manuscript: Baum's own words shown in green
This commit is contained in:
parent
aa8597bedd
commit
cb0f3a6b1f
1 changed files with 49 additions and 4 deletions
|
|
@ -24,6 +24,10 @@
|
||||||
.para.sel{border-color:var(--accent);background:#10141d}
|
.para.sel{border-color:var(--accent);background:#10141d}
|
||||||
.para.changed{border-left:3px solid #3fae74}
|
.para.changed{border-left:3px solid #3fae74}
|
||||||
.para .pn{position:absolute;left:-30px;top:14px;font:11px var(--mono,monospace);color:var(--muted)}
|
.para .pn{position:absolute;left:-30px;top:14px;font:11px var(--mono,monospace);color:var(--muted)}
|
||||||
|
.orig{color:#5fd38d}
|
||||||
|
.new{color:var(--ink)}
|
||||||
|
.legend{font-size:12px;color:var(--muted);margin:0 0 8px}
|
||||||
|
.legend .orig{font-weight:600}
|
||||||
mark{border-radius:4px;padding:0 2px;cursor:pointer;color:inherit}
|
mark{border-radius:4px;padding:0 2px;cursor:pointer;color:inherit}
|
||||||
mark.open{background:#5a4a12}
|
mark.open{background:#5a4a12}
|
||||||
mark.kept{background:#2a2f3a}
|
mark.kept{background:#2a2f3a}
|
||||||
|
|
@ -189,14 +193,55 @@
|
||||||
POLL = setTimeout(function () { openChapter(CH.n, PAGE); }, 4000);
|
POLL = setTimeout(function () { openChapter(CH.n, PAGE); }, 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Which words of the paragraph are Baum's. Longest common subsequence on
|
||||||
|
// words (punctuation ignored for the match, kept in the output).
|
||||||
|
function tok(t) { return String(t || "").split(/(\s+)/).filter(function (x) { return x.length; }); }
|
||||||
|
function key(w) { return w.toLowerCase().replace(/[^a-z0-9']/g, ""); }
|
||||||
|
function originalMask(p) {
|
||||||
|
if (p.text === p.original) return null;
|
||||||
|
var a = tok(p.original).filter(function (x) { return !/^\s+$/.test(x); }), b = tok(p.text);
|
||||||
|
var bw = b.map(function (x, i) { return /^\s+$/.test(x) ? null : i; }).filter(function (x) { return x !== null; });
|
||||||
|
var A = a.map(key), B = bw.map(function (i) { return key(b[i]); });
|
||||||
|
var n = A.length, m = B.length, L = [];
|
||||||
|
for (var i = 0; i <= n; i++) { L.push(new Uint16Array(m + 1)); }
|
||||||
|
for (i = n - 1; i >= 0; i--) for (var j = m - 1; j >= 0; j--) L[i][j] = A[i] === B[j] ? L[i + 1][j + 1] + 1 : Math.max(L[i + 1][j], L[i][j + 1]);
|
||||||
|
var mask = b.map(function () { return false; });
|
||||||
|
i = 0; j = 0;
|
||||||
|
while (i < n && j < m) {
|
||||||
|
if (A[i] === B[j]) { mask[bw[j]] = true; i++; j++; }
|
||||||
|
else if (L[i + 1][j] >= L[i][j + 1]) i++; else j++;
|
||||||
|
}
|
||||||
|
for (var k = 0; k < b.length; k++) if (/^\s+$/.test(b[k])) mask[k] = (k > 0 && mask[k - 1]) && (k + 1 < b.length && mask[k + 1]);
|
||||||
|
return { parts: b, mask: mask };
|
||||||
|
}
|
||||||
|
function greened(p) {
|
||||||
|
var om = originalMask(p);
|
||||||
|
if (!om) return '<span class="orig">' + esc(p.text) + '</span>';
|
||||||
|
var out = "", cur = null, buf = "";
|
||||||
|
om.parts.forEach(function (w, i) {
|
||||||
|
var cls = om.mask[i] ? "orig" : "new";
|
||||||
|
if (cls !== cur) { if (cur !== null) out += '<span class="' + cur + '">' + esc(buf) + '</span>'; cur = cls; buf = ""; }
|
||||||
|
buf += w;
|
||||||
|
});
|
||||||
|
if (cur !== null) out += '<span class="' + cur + '">' + esc(buf) + '</span>';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
function marked(p) {
|
function marked(p) {
|
||||||
var text = p.text, html = esc(text), refs = REFS.filter(function (r) { return r.para === p.i; });
|
var text = p.text, html = greened(p), refs = REFS.filter(function (r) { return r.para === p.i; });
|
||||||
refs.forEach(function (r) {
|
refs.forEach(function (r) {
|
||||||
var q = esc(r.quote), at = html.indexOf(q);
|
html = markIn(html, r.quote, esc(r.status), esc(r.id), esc(r.why || ""));
|
||||||
if (at >= 0) html = html.slice(0, at) + '<mark class="' + esc(r.status) + '" data-ref="' + esc(r.id) + '" title="' + esc(r.why || "") + '">' + q + '</mark>' + html.slice(at + q.length);
|
|
||||||
});
|
});
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
// Wrapping a quote in <mark> inside the green spans: the quote is found in
|
||||||
|
// the plain text; the coloured html is searched for the same run of words.
|
||||||
|
function markIn(html, q, cls, id, title) {
|
||||||
|
var plain = q.split(/\s+/).map(function (w) { return esc(w).replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }).join('(?:\\s|<\\/?span[^>]*>)+');
|
||||||
|
var rx = new RegExp(plain);
|
||||||
|
var m = rx.exec(html);
|
||||||
|
if (!m) return html;
|
||||||
|
return html.slice(0, m.index) + '<mark class="' + cls + '" data-ref="' + id + '" title="' + title + '">' + m[0] + '</mark>' + html.slice(m.index + m[0].length);
|
||||||
|
}
|
||||||
|
|
||||||
function paintChapter() {
|
function paintChapter() {
|
||||||
$("chtitle").textContent = (CH.n ? "Chapter " + CH.n + " — " : "") + CH.title;
|
$("chtitle").textContent = (CH.n ? "Chapter " + CH.n + " — " : "") + CH.title;
|
||||||
|
|
@ -218,7 +263,7 @@
|
||||||
$("pagebar").innerHTML = bar.replace('left in the chapter</span>', 'left in the chapter' + printSpan + '</span>');
|
$("pagebar").innerHTML = bar.replace('left in the chapter</span>', 'left in the chapter' + printSpan + '</span>');
|
||||||
var platesHere = PLATES.filter(function (x) { return pp.length && x.pg >= Math.min.apply(null, pp) && x.pg <= Math.max.apply(null, pp); });
|
var platesHere = PLATES.filter(function (x) { return pp.length && x.pg >= Math.min.apply(null, pp) && x.pg <= Math.max.apply(null, pp); });
|
||||||
var sceneOf = function (i) { var sc = SCENES.find(function (x) { return i >= x.from && i <= x.to; }); return sc ? '<span class="tiny" style="display:block;color:#f5c04b">Scene ' + sc.n + (sc.title ? ' · ' + esc(sc.title) : '') + '</span>' : ''; };
|
var sceneOf = function (i) { var sc = SCENES.find(function (x) { return i >= x.from && i <= x.to; }); return sc ? '<span class="tiny" style="display:block;color:#f5c04b">Scene ' + sc.n + (sc.title ? ' · ' + esc(sc.title) : '') + '</span>' : ''; };
|
||||||
$("paras").innerHTML = (platesHere.length ? '<div style="display:flex;gap:10px;flex-wrap:wrap;margin:0 0 12px">' + platesHere.map(function (x) { return '<a href="' + esc(x.url) + '" target="_blank" title="' + esc(x.alt) + ' (Denslow, 1900, p.' + x.pg + ')"><img src="' + esc(x.url) + '" style="height:150px;border-radius:6px;background:#fff" alt="' + esc(x.alt) + '"></a>'; }).join("") + '</div>' : '') + here.map(function (p) {
|
$("paras").innerHTML = '<p class="legend"><span class="orig">Green is Baum\'s own text, word for word.</span> White is what has been written for this adaptation.</p>' + (platesHere.length ? '<div style="display:flex;gap:10px;flex-wrap:wrap;margin:0 0 12px">' + platesHere.map(function (x) { return '<a href="' + esc(x.url) + '" target="_blank" title="' + esc(x.alt) + ' (Denslow, 1900, p.' + x.pg + ')"><img src="' + esc(x.url) + '" style="height:150px;border-radius:6px;background:#fff" alt="' + esc(x.alt) + '"></a>'; }).join("") + '</div>' : '') + here.map(function (p) {
|
||||||
var changed = p.text !== p.original;
|
var changed = p.text !== p.original;
|
||||||
return (SCENES.some(function (x) { return x.from === p.i; }) ? sceneOf(p.i) : '') + '<div class="para' + (changed ? ' changed' : '') + (SEL === p.i ? ' sel' : '') + '" data-para="' + p.i + '" title="' + (p.print_page ? 'first edition p. ' + p.print_page : '') + '"><span class="pn">' + (p.i + 1) + (p.print_page ? '<br>p' + p.print_page : '') + '</span>' + marked(p)
|
return (SCENES.some(function (x) { return x.from === p.i; }) ? sceneOf(p.i) : '') + '<div class="para' + (changed ? ' changed' : '') + (SEL === p.i ? ' sel' : '') + '" data-para="' + p.i + '" title="' + (p.print_page ? 'first edition p. ' + p.print_page : '') + '"><span class="pn">' + (p.i + 1) + (p.print_page ? '<br>p' + p.print_page : '') + '</span>' + marked(p)
|
||||||
+ (changed ? '<div class="was"><b>As Baum wrote it:</b> ' + esc(p.original) + '<br><span class="tiny">changed ' + esc(when(p.changed_at)) + ' by ' + esc(p.changed_by || "") + ' · ' + esc(p.how || "") + ' · revision ' + p.rev + '</span></div>' : '')
|
+ (changed ? '<div class="was"><b>As Baum wrote it:</b> ' + esc(p.original) + '<br><span class="tiny">changed ' + esc(when(p.changed_at)) + ' by ' + esc(p.changed_by || "") + ' · ' + esc(p.how || "") + ' · revision ' + p.rev + '</span></div>' : '')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue