// resources/js/modules/_reader.js
export function initReader() {
injectCommentaryMarkers();
}
function injectCommentaryMarkers() {
let counter = 0;
document
.querySelectorAll('div.sentence[data-note-id]')
.forEach((sentenceEl) => {
const uid = sentenceEl.dataset.noteId;
counter++;
const id = `commentary-${counter}`;
// checkbox:控制展开,紧跟在 sentence 后
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'commentary-toggle';
checkbox.id = id;
// label(icon):行内,插在句子文字末尾
const label = document.createElement('label');
label.htmlFor = id;
label.className = 'commentary-icon';
label.innerHTML = '';
// 注释块:紧跟在 checkbox 后(CSS 相邻选择器依赖此顺序)
const note = document.createElement('div');
note.className = 'commentary-note';
note.dataset.uuid = uid;
note.dataset.loaded = 'false';
// label 插入句子内文字末尾(行内不打断文字流)
const innerSpan = sentenceEl.querySelector(':scope > span');
(innerSpan ?? sentenceEl).appendChild(label);
// sentence 后:先插 note,再插 checkbox(after 逆序)
// 最终顺序:div.sentence → input.commentary-toggle → div.commentary-note
sentenceEl.after(note);
sentenceEl.after(checkbox);
// 点击时懒加载
checkbox.addEventListener('change', async () => {
if (!checkbox.checked) {
return;
}
if (note.dataset.loaded === 'true') {
return;
}
note.innerHTML =
'加载中…';
await fetchCommentary(note);
});
});
}
async function fetchCommentary(noteEl) {
const uuid = noteEl.dataset.uuid;
try {
const res = await fetch(`/api/v2/sentence/${uuid}?format=html`);
if (!res.ok) {
throw new Error(res.status);
}
const json = await res.json();
if (!json.ok) {
throw new Error('api error');
}
noteEl.innerHTML = json.data.html;
noteEl.dataset.loaded = 'true';
} catch {
noteEl.innerHTML = '加载失败';
}
}