Outline: share as a read-only link
- Share on the Outline page opens a sheet: create / copy / turn off a read-only link, share the link with the system share sheet, or send the outline as text - The link has its own token (separate from the whole-study share link) and the public endpoint returns only the outlines, rebuilt field by field: no observations, interpretations, applications, scripts or word notes - Opening the link shows the outline(s) with no sign-in, a switcher between the whole-study and per-chunk outlines, and Print / PDF - New outline_share_token column (added automatically on start) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2ca79730f1
commit
d7a1601f80
11 files changed
+444
-10
No files matched your search
@@ -0,0 +1,59 @@
|
||||
// What a read-only outline link shows: the outlines of a study (the whole-study one and each chunk's)
|
||||
// and nothing else — no observations, interpretations, applications, scripts or word notes. The
|
||||
// outline data comes from the browser, so it is rebuilt field by field instead of passed through.
|
||||
const MAX_NODES = 2000;
|
||||
const MAX_DEPTH = 8;
|
||||
const KINDS = new Set(['', 'illustration', 'application', 'quote', 'question', 'transition']);
|
||||
|
||||
const str = (v, max) => (typeof v === 'string' ? v.slice(0, max) : '');
|
||||
|
||||
function cleanTree(nodes, depth, counter) {
|
||||
if (!Array.isArray(nodes) || depth > MAX_DEPTH) return [];
|
||||
const out = [];
|
||||
for (const n of nodes) {
|
||||
if (!n || typeof n !== 'object' || counter.n >= MAX_NODES) continue;
|
||||
counter.n += 1;
|
||||
const minutes = Number.isFinite(n.minutes) && n.minutes >= 0 && n.minutes <= 600 ? n.minutes : null;
|
||||
out.push({
|
||||
id: str(n.id, 64) || `n${counter.n}`,
|
||||
text: str(n.text, 2000),
|
||||
ref: str(n.ref, 200),
|
||||
kind: KINDS.has(n.kind) ? n.kind : '',
|
||||
minutes,
|
||||
note: str(n.note, 8000),
|
||||
scripture: n.scripture && typeof n.scripture.text === 'string'
|
||||
? { ref: str(n.scripture.ref, 200), text: str(n.scripture.text, 6000), translation: str(n.scripture.translation, 12) }
|
||||
: null,
|
||||
attachments: (Array.isArray(n.attachments) ? n.attachments : []).slice(0, 50)
|
||||
.filter((a) => a && typeof a === 'object')
|
||||
.map((a) => ({ id: str(a.id, 100), type: a.type === 'word' ? 'word' : 'xref', label: str(a.label, 200), ...(a.detail ? { detail: str(a.detail, 500) } : {}) })),
|
||||
children: cleanTree(n.children, depth + 1, counter),
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const chunkLabel = (chapters, chapterIndex, chunk) => {
|
||||
const ch = chapters[chapterIndex];
|
||||
const next = chapters[chapterIndex + 1];
|
||||
if (Number.isInteger(chunk.spilloverEndVerse) && next && next.bookAbbrev === ch.bookAbbrev) {
|
||||
return `${ch.book} ${ch.chapter}:${chunk.startVerse}–${next.chapter}:${chunk.spilloverEndVerse}`;
|
||||
}
|
||||
return chunk.startVerse === chunk.endVerse ? `${ch.book} ${ch.chapter}:${chunk.startVerse}` : `${ch.book} ${ch.chapter}:${chunk.startVerse}–${chunk.endVerse}`;
|
||||
};
|
||||
|
||||
// -> { title, translation, outlines: [{ scope, label, tree }] } with only the outlines that have points
|
||||
export function buildOutlinePayload(project) {
|
||||
const counter = { n: 0 };
|
||||
const outlines = [];
|
||||
const whole = cleanTree(project?.outline, 0, counter);
|
||||
if (whole.length > 0) outlines.push({ scope: 'study', label: 'Whole study', tree: whole });
|
||||
const chapters = Array.isArray(project?.chapters) ? project.chapters : [];
|
||||
chapters.forEach((ch, chapterIndex) => {
|
||||
for (const chunk of Array.isArray(ch?.chunks) ? ch.chunks : []) {
|
||||
const tree = cleanTree(chunk?.outline, 0, counter);
|
||||
if (tree.length > 0) outlines.push({ scope: str(chunk.id, 64), label: str(chunkLabel(chapters, chapterIndex, chunk), 200), tree });
|
||||
}
|
||||
});
|
||||
return { title: str(project?.title, 500), translation: str(project?.translation, 12) || 'BSB', outlines };
|
||||
}
|
||||
Reference in new issue
Block a user