@richscripts/richtexteditor 2.4.0 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/migration/README.md +100 -0
- package/migration/cli.js +294 -0
- package/migration/index.d.ts +18 -0
- package/migration/index.js +242 -0
- package/migration/report-schema-v2.json +127 -0
- package/package.json +14 -2
- package/richtexteditor/CHANGELOG.md +326 -1
- package/richtexteditor/all_plugins.js +14982 -4831
- package/richtexteditor/all_plugins.min.js +62 -42
- package/richtexteditor/plugins/accessibilitychecker.js +8 -7
- package/richtexteditor/plugins/aitoolkit.css +17 -8
- package/richtexteditor/plugins/aitoolkit.js +8 -8
- package/richtexteditor/plugins/all_plugins.js +14982 -4831
- package/richtexteditor/plugins/all_plugins.min.js +62 -42
- package/richtexteditor/plugins/autocorrect.js +353 -0
- package/richtexteditor/plugins/bookmarkcard.js +12 -1
- package/richtexteditor/plugins/changecase.js +238 -0
- package/richtexteditor/plugins/comments.js +15 -28
- package/richtexteditor/plugins/contentminimap.js +6 -5
- package/richtexteditor/plugins/crdt-engine.js +2201 -198
- package/richtexteditor/plugins/crdt-engine.min.js +5 -5
- package/richtexteditor/plugins/crossreference.js +408 -0
- package/richtexteditor/plugins/documentimport.js +915 -21
- package/richtexteditor/plugins/documentoutline.js +5 -4
- package/richtexteditor/plugins/docxexport.js +960 -0
- package/richtexteditor/plugins/draghandle.js +309 -0
- package/richtexteditor/plugins/footnotes.js +398 -0
- package/richtexteditor/plugins/formatpainter.js +298 -0
- package/richtexteditor/plugins/formattingmarks.js +246 -0
- package/richtexteditor/plugins/html2pdf.js +108 -4
- package/richtexteditor/plugins/imageeditor.js +37 -7
- package/richtexteditor/plugins/insertgallery.js +553 -170
- package/richtexteditor/plugins/keyboarda11y.js +316 -0
- package/richtexteditor/plugins/linenumbers.js +352 -0
- package/richtexteditor/plugins/linkchecker.js +396 -0
- package/richtexteditor/plugins/mentionplugin.js +4 -3
- package/richtexteditor/plugins/mergefields.js +328 -0
- package/richtexteditor/plugins/multilevellist.js +137 -0
- package/richtexteditor/plugins/pagination.js +505 -0
- package/richtexteditor/plugins/pdfexport.js +1137 -0
- package/richtexteditor/plugins/permanentpen.js +211 -0
- package/richtexteditor/plugins/revisionhistory.js +47 -34
- package/richtexteditor/plugins/rtlui.js +150 -0
- package/richtexteditor/plugins/sanitizer.js +510 -0
- package/richtexteditor/plugins/slashcommand.js +142 -17
- package/richtexteditor/plugins/spellcheck.js +6 -3
- package/richtexteditor/plugins/tableofcontents.js +353 -0
- package/richtexteditor/plugins/tabletools.js +342 -0
- package/richtexteditor/plugins/textdirection.js +313 -0
- package/richtexteditor/plugins/trackedchanges.js +37 -6
- package/richtexteditor/plugins/tui.image-editor/tui-code-snippet.min.js +1 -1
- package/richtexteditor/plugins/tui.image-editor/tui-color-picker.min.js +1 -1
- package/richtexteditor/plugins/tui.image-editor/tui-image-editor.min.js +1 -1
- package/richtexteditor/plugins/vendor/html2pdf.bundle.min.js +3 -0
- package/richtexteditor/plugins/watermark.js +214 -0
- package/richtexteditor/plugins/wordexport.js +0 -0
- package/richtexteditor/plugins/yjscollab.js +49 -11
- package/richtexteditor/rte-config.js +44 -44
- package/richtexteditor/rte.js +91 -63
- package/richtexteditor/rte_theme_default.css +483 -384
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
|
|
2
|
+
|
|
3
|
+
// 2026-07-27 Cross-references. "See clause 3.2", "Figure 4", "as described in
|
|
4
|
+
// Scope of Work (page 7)" — references that keep pointing at the right thing
|
|
5
|
+
// after the document is edited around them.
|
|
6
|
+
//
|
|
7
|
+
// This is the piece that makes the rest of the document suite hold together.
|
|
8
|
+
// Legal numbering renumbers clauses, the table of contents re-derives itself,
|
|
9
|
+
// footnotes renumber — and until now a sentence saying "see clause 3.2" stayed
|
|
10
|
+
// frozen at 3.2 while the clause it meant became 4.1. A stale cross-reference in
|
|
11
|
+
// a contract is not cosmetic; it changes what the contract says.
|
|
12
|
+
//
|
|
13
|
+
// Competitive position (checked 2026-07-27): CKEditor 5 ships Bookmarks
|
|
14
|
+
// (in-text anchors) and its own auto-updating table of contents, but describes
|
|
15
|
+
// auto-updating cross-references as a PLANNED enhancement rather than a current
|
|
16
|
+
// feature. TinyMCE documents no cross-reference plugin. Word has had this for
|
|
17
|
+
// decades and it is table stakes for contract and specification work.
|
|
18
|
+
//
|
|
19
|
+
// Design notes:
|
|
20
|
+
// - A reference is an atomic contenteditable=false chip carrying the target id
|
|
21
|
+
// and the display format. The visible text is REAL TEXT, recomputed on every
|
|
22
|
+
// mutation, so the saved HTML stands alone outside the editor (same reasoning
|
|
23
|
+
// as footnotes.js).
|
|
24
|
+
// - A reference whose target has been deleted renders a visible error rather
|
|
25
|
+
// than silently keeping its last value. Word does this too, and it is the
|
|
26
|
+
// right call: a wrong-but-plausible clause number is far more dangerous than
|
|
27
|
+
// an obviously broken one.
|
|
28
|
+
RTE_DefaultConfig.plugin_crossreference = RTE_Plugin_CrossReference;
|
|
29
|
+
|
|
30
|
+
// Shown when the target no longer exists.
|
|
31
|
+
if (typeof RTE_DefaultConfig.crossRefMissingText === "undefined") RTE_DefaultConfig.crossRefMissingText = "[reference not found]";
|
|
32
|
+
// Prefixes used when auto-numbering tables and figures.
|
|
33
|
+
if (typeof RTE_DefaultConfig.crossRefTableLabel === "undefined") RTE_DefaultConfig.crossRefTableLabel = "Table";
|
|
34
|
+
if (typeof RTE_DefaultConfig.crossRefFigureLabel === "undefined") RTE_DefaultConfig.crossRefFigureLabel = "Figure";
|
|
35
|
+
|
|
36
|
+
function RTE_Plugin_CrossReference() {
|
|
37
|
+
var obj = this;
|
|
38
|
+
var config, editor;
|
|
39
|
+
var boundDoc = null;
|
|
40
|
+
var queued = false;
|
|
41
|
+
var idSeq = 0;
|
|
42
|
+
|
|
43
|
+
obj.PluginName = "CrossReference";
|
|
44
|
+
|
|
45
|
+
obj.InitConfig = function (argconfig) { config = argconfig; };
|
|
46
|
+
|
|
47
|
+
obj.InitEditor = function (argeditor) {
|
|
48
|
+
editor = argeditor;
|
|
49
|
+
|
|
50
|
+
editor.attachEvent("exec_command_insertcrossreference", function (state) {
|
|
51
|
+
state.returnValue = true;
|
|
52
|
+
var v = state && state.value;
|
|
53
|
+
if (v && typeof v === "object") obj.Insert(v.target, v.format);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
setup();
|
|
57
|
+
try { editor.attachEvent("ready", setup); } catch (e) {}
|
|
58
|
+
try { editor.attachEvent("aftersethtml", function () { setup(); queue(); }); } catch (e) {}
|
|
59
|
+
setTimeout(function () { setup(); queue(); }, 0);
|
|
60
|
+
|
|
61
|
+
// Public API.
|
|
62
|
+
editor.listCrossReferenceTargets = function () { return obj.Targets(); };
|
|
63
|
+
editor.insertCrossReference = function (targetId, format) { return obj.Insert(targetId, format); };
|
|
64
|
+
editor.updateCrossReferences = function () { return refresh(); };
|
|
65
|
+
editor.getCrossReferences = function () { return obj.List(); };
|
|
66
|
+
editor.getCrossReferenceCss = function () { return css(); };
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
function setup() {
|
|
70
|
+
var doc = getDoc();
|
|
71
|
+
if (!doc) return;
|
|
72
|
+
injectStyles(doc);
|
|
73
|
+
if (doc === boundDoc) return;
|
|
74
|
+
boundDoc = doc;
|
|
75
|
+
var editable = getEditable();
|
|
76
|
+
if (!editable) return;
|
|
77
|
+
editable.addEventListener("keyup", queue);
|
|
78
|
+
editable.addEventListener("cut", queue);
|
|
79
|
+
editable.addEventListener("paste", queue);
|
|
80
|
+
editable.addEventListener("drop", queue);
|
|
81
|
+
editable.addEventListener("click", function (e) {
|
|
82
|
+
var chip = closestClass(e.target, "rte-xref", editable);
|
|
83
|
+
if (!chip) return;
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
var t = resolveTarget(chip.getAttribute("data-xref-target"));
|
|
86
|
+
if (!t) return;
|
|
87
|
+
try { t.el.scrollIntoView({ block: "center" }); } catch (e2) { t.el.scrollIntoView(); }
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getDoc() { try { return editor.getDocument(); } catch (e) { return null; } }
|
|
92
|
+
function getEditable() { try { return editor.getEditable(); } catch (e) { return null; } }
|
|
93
|
+
|
|
94
|
+
function queue() {
|
|
95
|
+
if (queued) return;
|
|
96
|
+
queued = true;
|
|
97
|
+
setTimeout(function () { queued = false; refresh(); }, 0);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function closestClass(node, cls, root) {
|
|
101
|
+
while (node && node !== root) {
|
|
102
|
+
if (node.nodeType === 1 && node.classList && node.classList.contains(cls)) return node;
|
|
103
|
+
node = node.parentNode;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function newId(prefix) {
|
|
109
|
+
return prefix + Math.floor(Math.random() * 1e9).toString(36) + (idSeq++).toString(36);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function ensureId(el, prefix) {
|
|
113
|
+
var id = el.getAttribute("id");
|
|
114
|
+
if (id) return id;
|
|
115
|
+
id = newId(prefix);
|
|
116
|
+
el.setAttribute("id", id);
|
|
117
|
+
return id;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ---- targets ---------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
// Everything in the document that can be referred to, in document order.
|
|
123
|
+
obj.Targets = function () {
|
|
124
|
+
var editable = getEditable();
|
|
125
|
+
if (!editable) return [];
|
|
126
|
+
var out = [];
|
|
127
|
+
|
|
128
|
+
var headings = editable.querySelectorAll("h1,h2,h3,h4,h5,h6");
|
|
129
|
+
for (var i = 0; i < headings.length; i++) {
|
|
130
|
+
var h = headings[i];
|
|
131
|
+
// Generated regions are not referable content.
|
|
132
|
+
if (h.closest && (h.closest("nav.rte-toc") || h.closest("section.rte-footnotes"))) continue;
|
|
133
|
+
var text = (h.textContent || "").trim();
|
|
134
|
+
if (!text) continue;
|
|
135
|
+
out.push({ id: ensureId(h, "rte-h-"), type: "heading", label: text, number: null });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Legal-numbered clauses: the number is derived from position, exactly
|
|
139
|
+
// like the CSS counters that render it.
|
|
140
|
+
var roots = editable.querySelectorAll("ol.rte-legal-list");
|
|
141
|
+
for (var r = 0; r < roots.length; r++) collectClauses(roots[r], [], out);
|
|
142
|
+
|
|
143
|
+
var notes = editable.querySelectorAll("li.rte-fn-note[data-fn-id]");
|
|
144
|
+
for (var n = 0; n < notes.length; n++) {
|
|
145
|
+
out.push({
|
|
146
|
+
id: ensureId(notes[n], "rte-fn-"),
|
|
147
|
+
type: "footnote",
|
|
148
|
+
label: (noteText(notes[n]) || "footnote"),
|
|
149
|
+
number: notes[n].getAttribute("data-fn-number")
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
var tables = editable.querySelectorAll("table");
|
|
154
|
+
var tnum = 0;
|
|
155
|
+
for (var t = 0; t < tables.length; t++) {
|
|
156
|
+
tnum++;
|
|
157
|
+
var cap = tables[t].querySelector("caption");
|
|
158
|
+
out.push({
|
|
159
|
+
id: ensureId(tables[t], "rte-tbl-"),
|
|
160
|
+
type: "table",
|
|
161
|
+
label: (cap && cap.textContent.trim()) || (String(config.crossRefTableLabel) + " " + tnum),
|
|
162
|
+
number: String(tnum)
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var figs = editable.querySelectorAll("figure, img");
|
|
167
|
+
var fnum = 0;
|
|
168
|
+
for (var f = 0; f < figs.length; f++) {
|
|
169
|
+
// An <img> inside a <figure> is the same figure, counted once.
|
|
170
|
+
if (figs[f].nodeName === "IMG" && figs[f].closest && figs[f].closest("figure")) continue;
|
|
171
|
+
fnum++;
|
|
172
|
+
var fc = figs[f].querySelector ? figs[f].querySelector("figcaption") : null;
|
|
173
|
+
out.push({
|
|
174
|
+
id: ensureId(figs[f], "rte-fig-"),
|
|
175
|
+
type: "figure",
|
|
176
|
+
label: (fc && fc.textContent.trim()) || (String(config.crossRefFigureLabel) + " " + fnum),
|
|
177
|
+
number: String(fnum)
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return out;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
function collectClauses(ol, path, out) {
|
|
184
|
+
var idx = 0;
|
|
185
|
+
for (var i = 0; i < ol.children.length; i++) {
|
|
186
|
+
var li = ol.children[i];
|
|
187
|
+
if (li.nodeName !== "LI") continue;
|
|
188
|
+
idx++;
|
|
189
|
+
var here = path.concat([idx]);
|
|
190
|
+
var first = firstLineText(li);
|
|
191
|
+
out.push({
|
|
192
|
+
id: ensureId(li, "rte-cl-"),
|
|
193
|
+
type: "clause",
|
|
194
|
+
label: first || ("clause " + here.join(".")),
|
|
195
|
+
number: here.join(".")
|
|
196
|
+
});
|
|
197
|
+
for (var c = 0; c < li.children.length; c++) {
|
|
198
|
+
if (li.children[c].nodeName === "OL") collectClauses(li.children[c], here, out);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// The clause's own text, excluding any nested sub-list.
|
|
204
|
+
function firstLineText(li) {
|
|
205
|
+
var s = "";
|
|
206
|
+
for (var i = 0; i < li.childNodes.length; i++) {
|
|
207
|
+
var n = li.childNodes[i];
|
|
208
|
+
if (n.nodeType === 1 && (n.nodeName === "OL" || n.nodeName === "UL")) break;
|
|
209
|
+
s += n.textContent || "";
|
|
210
|
+
}
|
|
211
|
+
return s.trim().replace(/\s+/g, " ").slice(0, 80);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function noteText(note) {
|
|
215
|
+
var clone = note.cloneNode(true);
|
|
216
|
+
var backs = clone.querySelectorAll ? clone.querySelectorAll("a.rte-fn-back") : [];
|
|
217
|
+
for (var i = 0; i < backs.length; i++) if (backs[i].parentNode) backs[i].parentNode.removeChild(backs[i]);
|
|
218
|
+
return (clone.textContent || "").replace(/↩/g, "").trim().slice(0, 80);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function resolveTarget(id) {
|
|
222
|
+
if (!id) return null;
|
|
223
|
+
var list = obj.Targets();
|
|
224
|
+
for (var i = 0; i < list.length; i++) {
|
|
225
|
+
if (list[i].id !== id) continue;
|
|
226
|
+
var editable = getEditable();
|
|
227
|
+
var el = editable ? editable.querySelector("#" + id.replace(/["\\\]\[]/g, "\\$&")) : null;
|
|
228
|
+
if (!el) return null;
|
|
229
|
+
var t = list[i];
|
|
230
|
+
t.el = el;
|
|
231
|
+
return t;
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ---- insert ----------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
// format: "text" | "number" | "page" | "position" | "label"
|
|
239
|
+
obj.Insert = function (targetId, format) {
|
|
240
|
+
var doc = getDoc();
|
|
241
|
+
var editable = getEditable();
|
|
242
|
+
if (!doc || !editable) return false;
|
|
243
|
+
var target = resolveTarget(targetId);
|
|
244
|
+
if (!target) return false;
|
|
245
|
+
format = String(format || "text");
|
|
246
|
+
|
|
247
|
+
var chip = doc.createElement("span");
|
|
248
|
+
chip.className = "rte-xref";
|
|
249
|
+
chip.setAttribute("data-xref-target", targetId);
|
|
250
|
+
chip.setAttribute("data-xref-format", format);
|
|
251
|
+
chip.setAttribute("contenteditable", "false");
|
|
252
|
+
chip.textContent = displayFor(target, format, chip);
|
|
253
|
+
|
|
254
|
+
var placed = false;
|
|
255
|
+
try {
|
|
256
|
+
if (typeof editor.insertElement === "function") { editor.insertElement(chip); placed = true; }
|
|
257
|
+
} catch (e) {}
|
|
258
|
+
if (!placed) {
|
|
259
|
+
try {
|
|
260
|
+
var sel = editor.getSelection();
|
|
261
|
+
if (sel && sel.rangeCount) {
|
|
262
|
+
var r = sel.getRangeAt(0);
|
|
263
|
+
r.collapse(false);
|
|
264
|
+
r.insertNode(chip);
|
|
265
|
+
r.setStartAfter(chip); r.collapse(true);
|
|
266
|
+
sel.removeAllRanges(); sel.addRange(r);
|
|
267
|
+
placed = true;
|
|
268
|
+
}
|
|
269
|
+
} catch (e) {}
|
|
270
|
+
}
|
|
271
|
+
if (!placed) editable.appendChild(chip);
|
|
272
|
+
// Recompute now that the chip is actually IN the document. The text set
|
|
273
|
+
// above was computed while it was still detached, and the "position"
|
|
274
|
+
// format compares the chip against its target — on a detached node that
|
|
275
|
+
// comparison is meaningless, so a reference to something earlier in the
|
|
276
|
+
// document displayed "below" until the next refresh happened to fix it.
|
|
277
|
+
refresh();
|
|
278
|
+
fireChange();
|
|
279
|
+
return targetId;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
function displayFor(target, format, chip) {
|
|
283
|
+
if (!target) return String(config.crossRefMissingText);
|
|
284
|
+
switch (format) {
|
|
285
|
+
case "number":
|
|
286
|
+
if (target.number) return target.number;
|
|
287
|
+
return target.label; // headings have no number
|
|
288
|
+
case "label":
|
|
289
|
+
// "Table 2" / "Figure 3" / "clause 3.2" style
|
|
290
|
+
if (target.type === "table") return String(config.crossRefTableLabel) + " " + target.number;
|
|
291
|
+
if (target.type === "figure") return String(config.crossRefFigureLabel) + " " + target.number;
|
|
292
|
+
if (target.type === "clause") return "clause " + target.number;
|
|
293
|
+
if (target.type === "footnote") return "footnote " + target.number;
|
|
294
|
+
return target.label;
|
|
295
|
+
case "page":
|
|
296
|
+
var p = null;
|
|
297
|
+
try {
|
|
298
|
+
if (typeof editor.getPageOfElement === "function") p = editor.getPageOfElement(target.el);
|
|
299
|
+
} catch (e) { p = null; }
|
|
300
|
+
// No page view means no honest page number; keep whatever was
|
|
301
|
+
// last computed rather than inventing or blanking one.
|
|
302
|
+
if (p) return String(p);
|
|
303
|
+
var prev = chip ? chip.getAttribute("data-xref-last-page") : null;
|
|
304
|
+
return prev || "?";
|
|
305
|
+
case "position":
|
|
306
|
+
return positionOf(target.el, chip);
|
|
307
|
+
default:
|
|
308
|
+
return target.label;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// "above" / "below" relative to the reference itself.
|
|
313
|
+
function positionOf(targetEl, chip) {
|
|
314
|
+
if (!targetEl || !chip) return "above";
|
|
315
|
+
try {
|
|
316
|
+
var pos = chip.compareDocumentPosition(targetEl);
|
|
317
|
+
if (pos & Node.DOCUMENT_POSITION_PRECEDING) return "above";
|
|
318
|
+
if (pos & Node.DOCUMENT_POSITION_FOLLOWING) return "below";
|
|
319
|
+
} catch (e) {}
|
|
320
|
+
return "above";
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ---- refresh ---------------------------------------------------------
|
|
324
|
+
|
|
325
|
+
function chips() {
|
|
326
|
+
var editable = getEditable();
|
|
327
|
+
if (!editable) return [];
|
|
328
|
+
return Array.prototype.slice.call(editable.querySelectorAll("span.rte-xref[data-xref-target]"));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function refresh() {
|
|
332
|
+
var list = chips();
|
|
333
|
+
if (!list.length) return [];
|
|
334
|
+
// Build the target index once rather than per chip.
|
|
335
|
+
var targets = obj.Targets();
|
|
336
|
+
var byId = {};
|
|
337
|
+
for (var t = 0; t < targets.length; t++) byId[targets[t].id] = targets[t];
|
|
338
|
+
var editable = getEditable();
|
|
339
|
+
|
|
340
|
+
var out = [];
|
|
341
|
+
for (var i = 0; i < list.length; i++) {
|
|
342
|
+
var chip = list[i];
|
|
343
|
+
var id = chip.getAttribute("data-xref-target");
|
|
344
|
+
var fmt = chip.getAttribute("data-xref-format") || "text";
|
|
345
|
+
var target = byId[id] || null;
|
|
346
|
+
if (target) {
|
|
347
|
+
target.el = editable.querySelector("#" + id.replace(/["\\\]\[]/g, "\\$&"));
|
|
348
|
+
}
|
|
349
|
+
var text = displayFor(target, fmt, chip);
|
|
350
|
+
if (chip.textContent !== text) chip.textContent = text;
|
|
351
|
+
if (target) {
|
|
352
|
+
chip.classList.remove("rte-xref-broken");
|
|
353
|
+
if (fmt === "page" && /^\d+$/.test(text)) chip.setAttribute("data-xref-last-page", text);
|
|
354
|
+
} else {
|
|
355
|
+
// Visible failure beats a plausible wrong number.
|
|
356
|
+
chip.classList.add("rte-xref-broken");
|
|
357
|
+
}
|
|
358
|
+
out.push({ target: id, format: fmt, text: text, resolved: !!target });
|
|
359
|
+
}
|
|
360
|
+
return out;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
obj.List = function () {
|
|
364
|
+
var list = chips();
|
|
365
|
+
var out = [];
|
|
366
|
+
for (var i = 0; i < list.length; i++) {
|
|
367
|
+
out.push({
|
|
368
|
+
target: list[i].getAttribute("data-xref-target"),
|
|
369
|
+
format: list[i].getAttribute("data-xref-format") || "text",
|
|
370
|
+
text: list[i].textContent,
|
|
371
|
+
resolved: !list[i].classList.contains("rte-xref-broken")
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
return out;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
function fireChange() {
|
|
378
|
+
try { if (typeof editor.updateDesign === "function") editor.updateDesign(); } catch (e) {}
|
|
379
|
+
try { if (typeof editor.fireChange === "function") editor.fireChange(); } catch (e) {}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// ---- styles ----------------------------------------------------------
|
|
383
|
+
|
|
384
|
+
function css() {
|
|
385
|
+
return (
|
|
386
|
+
"span.rte-xref{color:#1474ea;cursor:pointer;border-bottom:1px dotted #9dc2f5;" +
|
|
387
|
+
"user-select:none;}" +
|
|
388
|
+
"span.rte-xref:hover{border-bottom-style:solid;}" +
|
|
389
|
+
"span.rte-xref.rte-xref-broken{color:#c81e1e;background:rgba(200,30,30,.09);" +
|
|
390
|
+
"border-bottom:1px solid #e59b9b;border-radius:2px;padding:0 .15em;}"
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function injectStyles(doc) {
|
|
395
|
+
if (!doc) return;
|
|
396
|
+
var existing = doc.getElementById("rte-xref-styles");
|
|
397
|
+
var text = css();
|
|
398
|
+
if (existing) {
|
|
399
|
+
if (existing.getAttribute("data-css") === text) return;
|
|
400
|
+
existing.parentNode && existing.parentNode.removeChild(existing);
|
|
401
|
+
}
|
|
402
|
+
var st = doc.createElement("style");
|
|
403
|
+
st.id = "rte-xref-styles";
|
|
404
|
+
st.setAttribute("data-css", text);
|
|
405
|
+
st.appendChild(doc.createTextNode(text));
|
|
406
|
+
(doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement).appendChild(st);
|
|
407
|
+
}
|
|
408
|
+
}
|