@richscripts/richtexteditor 2.14.0 → 2.15.0
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/README.md +173 -10
- package/angular/build-manifest.json +23 -0
- package/angular/index.d.ts +71 -76
- package/angular/index.mjs +2 -0
- package/angular/package.json +4 -0
- package/headless/index.d.ts +3 -1
- package/headless/index.js +72 -16
- package/index.d.ts +33 -54
- package/integrations/initialization-scope.js +27 -0
- package/integrations/native-mount.js +30 -0
- package/integrations/shared.d.ts +23 -1
- package/integrations/shared.js +58 -22
- package/package.json +25 -3
- package/react/index.js +118 -37
- package/react/index.mjs +29 -0
- package/richtexteditor/all_plugins.js +7113 -1111
- package/richtexteditor/all_plugins.min.js +62 -59
- package/richtexteditor/lang/emoji/LICENSE-CLDR.txt +41 -0
- package/richtexteditor/lang/emoji/rte-emoji-de.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-es.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-fr.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-it.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ja.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ko.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-nl.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-pt-pt.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-pt.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ru.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-zh-Hans.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-zh-Hant.js +3 -0
- package/richtexteditor/lang/rte-lang-af.js +1 -0
- package/richtexteditor/lang/rte-lang-ar.js +1 -0
- package/richtexteditor/lang/rte-lang-bg.js +1 -0
- package/richtexteditor/lang/rte-lang-bn.js +1 -0
- package/richtexteditor/lang/rte-lang-bs.js +1 -0
- package/richtexteditor/lang/rte-lang-ca.js +1 -0
- package/richtexteditor/lang/rte-lang-cs.js +1 -0
- package/richtexteditor/lang/rte-lang-cy.js +1 -0
- package/richtexteditor/lang/rte-lang-da.js +1 -0
- package/richtexteditor/lang/rte-lang-de.js +1017 -2
- package/richtexteditor/lang/rte-lang-el.js +1 -0
- package/richtexteditor/lang/rte-lang-en.js +1 -0
- package/richtexteditor/lang/rte-lang-es.js +1023 -2
- package/richtexteditor/lang/rte-lang-et.js +1 -0
- package/richtexteditor/lang/rte-lang-fa.js +1 -0
- package/richtexteditor/lang/rte-lang-fi.js +1 -0
- package/richtexteditor/lang/rte-lang-fil.js +1 -0
- package/richtexteditor/lang/rte-lang-fj.js +1 -0
- package/richtexteditor/lang/rte-lang-fr.js +1023 -2
- package/richtexteditor/lang/rte-lang-ga.js +1 -0
- package/richtexteditor/lang/rte-lang-gu.js +1 -0
- package/richtexteditor/lang/rte-lang-he.js +1 -0
- package/richtexteditor/lang/rte-lang-hi.js +1 -0
- package/richtexteditor/lang/rte-lang-hr.js +1 -0
- package/richtexteditor/lang/rte-lang-ht.js +1 -0
- package/richtexteditor/lang/rte-lang-hu.js +1 -0
- package/richtexteditor/lang/rte-lang-id.js +1 -0
- package/richtexteditor/lang/rte-lang-is.js +1 -0
- package/richtexteditor/lang/rte-lang-it.js +1023 -2
- package/richtexteditor/lang/rte-lang-ja.js +1023 -2
- package/richtexteditor/lang/rte-lang-kn.js +1 -0
- package/richtexteditor/lang/rte-lang-ko.js +1023 -2
- package/richtexteditor/lang/rte-lang-lt.js +1 -0
- package/richtexteditor/lang/rte-lang-lv.js +1 -0
- package/richtexteditor/lang/rte-lang-mg.js +1 -0
- package/richtexteditor/lang/rte-lang-mi.js +1 -0
- package/richtexteditor/lang/rte-lang-ml.js +1 -0
- package/richtexteditor/lang/rte-lang-mr.js +1 -0
- package/richtexteditor/lang/rte-lang-ms.js +1 -0
- package/richtexteditor/lang/rte-lang-mt.js +1 -0
- package/richtexteditor/lang/rte-lang-mww.js +1 -0
- package/richtexteditor/lang/rte-lang-nb.js +1 -0
- package/richtexteditor/lang/rte-lang-nl.js +1023 -2
- package/richtexteditor/lang/rte-lang-otq.js +1 -0
- package/richtexteditor/lang/rte-lang-pa.js +1 -0
- package/richtexteditor/lang/rte-lang-pl.js +1 -0
- package/richtexteditor/lang/rte-lang-pt-pt.js +1023 -2
- package/richtexteditor/lang/rte-lang-pt.js +1023 -2
- package/richtexteditor/lang/rte-lang-ro.js +1 -0
- package/richtexteditor/lang/rte-lang-ru.js +1023 -2
- package/richtexteditor/lang/rte-lang-sk.js +1 -0
- package/richtexteditor/lang/rte-lang-sl.js +1 -0
- package/richtexteditor/lang/rte-lang-sm.js +1 -0
- package/richtexteditor/lang/rte-lang-sr-Cyrl.js +1 -0
- package/richtexteditor/lang/rte-lang-sr-Latn.js +1 -0
- package/richtexteditor/lang/rte-lang-sv.js +1 -0
- package/richtexteditor/lang/rte-lang-sw.js +1 -0
- package/richtexteditor/lang/rte-lang-ta.js +1 -0
- package/richtexteditor/lang/rte-lang-te.js +1 -0
- package/richtexteditor/lang/rte-lang-th.js +1 -0
- package/richtexteditor/lang/rte-lang-tlh-Latn.js +1 -0
- package/richtexteditor/lang/rte-lang-tlh-Piqd.js +1 -0
- package/richtexteditor/lang/rte-lang-to.js +1 -0
- package/richtexteditor/lang/rte-lang-tr.js +1 -0
- package/richtexteditor/lang/rte-lang-ty.js +1 -0
- package/richtexteditor/lang/rte-lang-uk.js +1 -0
- package/richtexteditor/lang/rte-lang-ur.js +1 -0
- package/richtexteditor/lang/rte-lang-vi.js +1 -0
- package/richtexteditor/lang/rte-lang-yua.js +1 -0
- package/richtexteditor/lang/rte-lang-zh-Hans.js +1017 -2
- package/richtexteditor/lang/rte-lang-zh-Hant.js +1017 -2
- package/richtexteditor/plugins/a11yenhance.js +2 -1
- package/richtexteditor/plugins/a11yenhance.min.js +1 -1
- package/richtexteditor/plugins/accessibilitychecker.js +252 -60
- package/richtexteditor/plugins/accessibilitychecker.min.js +1 -1
- package/richtexteditor/plugins/aitoolkit.js +966 -303
- package/richtexteditor/plugins/aitoolkit.min.js +7 -7
- package/richtexteditor/plugins/all_plugins.js +7113 -1111
- package/richtexteditor/plugins/all_plugins.min.js +62 -59
- package/richtexteditor/plugins/autocorrect.js +66 -31
- package/richtexteditor/plugins/autocorrect.min.js +1 -1
- package/richtexteditor/plugins/autoembed.js +17 -0
- package/richtexteditor/plugins/autoembed.min.js +1 -1
- package/richtexteditor/plugins/blocktypes.js +18 -9
- package/richtexteditor/plugins/blocktypes.min.js +1 -1
- package/richtexteditor/plugins/bookmarkcard.js +12 -5
- package/richtexteditor/plugins/bookmarkcard.min.js +2 -2
- package/richtexteditor/plugins/changecase.js +72 -19
- package/richtexteditor/plugins/changecase.min.js +1 -1
- package/richtexteditor/plugins/charlimit.js +62 -2
- package/richtexteditor/plugins/charlimit.min.js +2 -2
- package/richtexteditor/plugins/comments.js +458 -59
- package/richtexteditor/plugins/comments.min.js +4 -3
- package/richtexteditor/plugins/contentminimap.js +25 -6
- package/richtexteditor/plugins/contentminimap.min.js +1 -1
- package/richtexteditor/plugins/crossreference.js +1 -1
- package/richtexteditor/plugins/crossreference.min.js +1 -1
- package/richtexteditor/plugins/dialoga11y.js +26 -4
- package/richtexteditor/plugins/dialoga11y.min.js +1 -1
- package/richtexteditor/plugins/dictation.js +1 -1
- package/richtexteditor/plugins/documentimport.js +220 -51
- package/richtexteditor/plugins/documentimport.min.js +4 -4
- package/richtexteditor/plugins/documentoutline.js +88 -38
- package/richtexteditor/plugins/documentoutline.min.js +1 -1
- package/richtexteditor/plugins/docxexport.js +204 -32
- package/richtexteditor/plugins/docxexport.min.js +2 -2
- package/richtexteditor/plugins/draghandle.js +267 -3
- package/richtexteditor/plugins/draghandle.min.js +1 -1
- package/richtexteditor/plugins/emailtoolkit.js +28 -14
- package/richtexteditor/plugins/emailtoolkit.min.js +1 -1
- package/richtexteditor/plugins/emojiautocomplete.js +110 -56
- package/richtexteditor/plugins/emojiautocomplete.min.js +1 -1
- package/richtexteditor/plugins/footnotes.js +65 -11
- package/richtexteditor/plugins/footnotes.min.js +1 -1
- package/richtexteditor/plugins/formatpainter.js +10 -0
- package/richtexteditor/plugins/formatpainter.min.js +1 -1
- package/richtexteditor/plugins/formattingmarks.js +53 -8
- package/richtexteditor/plugins/formattingmarks.min.js +1 -1
- package/richtexteditor/plugins/gapcursor.js +60 -0
- package/richtexteditor/plugins/gapcursor.min.js +1 -1
- package/richtexteditor/plugins/ghostcomplete.js +1 -1
- package/richtexteditor/plugins/html2pdf.js +1 -1
- package/richtexteditor/plugins/html2pdf.min.js +1 -1
- package/richtexteditor/plugins/imageeditor.js +12 -6
- package/richtexteditor/plugins/imageeditor.min.js +1 -1
- package/richtexteditor/plugins/importstyles.js +1 -1
- package/richtexteditor/plugins/inlinecode.js +25 -0
- package/richtexteditor/plugins/inlinecode.min.js +1 -1
- package/richtexteditor/plugins/insertcode.js +21 -3
- package/richtexteditor/plugins/insertcode.min.js +4 -4
- package/richtexteditor/plugins/insertemoji.js +112 -15
- package/richtexteditor/plugins/insertemoji.min.js +1 -1
- package/richtexteditor/plugins/insertgallery.js +42 -36
- package/richtexteditor/plugins/insertgallery.min.js +1 -1
- package/richtexteditor/plugins/inserttemplate.js +33 -17
- package/richtexteditor/plugins/inserttemplate.min.js +1 -1
- package/richtexteditor/plugins/keyboarda11y.js +66 -3
- package/richtexteditor/plugins/keyboarda11y.min.js +1 -1
- package/richtexteditor/plugins/layouttable.js +20 -0
- package/richtexteditor/plugins/layouttable.min.js +1 -1
- package/richtexteditor/plugins/linkchecker.js +29 -9
- package/richtexteditor/plugins/linkchecker.min.js +1 -1
- package/richtexteditor/plugins/localdraft.js +51 -7
- package/richtexteditor/plugins/localdraft.min.js +1 -1
- package/richtexteditor/plugins/markdownexport.js +159 -0
- package/richtexteditor/plugins/markdownexport.min.js +2 -2
- package/richtexteditor/plugins/mathdialog.js +11 -5
- package/richtexteditor/plugins/mathdialog.min.js +1 -1
- package/richtexteditor/plugins/mentionplugin.js +88 -25
- package/richtexteditor/plugins/mentionplugin.min.js +1 -1
- package/richtexteditor/plugins/mermaiddiagram.js +9 -3
- package/richtexteditor/plugins/mermaiddiagram.min.js +2 -2
- package/richtexteditor/plugins/multilevellist.js +4 -0
- package/richtexteditor/plugins/multilevellist.min.js +1 -1
- package/richtexteditor/plugins/pdfexport.js +235 -35
- package/richtexteditor/plugins/pdfexport.min.js +12 -12
- package/richtexteditor/plugins/permanentpen.js +3 -3
- package/richtexteditor/plugins/permanentpen.min.js +1 -1
- package/richtexteditor/plugins/readabilitystats.js +25 -11
- package/richtexteditor/plugins/readabilitystats.min.js +1 -1
- package/richtexteditor/plugins/readaloud.js +29 -15
- package/richtexteditor/plugins/readaloud.min.js +1 -1
- package/richtexteditor/plugins/restrictedediting.js +166 -0
- package/richtexteditor/plugins/restrictedediting.min.js +2 -2
- package/richtexteditor/plugins/revisionhistory.js +169 -37
- package/richtexteditor/plugins/revisionhistory.min.js +3 -3
- package/richtexteditor/plugins/rubyannotation.js +19 -9
- package/richtexteditor/plugins/rubyannotation.min.js +1 -1
- package/richtexteditor/plugins/sanitizer.js +86 -4
- package/richtexteditor/plugins/sanitizer.min.js +1 -1
- package/richtexteditor/plugins/slashcommand.js +30 -16
- package/richtexteditor/plugins/slashcommand.min.js +2 -2
- package/richtexteditor/plugins/smartchips.js +36 -22
- package/richtexteditor/plugins/smartchips.min.js +2 -2
- package/richtexteditor/plugins/spellcheck.js +17 -8
- package/richtexteditor/plugins/spellcheck.min.js +2 -2
- package/richtexteditor/plugins/stateinspector.js +19 -9
- package/richtexteditor/plugins/stateinspector.min.js +2 -2
- package/richtexteditor/plugins/structured-content-bridge.js +56 -24
- package/richtexteditor/plugins/structured-content-bridge.min.js +7 -7
- package/richtexteditor/plugins/tableofcontents.js +5 -2
- package/richtexteditor/plugins/tableofcontents.min.js +1 -1
- package/richtexteditor/plugins/tabletools.js +388 -3
- package/richtexteditor/plugins/tabletools.min.js +1 -1
- package/richtexteditor/plugins/textdirection.js +18 -5
- package/richtexteditor/plugins/textdirection.min.js +1 -1
- package/richtexteditor/plugins/textpartlanguage.js +161 -32
- package/richtexteditor/plugins/textpartlanguage.min.js +1 -1
- package/richtexteditor/plugins/todolist.js +90 -6
- package/richtexteditor/plugins/todolist.min.js +1 -1
- package/richtexteditor/plugins/trackedchanges.js +1812 -25
- package/richtexteditor/plugins/trackedchanges.min.js +5 -3
- package/richtexteditor/plugins/wordexport.js +2 -2
- package/richtexteditor/plugins/yjscollab.js +9 -4
- package/richtexteditor/plugins/yjscollab.min.js +1 -1
- package/richtexteditor/plugins/zz_richtextbox_dialog_style.js +22 -13
- package/richtexteditor/plugins/zz_richtextbox_dialog_style.min.js +1 -1
- package/richtexteditor/rte-config.js +131 -50
- package/richtexteditor/rte-headless.js +19 -4
- package/richtexteditor/rte-webcomponent.js +89 -16
- package/richtexteditor/rte.js +133 -52
- package/richtexteditor/runtime/colorpicker_more_ns.htm +93 -16
- package/scripts/build-angular.mjs +97 -0
- package/svelte/index.d.ts +2 -1
- package/svelte/index.js +80 -9
- package/vue/index.js +130 -34
- package/angular/component.ts +0 -297
- package/angular/index.ts +0 -24
|
@@ -4,17 +4,28 @@
|
|
|
4
4
|
<meta http-equiv="Page-Exit" content="blendTrans(Duration=0.1)" />
|
|
5
5
|
|
|
6
6
|
<script type="text/javascript">
|
|
7
|
+
// Call the editor directly when this frame may. Opened from disk (file://) every frame
|
|
8
|
+
// is its own origin and the direct call throws a SecurityError - which used to abort this
|
|
9
|
+
// page's load before it drew Recent, and made OK do nothing. Post a message instead; the
|
|
10
|
+
// editor's Color Picker listens for this frame's messages.
|
|
11
|
+
function callPicker(method, value) {
|
|
12
|
+
try { parent.rtecolorpicker[method](value); return; }
|
|
13
|
+
catch (e) { }
|
|
14
|
+
try { parent.postMessage({ rtecolorpicker: method, value: value }, "*"); }
|
|
15
|
+
catch (e) { }
|
|
16
|
+
}
|
|
7
17
|
function updateColor(c) {
|
|
8
|
-
|
|
18
|
+
callPicker("update", c);
|
|
9
19
|
}
|
|
10
20
|
function selectColor(c) {
|
|
11
|
-
|
|
21
|
+
callPicker("select", c);
|
|
12
22
|
}
|
|
13
23
|
function selectCancel() {
|
|
14
|
-
|
|
24
|
+
callPicker("cancel");
|
|
15
25
|
}
|
|
16
26
|
function setCallback(cb) {
|
|
17
|
-
parent.rtecolorpicker.setCallback(cb);
|
|
27
|
+
try { parent.rtecolorpicker.setCallback(cb); }
|
|
28
|
+
catch (e) { }
|
|
18
29
|
}
|
|
19
30
|
</script>
|
|
20
31
|
|
|
@@ -121,12 +132,14 @@
|
|
|
121
132
|
|
|
122
133
|
}
|
|
123
134
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
135
|
+
var _dialogArguments = null;
|
|
136
|
+
try { _dialogArguments = top.dialogArguments; } catch (e) { } // cross-origin from disk
|
|
137
|
+
if (_dialogArguments) {
|
|
138
|
+
if (typeof (_dialogArguments) == 'object') {
|
|
139
|
+
if (_dialogArguments.onchange) {
|
|
140
|
+
firecolorchange = _dialogArguments.onchange;
|
|
141
|
+
_origincolor = _dialogArguments.color;
|
|
142
|
+
_editor = _dialogArguments.editor;
|
|
130
143
|
}
|
|
131
144
|
}
|
|
132
145
|
}
|
|
@@ -313,7 +326,8 @@
|
|
|
313
326
|
msg.SelectAColor = "Select a color:";
|
|
314
327
|
msg.OKButton = "OK";
|
|
315
328
|
msg.CancelButton = "Cancel";
|
|
316
|
-
msg.Recent = "Recent";
|
|
329
|
+
msg.Recent = "Recent colors";
|
|
330
|
+
msg.RecentEmpty = "Colors you apply will appear here.";
|
|
317
331
|
msg.WebSafeWarning = "Warning: not a web safe color";
|
|
318
332
|
msg.WebSafeClick = "Click to select web safe color";
|
|
319
333
|
msg.HsbHue = "H:";
|
|
@@ -392,11 +406,17 @@
|
|
|
392
406
|
frm.ColorType[new Number(GetCookie("ColorMode") || 0)].checked = true;
|
|
393
407
|
ColorMode_Changed(e);
|
|
394
408
|
|
|
395
|
-
|
|
409
|
+
// The editor passes its list (every colour it applied, from anywhere); fall back to
|
|
410
|
+
// the shared storage for a page opened some other way.
|
|
411
|
+
var recent = GetQuery("Recent") || GetCookie("RecentColors") || "";
|
|
412
|
+
recent = String(recent).toUpperCase().replace(/[^0-9A-F]/g, "");
|
|
413
|
+
recent = recent.substring(0, recent.length - recent.length % 6);
|
|
396
414
|
|
|
397
415
|
var RecentTooltip = msg.RecentTooltip;
|
|
416
|
+
var recentShown = 0;
|
|
398
417
|
for (var i = 1; i < 33; i++)
|
|
399
|
-
if (recent.length / 6 >= i) {
|
|
418
|
+
if (recent.length / 6 >= i && i <= 24) {
|
|
419
|
+
recentShown++;
|
|
400
420
|
hex = recent.substr((i - 1) * 6, 6);
|
|
401
421
|
var rgb = HexToRgb(hex);
|
|
402
422
|
var title = formatString(msg.RecentTooltip, hex, rgb[0], rgb[1], rgb[2]);
|
|
@@ -410,8 +430,13 @@
|
|
|
410
430
|
recentColor.onkeydown = pnlRecent_KeyDown;
|
|
411
431
|
}
|
|
412
432
|
else
|
|
413
|
-
document.getElementById("pnlRecent" + i).
|
|
414
|
-
|
|
433
|
+
document.getElementById("pnlRecent" + i).className = "recent-empty";
|
|
434
|
+
if (!recentShown) {
|
|
435
|
+
var none = document.createElement("span");
|
|
436
|
+
none.id = "pnlRecentNone";
|
|
437
|
+
none.innerText = msg.RecentEmpty;
|
|
438
|
+
document.getElementById("pnlRecent").appendChild(none);
|
|
439
|
+
}
|
|
415
440
|
}
|
|
416
441
|
|
|
417
442
|
function pnlRecent_Click(e) {
|
|
@@ -2421,6 +2446,56 @@ Elements
|
|
|
2421
2446
|
margin: 0;
|
|
2422
2447
|
text-align: center;
|
|
2423
2448
|
}
|
|
2449
|
+
|
|
2450
|
+
/* Recent colors: only the swatches there are, rounded, in a grid - not 32 sunken empty
|
|
2451
|
+
boxes. Up to 24 (three rows) fit the space. */
|
|
2452
|
+
#colorpickerpanel #pnlRecentBorder {
|
|
2453
|
+
display: none;
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
#colorpickerpanel #lblRecent {
|
|
2457
|
+
width: 160px;
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
#colorpickerpanel #pnlRecent {
|
|
2461
|
+
display: grid;
|
|
2462
|
+
grid-template-columns: repeat(8, 16px);
|
|
2463
|
+
grid-auto-rows: 16px;
|
|
2464
|
+
gap: 4px;
|
|
2465
|
+
align-content: start;
|
|
2466
|
+
height: 72px;
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
#colorpickerpanel #pnlRecent DIV {
|
|
2470
|
+
position: static;
|
|
2471
|
+
width: 16px;
|
|
2472
|
+
height: 16px;
|
|
2473
|
+
box-sizing: border-box;
|
|
2474
|
+
border: 1px solid rgba(0, 0, 0, .22);
|
|
2475
|
+
border-radius: 3px;
|
|
2476
|
+
cursor: pointer;
|
|
2477
|
+
transition: transform .1s, box-shadow .1s;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
#colorpickerpanel #pnlRecent DIV:hover {
|
|
2481
|
+
transform: scale(1.2);
|
|
2482
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
#colorpickerpanel #pnlRecent DIV:focus-visible {
|
|
2486
|
+
outline: 2px solid #1a73e8;
|
|
2487
|
+
outline-offset: 1px;
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
#colorpickerpanel #pnlRecent DIV.recent-empty {
|
|
2491
|
+
display: none;
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
#pnlRecentNone {
|
|
2495
|
+
grid-column: 1 / -1;
|
|
2496
|
+
font: 11px/1.35 Arial, sans-serif;
|
|
2497
|
+
color: #6b7280;
|
|
2498
|
+
}
|
|
2424
2499
|
</style>
|
|
2425
2500
|
<title>CustomColor</title>
|
|
2426
2501
|
</head>
|
|
@@ -2683,7 +2758,9 @@ Elements
|
|
|
2683
2758
|
<script>
|
|
2684
2759
|
|
|
2685
2760
|
new function () {
|
|
2686
|
-
var editor =
|
|
2761
|
+
var editor = null;
|
|
2762
|
+
try { editor = parent.rtecolorpickereditor; } catch (e) { } // cross-origin from disk: keep English
|
|
2763
|
+
if (!editor || !editor.getLangText) return;
|
|
2687
2764
|
var ns = document.getElementsByTagName("*");
|
|
2688
2765
|
for (var i = 0; i < ns.length; i++) {
|
|
2689
2766
|
var n = ns[i];
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Build a partial-Ivy ESM entry point. Never publishes or changes editor core.
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
const packageRoot = path.resolve(import.meta.dirname, '..');
|
|
9
|
+
const repoRoot = path.dirname(packageRoot);
|
|
10
|
+
const sha256 = data => createHash('sha256').update(data).digest('hex');
|
|
11
|
+
// npm may repack an installed distribution. It contains validated generated
|
|
12
|
+
// output, not the maintainer-only TypeScript sources/toolchain.
|
|
13
|
+
try { await fs.access(path.join(packageRoot, 'angular/component.ts')); }
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (error.code !== 'ENOENT') throw error;
|
|
16
|
+
const manifest = JSON.parse(await fs.readFile(path.join(packageRoot, 'angular/build-manifest.json'), 'utf8'));
|
|
17
|
+
for (const [file, expected] of Object.entries(manifest.outputs)) {
|
|
18
|
+
if (sha256(await fs.readFile(path.join(packageRoot, file))) !== expected.sha256) throw new Error('Invalid prebuilt Angular output: ' + file);
|
|
19
|
+
}
|
|
20
|
+
for (const [file, expected] of Object.entries(manifest.sources)) {
|
|
21
|
+
let data;
|
|
22
|
+
try { data = await fs.readFile(path.join(packageRoot, file)); }
|
|
23
|
+
catch (readError) { if (readError.code === 'ENOENT') continue; throw readError; }
|
|
24
|
+
if (sha256(data) !== expected) throw new Error('Angular dependency changed; rebuild from the repository: ' + file);
|
|
25
|
+
}
|
|
26
|
+
console.log('Verified prebuilt Angular entry point');
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
const ownRequire = createRequire(path.join(packageRoot, 'package.json'));
|
|
30
|
+
let toolRequire = ownRequire;
|
|
31
|
+
try { toolRequire.resolve('@angular/compiler-cli/package.json'); }
|
|
32
|
+
catch {
|
|
33
|
+
// The downloadable Angular demo already has this pinned toolchain installed
|
|
34
|
+
// in a repository checkout. Published consumers do not run this build step.
|
|
35
|
+
toolRequire = createRequire(path.join(repoRoot, 'Demos/rte-ng-ts/package.json'));
|
|
36
|
+
}
|
|
37
|
+
const compilerPackage = toolRequire.resolve('@angular/compiler-cli/package.json');
|
|
38
|
+
const compilerInfo = JSON.parse(await fs.readFile(compilerPackage, 'utf8'));
|
|
39
|
+
const compilerDir = path.dirname(compilerPackage);
|
|
40
|
+
const compilerBin = path.resolve(compilerDir, compilerInfo.bin.ngc);
|
|
41
|
+
const angularScope = path.dirname(path.dirname(toolRequire.resolve('@angular/core/package.json')));
|
|
42
|
+
const rxjs = path.dirname(toolRequire.resolve('rxjs/package.json'));
|
|
43
|
+
const stage = await fs.mkdtemp(path.join(os.tmpdir(), 'rte-angular-apf-'));
|
|
44
|
+
const config = {
|
|
45
|
+
compilerOptions: {
|
|
46
|
+
target: 'ES2022', module: 'ES2022', moduleResolution: 'bundler',
|
|
47
|
+
experimentalDecorators: true, strict: true, declaration: true,
|
|
48
|
+
skipLibCheck: false, noEmitOnError: true, types: [],
|
|
49
|
+
rootDir: packageRoot, outDir: path.join(stage, 'out'), baseUrl: packageRoot,
|
|
50
|
+
paths: { '@angular/*': [path.join(angularScope, '*')], rxjs: [rxjs], 'rxjs/*': [path.join(rxjs, '*')] }
|
|
51
|
+
},
|
|
52
|
+
angularCompilerOptions: { strictTemplates: true, compilationMode: 'partial' },
|
|
53
|
+
files: [path.join(packageRoot, 'angular/index.ts')]
|
|
54
|
+
};
|
|
55
|
+
const configFile = path.join(stage, 'tsconfig.json');
|
|
56
|
+
await fs.writeFile(configFile, JSON.stringify(config, null, 2));
|
|
57
|
+
const result = spawnSync(process.execPath, [compilerBin, '-p', configFile], { cwd: packageRoot, encoding: 'utf8', windowsHide: true, timeout: 120000 });
|
|
58
|
+
process.stdout.write(result.stdout || ''); process.stderr.write(result.stderr || '');
|
|
59
|
+
if (result.status !== 0) throw new Error('Angular partial compilation failed; staging retained at ' + stage);
|
|
60
|
+
const esbuild = toolRequire('esbuild');
|
|
61
|
+
const bundled = await esbuild.build({
|
|
62
|
+
entryPoints: [path.join(stage, 'out/angular/index.js')],
|
|
63
|
+
bundle: true, write: false, format: 'esm', platform: 'browser', target: 'es2022',
|
|
64
|
+
charset: 'utf8', minifyWhitespace: true, legalComments: 'eof',
|
|
65
|
+
banner: { js: '// Generated Angular partial-Ivy entry. See package license.' },
|
|
66
|
+
external: ['@angular/*'],
|
|
67
|
+
plugins: [{ name: 'rte-shared-runtime', setup(build) {
|
|
68
|
+
build.onResolve({ filter: /^\.\.\/integrations\/shared(?:\.js)?$/ }, () => ({ path: path.join(packageRoot, 'integrations/shared.js') }));
|
|
69
|
+
} }]
|
|
70
|
+
});
|
|
71
|
+
let declarations = await fs.readFile(path.join(stage, 'out/angular/component.d.ts'), 'utf8');
|
|
72
|
+
const indexDeclarations = await fs.readFile(path.join(stage, 'out/angular/index.d.ts'), 'utf8');
|
|
73
|
+
const ts = toolRequire('typescript');
|
|
74
|
+
const indexAst = ts.createSourceFile('index.d.ts', indexDeclarations, ts.ScriptTarget.Latest, true);
|
|
75
|
+
const componentExport = indexAst.statements.find(s => ts.isExportDeclaration(s) && s.moduleSpecifier?.text === './component');
|
|
76
|
+
if (!componentExport) throw new Error('Missing generated component export');
|
|
77
|
+
declarations += '\n' + indexDeclarations.slice(0, componentExport.getFullStart()) + indexDeclarations.slice(componentExport.getEnd());
|
|
78
|
+
if (!declarations.includes('ɵɵComponentDeclaration') || !bundled.outputFiles[0].text.includes('ɵɵngDeclareComponent')) throw new Error('Partial-Ivy metadata is required');
|
|
79
|
+
const sources = {};
|
|
80
|
+
for (const file of ['angular/component.ts', 'angular/index.ts', 'integrations/shared.js', 'integrations/shared.d.ts', 'index.d.ts', 'scripts/build-angular.mjs']) sources[file] = sha256(await fs.readFile(path.join(packageRoot, file)));
|
|
81
|
+
const outputs = { 'angular/index.mjs': bundled.outputFiles[0].text, 'angular/index.d.ts': declarations };
|
|
82
|
+
async function writeIfChanged(file, data) {
|
|
83
|
+
try { if (await fs.readFile(file, 'utf8') === data) return; }
|
|
84
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
85
|
+
await fs.writeFile(file, data);
|
|
86
|
+
}
|
|
87
|
+
// Save the existing public declarations before first replacing them with
|
|
88
|
+
// compiler-generated metadata. This is a local migration backup, not payload.
|
|
89
|
+
const backup = path.join(stage, 'previous-index.d.ts');
|
|
90
|
+
await fs.mkdir(path.dirname(backup), { recursive: true });
|
|
91
|
+
try { await fs.copyFile(path.join(packageRoot, 'angular/index.d.ts'), backup, (await import('node:fs')).constants.COPYFILE_EXCL); }
|
|
92
|
+
catch (error) { if (error.code !== 'EEXIST') throw error; }
|
|
93
|
+
for (const [file, data] of Object.entries(outputs)) await writeIfChanged(path.join(packageRoot, file), data);
|
|
94
|
+
const manifest = { angularCompiler: compilerInfo.version, typescript: ts.version, esbuild: esbuild.version, sources,
|
|
95
|
+
outputs: Object.fromEntries(Object.entries(outputs).map(([file, data]) => [file, { bytes: Buffer.byteLength(data), sha256: sha256(data) }])) };
|
|
96
|
+
await writeIfChanged(path.join(packageRoot, 'angular/build-manifest.json'), JSON.stringify(manifest, null, 2) + '\n');
|
|
97
|
+
console.log('Built Angular partial-Ivy ESM + metadata declarations', JSON.stringify(manifest.outputs));
|
package/svelte/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ import type { HeadlessController, HeadlessEditorOptions, HeadlessState } from ".
|
|
|
4
4
|
export interface SvelteEditorOptions extends HeadlessEditorOptions {
|
|
5
5
|
onReady?: (editor: HeadlessController) => void;
|
|
6
6
|
onUpdate?: (state: HeadlessState) => void;
|
|
7
|
-
|
|
7
|
+
/** Called with the controller as this; may flush final native input synchronously on unmount. */
|
|
8
|
+
onChange?: (this: HeadlessController, ...args: any[]) => void;
|
|
8
9
|
onError?: (error: unknown) => void;
|
|
9
10
|
}
|
|
10
11
|
|
package/svelte/index.js
CHANGED
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
* let state = {};
|
|
12
12
|
* </script>
|
|
13
13
|
*
|
|
14
|
-
* <button
|
|
15
|
-
*
|
|
14
|
+
* <button type="button" disabled={!editor} aria-pressed={!!state.bold}
|
|
15
|
+
* on:pointerdown|preventDefault
|
|
16
|
+
* on:click={() => editor && editor.run("bold")}
|
|
17
|
+
* class:is-active={state.bold}>Bold</button>
|
|
16
18
|
*
|
|
17
19
|
* <div use:richTextEditor={{
|
|
18
20
|
* value: "<p>Hello</p>",
|
|
@@ -21,34 +23,103 @@
|
|
|
21
23
|
* }}></div>
|
|
22
24
|
*/
|
|
23
25
|
var headless = require("../headless");
|
|
26
|
+
var initializationScope = require("../integrations/initialization-scope");
|
|
27
|
+
var nativeMounts = require("../integrations/native-mount");
|
|
24
28
|
|
|
25
29
|
function richTextEditor(node, options) {
|
|
26
30
|
options = options || {};
|
|
27
31
|
var controller = null;
|
|
28
32
|
var current = options;
|
|
33
|
+
var disposed = false;
|
|
34
|
+
var pendingScope = null;
|
|
35
|
+
var lastKnownHtml = null;
|
|
36
|
+
var mountBoundary = null;
|
|
37
|
+
var nativeMount = null;
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
function releaseController(ctl) {
|
|
40
|
+
if (ctl) { try { ctl.destroy(); } catch (e) { /* Continue lifecycle cleanup. */ } }
|
|
41
|
+
nativeMounts.releaseNativeMount(ctl && ctl.editor, nativeMount);
|
|
42
|
+
nativeMount = null;
|
|
43
|
+
var boundary = mountBoundary;
|
|
44
|
+
mountBoundary = null;
|
|
45
|
+
if (boundary && boundary.parentNode) boundary.parentNode.removeChild(boundary);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Route synchronous setup errors through onError too, and avoid creating
|
|
49
|
+
// an editor when an action is destroyed before the first microtask.
|
|
50
|
+
Promise.resolve().then(function () {
|
|
51
|
+
if (disposed) return null;
|
|
52
|
+
pendingScope = initializationScope.createInitializationScope(current.signal);
|
|
53
|
+
// Keep native form-control conversion unchanged for legacy callers.
|
|
54
|
+
if (/^(INPUT|TEXTAREA)$/i.test(node.tagName || "")) {
|
|
55
|
+
return headless.createHeadlessEditor(node, Object.assign({}, current, { signal: pendingScope.signal }));
|
|
56
|
+
}
|
|
57
|
+
// The action node belongs to Svelte. Plugins may reparent their own
|
|
58
|
+
// host, so contain all generated shells in a removable private subtree.
|
|
59
|
+
mountBoundary = node.ownerDocument.createElement("div");
|
|
60
|
+
var editorMount = node.ownerDocument.createElement("div");
|
|
61
|
+
mountBoundary.appendChild(editorMount);
|
|
62
|
+
node.appendChild(mountBoundary);
|
|
63
|
+
nativeMount = nativeMounts.captureNativeMount(editorMount);
|
|
64
|
+
return headless.createHeadlessEditor(editorMount, Object.assign({}, current, { signal: pendingScope.signal }));
|
|
65
|
+
})
|
|
31
66
|
.then(function (ctl) {
|
|
67
|
+
if (pendingScope) pendingScope.complete();
|
|
68
|
+
if (!ctl) return;
|
|
69
|
+
if (disposed) { releaseController(ctl); return; }
|
|
32
70
|
controller = ctl;
|
|
33
|
-
if (current.
|
|
34
|
-
|
|
35
|
-
|
|
71
|
+
if (current.value != null && current.value !== ctl.getHTML()) ctl.setHTML(current.value);
|
|
72
|
+
lastKnownHtml = ctl.getHTML();
|
|
73
|
+
// Stable relays read the latest options. Svelte can replace event
|
|
74
|
+
// callbacks without remounting the action or leaving stale closures.
|
|
75
|
+
ctl.on("update", function () {
|
|
76
|
+
if (!disposed && typeof current.onUpdate === "function") current.onUpdate.apply(ctl, arguments);
|
|
77
|
+
});
|
|
78
|
+
ctl.on("change", function () {
|
|
79
|
+
if (!disposed && typeof current.onChange === "function") {
|
|
80
|
+
lastKnownHtml = ctl.getHTML();
|
|
81
|
+
current.onChange.apply(ctl, arguments);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
if (typeof current.onReady === "function") current.onReady(ctl);
|
|
36
85
|
})
|
|
37
86
|
.catch(function (error) {
|
|
38
|
-
if (
|
|
87
|
+
if (pendingScope) pendingScope.complete();
|
|
88
|
+
var ctl = controller;
|
|
89
|
+
controller = null;
|
|
90
|
+
releaseController(ctl);
|
|
91
|
+
if (!disposed && typeof current.onError === "function") current.onError(error);
|
|
39
92
|
});
|
|
40
93
|
|
|
41
94
|
return {
|
|
42
95
|
update: function (next) {
|
|
96
|
+
if (disposed) return;
|
|
97
|
+
var previous = current;
|
|
43
98
|
current = next || {};
|
|
44
99
|
// keep content in sync if the bound value changes
|
|
45
|
-
if (controller && next && next.value != null && next.value !== controller.getHTML()) {
|
|
100
|
+
if (controller && next && next.value != null && next.value !== previous.value && next.value !== controller.getHTML()) {
|
|
46
101
|
controller.setHTML(next.value);
|
|
102
|
+
lastKnownHtml = controller.getHTML();
|
|
47
103
|
}
|
|
48
104
|
},
|
|
49
105
|
destroy: function () {
|
|
50
|
-
if (
|
|
106
|
+
if (disposed) return;
|
|
107
|
+
disposed = true;
|
|
108
|
+
if (pendingScope) pendingScope.dispose();
|
|
109
|
+
var ctl = controller;
|
|
51
110
|
controller = null;
|
|
111
|
+
try {
|
|
112
|
+
// Core change is deferred; an action can unmount in the same
|
|
113
|
+
// turn as the last native input. Deliver that value once while
|
|
114
|
+
// the controller is still readable, before destroying it.
|
|
115
|
+
if (ctl && typeof current.onChange === "function") {
|
|
116
|
+
var finalHtml = ctl.getHTML();
|
|
117
|
+
if (finalHtml !== lastKnownHtml) {
|
|
118
|
+
lastKnownHtml = finalHtml;
|
|
119
|
+
current.onChange.call(ctl, ctl.editor);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} finally { releaseController(ctl); }
|
|
52
123
|
}
|
|
53
124
|
};
|
|
54
125
|
}
|
package/vue/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
var vue = require("vue");
|
|
2
2
|
var shared = require("../integrations/shared");
|
|
3
3
|
var headless = require("../headless");
|
|
4
|
+
var initializationScope = require("../integrations/initialization-scope");
|
|
5
|
+
var nativeMounts = require("../integrations/native-mount");
|
|
4
6
|
|
|
5
7
|
function editorMethodAccessor(editorRef, name, emptyValue) {
|
|
6
8
|
return function () {
|
|
@@ -24,6 +26,7 @@ var RichTextEditorVue = vue.defineComponent({
|
|
|
24
26
|
type: Boolean,
|
|
25
27
|
default: true
|
|
26
28
|
},
|
|
29
|
+
changeDelay: { type: Number, default: 120 },
|
|
27
30
|
config: {
|
|
28
31
|
type: Object,
|
|
29
32
|
default: function () {
|
|
@@ -52,8 +55,47 @@ var RichTextEditorVue = vue.defineComponent({
|
|
|
52
55
|
var hostRef = vue.ref(null);
|
|
53
56
|
var editorRef = vue.ref(null);
|
|
54
57
|
var changeHandler = null;
|
|
58
|
+
var blurHandler = null;
|
|
55
59
|
var emitChange = null;
|
|
56
60
|
var lastEmitted;
|
|
61
|
+
var disposed = false;
|
|
62
|
+
var writingValue = false;
|
|
63
|
+
var lastKnownHtml = null;
|
|
64
|
+
var nativeMount = null;
|
|
65
|
+
|
|
66
|
+
function emitCurrentValue() {
|
|
67
|
+
var editor = editorRef.value;
|
|
68
|
+
if (!editor) return;
|
|
69
|
+
var nextValue = shared.getEditorValue(editor, props.valueFormat);
|
|
70
|
+
var html = typeof nextValue === "string" ? nextValue : (typeof nextValue.html === "string" ? nextValue.html : editor.getHTMLCode());
|
|
71
|
+
if (html === lastKnownHtml) return;
|
|
72
|
+
lastKnownHtml = html;
|
|
73
|
+
lastEmitted = nextValue;
|
|
74
|
+
context.emit("update:modelValue", nextValue);
|
|
75
|
+
if (editorRef.value === editor) context.emit("change", nextValue, editor);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function releaseEditor() {
|
|
79
|
+
if (emitChange) emitChange.cancel();
|
|
80
|
+
emitChange = null;
|
|
81
|
+
var editor = editorRef.value;
|
|
82
|
+
var handler = changeHandler;
|
|
83
|
+
editorRef.value = null;
|
|
84
|
+
changeHandler = null;
|
|
85
|
+
if (editor && blurHandler && typeof editor.detachEvent === "function") {
|
|
86
|
+
try { editor.detachEvent("blur", blurHandler); } catch (e) { /* Continue cleanup. */ }
|
|
87
|
+
}
|
|
88
|
+
blurHandler = null;
|
|
89
|
+
if (editor && handler && typeof editor.detachEvent === "function") {
|
|
90
|
+
try { editor.detachEvent("change", handler); } catch (e) { /* Continue cleanup. */ }
|
|
91
|
+
}
|
|
92
|
+
if (editor && typeof editor.destroy === "function") {
|
|
93
|
+
try { editor.destroy(); } catch (e) { /* Continue cleanup. */ }
|
|
94
|
+
}
|
|
95
|
+
nativeMounts.releaseNativeMount(editor, nativeMount);
|
|
96
|
+
nativeMount = null;
|
|
97
|
+
if (hostRef.value) hostRef.value.innerHTML = "";
|
|
98
|
+
}
|
|
57
99
|
|
|
58
100
|
function syncEditor(nextValue) {
|
|
59
101
|
if (!editorRef.value) {
|
|
@@ -62,11 +104,15 @@ var RichTextEditorVue = vue.defineComponent({
|
|
|
62
104
|
|
|
63
105
|
var nextHtml = shared.normalizeStructuredContent(nextValue);
|
|
64
106
|
if (editorRef.value.getHTMLCode() !== nextHtml) {
|
|
65
|
-
|
|
107
|
+
writingValue = true;
|
|
108
|
+
try { shared.setEditorValue(editorRef.value, nextValue, props.valueFormat); }
|
|
109
|
+
finally { writingValue = false; }
|
|
66
110
|
}
|
|
111
|
+
if (editorRef.value) lastKnownHtml = editorRef.value.getHTMLCode();
|
|
67
112
|
}
|
|
68
113
|
|
|
69
114
|
vue.onMounted(async function () {
|
|
115
|
+
if (disposed) return;
|
|
70
116
|
try {
|
|
71
117
|
if (props.autoload === false) {
|
|
72
118
|
shared.installStructuredContentBridge();
|
|
@@ -74,34 +120,54 @@ var RichTextEditorVue = vue.defineComponent({
|
|
|
74
120
|
await shared.loadRichTextEditorAssets({ basePath: props.assetBasePath });
|
|
75
121
|
}
|
|
76
122
|
|
|
77
|
-
if (!hostRef.value) {
|
|
123
|
+
if (disposed || !hostRef.value) {
|
|
78
124
|
return;
|
|
79
125
|
}
|
|
80
126
|
|
|
81
|
-
var
|
|
127
|
+
var editorMount = hostRef.value;
|
|
128
|
+
// Preserve legacy native form-control conversion. Block roots
|
|
129
|
+
// stay Vue-owned while plugins wrap only a disposable child.
|
|
130
|
+
if (!/^(INPUT|TEXTAREA)$/i.test(editorMount.tagName || "")) {
|
|
131
|
+
editorMount = hostRef.value.ownerDocument.createElement("div");
|
|
132
|
+
hostRef.value.appendChild(editorMount);
|
|
133
|
+
}
|
|
134
|
+
nativeMount = nativeMounts.captureNativeMount(editorMount);
|
|
135
|
+
var editor = shared.createEditor(editorMount, props.config || {});
|
|
136
|
+
if (disposed) {
|
|
137
|
+
try { editor.destroy(); } catch (e) { /* Continue cleanup. */ }
|
|
138
|
+
nativeMounts.releaseNativeMount(editor, nativeMount);
|
|
139
|
+
nativeMount = null;
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
82
142
|
editorRef.value = editor;
|
|
83
143
|
|
|
84
144
|
var initialValue = props.modelValue !== undefined ? props.modelValue : props.defaultValue;
|
|
85
145
|
if (initialValue !== undefined) {
|
|
86
146
|
shared.setEditorValue(editor, initialValue, props.valueFormat);
|
|
87
147
|
}
|
|
148
|
+
if (disposed) return;
|
|
149
|
+
lastKnownHtml = editor.getHTMLCode();
|
|
88
150
|
|
|
89
151
|
// Coalesce: the editor fires `change` per keystroke and
|
|
90
152
|
// getEditorValue serialises the whole document (78 ms on a
|
|
91
153
|
// 3000-paragraph document). See shared.createChangeCoalescer.
|
|
92
|
-
emitChange = shared.createChangeCoalescer(
|
|
93
|
-
var nextValue = shared.getEditorValue(editor, props.valueFormat);
|
|
94
|
-
lastEmitted = nextValue;
|
|
95
|
-
context.emit("update:modelValue", nextValue);
|
|
96
|
-
context.emit("change", nextValue, editor);
|
|
97
|
-
}, props.changeDelay == null ? 120 : props.changeDelay);
|
|
154
|
+
emitChange = shared.createChangeCoalescer(emitCurrentValue, props.changeDelay == null ? 120 : props.changeDelay);
|
|
98
155
|
|
|
99
|
-
changeHandler = function () { emitChange(); };
|
|
156
|
+
changeHandler = function () { if (!disposed && !writingValue && emitChange) emitChange(); };
|
|
100
157
|
|
|
101
158
|
editor.attachEvent("change", changeHandler);
|
|
159
|
+
blurHandler = function () {
|
|
160
|
+
if (disposed || writingValue) return;
|
|
161
|
+
if (emitChange) emitChange.flush();
|
|
162
|
+
emitCurrentValue();
|
|
163
|
+
};
|
|
164
|
+
editor.attachEvent("blur", blurHandler);
|
|
102
165
|
context.emit("ready", editor);
|
|
103
166
|
} catch (error) {
|
|
104
|
-
|
|
167
|
+
if (!disposed) {
|
|
168
|
+
releaseEditor();
|
|
169
|
+
context.emit("error", error);
|
|
170
|
+
}
|
|
105
171
|
}
|
|
106
172
|
});
|
|
107
173
|
|
|
@@ -126,23 +192,14 @@ var RichTextEditorVue = vue.defineComponent({
|
|
|
126
192
|
});
|
|
127
193
|
|
|
128
194
|
vue.onBeforeUnmount(function () {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (emitChange)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
try { ed.destroy(); } catch (e) { /* ignore */ }
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (hostRef.value) {
|
|
142
|
-
hostRef.value.innerHTML = "";
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
editorRef.value = null;
|
|
195
|
+
if (disposed) return;
|
|
196
|
+
disposed = true;
|
|
197
|
+
try {
|
|
198
|
+
if (emitChange) emitChange.flush();
|
|
199
|
+
// Core itself can defer change; preserve native input even if
|
|
200
|
+
// no wrapper timer was scheduled before the view unmounted.
|
|
201
|
+
if (changeHandler) emitCurrentValue();
|
|
202
|
+
} finally { releaseEditor(); }
|
|
146
203
|
});
|
|
147
204
|
|
|
148
205
|
function pluginAccessor(name) {
|
|
@@ -252,25 +309,64 @@ function useRichTextEditor(options) {
|
|
|
252
309
|
var editor = vue.shallowRef(null);
|
|
253
310
|
var state = vue.ref({});
|
|
254
311
|
var controller = null;
|
|
312
|
+
var disposed = false;
|
|
313
|
+
var pendingScope = null;
|
|
314
|
+
var activeHost = null;
|
|
315
|
+
var nativeMount = null;
|
|
316
|
+
|
|
317
|
+
function releaseController() {
|
|
318
|
+
var owned = controller;
|
|
319
|
+
controller = null;
|
|
320
|
+
if (editor.value === owned) editor.value = null;
|
|
321
|
+
if (owned) { try { owned.destroy(); } catch (e) { /* Continue cleanup. */ } }
|
|
322
|
+
nativeMounts.releaseNativeMount(owned && owned.editor, nativeMount);
|
|
323
|
+
nativeMount = null;
|
|
324
|
+
if (activeHost && !editor.value) activeHost.innerHTML = "";
|
|
325
|
+
}
|
|
255
326
|
|
|
256
327
|
vue.onMounted(function () {
|
|
257
|
-
|
|
328
|
+
activeHost = mountRef.value;
|
|
329
|
+
Promise.resolve().then(function () {
|
|
330
|
+
if (disposed) return null;
|
|
331
|
+
if (!activeHost) throw new Error("useRichTextEditor: render mountRef before initialization.");
|
|
332
|
+
pendingScope = initializationScope.createInitializationScope(options.signal);
|
|
333
|
+
var editorMount = activeHost;
|
|
334
|
+
if (!/^(INPUT|TEXTAREA)$/i.test(editorMount.tagName || "")) {
|
|
335
|
+
editorMount = activeHost.ownerDocument.createElement("div");
|
|
336
|
+
activeHost.appendChild(editorMount);
|
|
337
|
+
}
|
|
338
|
+
nativeMount = nativeMounts.captureNativeMount(editorMount);
|
|
339
|
+
return headless.createHeadlessEditor(editorMount, Object.assign({}, options, { signal: pendingScope.signal }));
|
|
340
|
+
})
|
|
258
341
|
.then(function (ctl) {
|
|
342
|
+
if (pendingScope) pendingScope.complete();
|
|
343
|
+
if (!ctl) return;
|
|
344
|
+
if (disposed) { try { ctl.destroy(); } finally { nativeMounts.releaseNativeMount(ctl.editor, nativeMount); nativeMount = null; } return; }
|
|
259
345
|
controller = ctl;
|
|
260
346
|
editor.value = ctl;
|
|
347
|
+
if (options.value != null && options.value !== ctl.getHTML()) ctl.setHTML(options.value);
|
|
261
348
|
state.value = ctl.state();
|
|
262
|
-
ctl.on("update", function (snapshot) { state.value = snapshot; });
|
|
349
|
+
ctl.on("update", function (snapshot) { if (!disposed) state.value = snapshot; });
|
|
263
350
|
if (options.onReady) { options.onReady(ctl); }
|
|
264
351
|
})
|
|
265
352
|
.catch(function (error) {
|
|
266
|
-
if (
|
|
353
|
+
if (pendingScope) pendingScope.complete();
|
|
354
|
+
if (!disposed) {
|
|
355
|
+
releaseController();
|
|
356
|
+
if (options.onError) options.onError(error);
|
|
357
|
+
}
|
|
267
358
|
});
|
|
268
359
|
});
|
|
269
360
|
|
|
270
361
|
vue.onBeforeUnmount(function () {
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
362
|
+
if (disposed) return;
|
|
363
|
+
disposed = true;
|
|
364
|
+
if (pendingScope) pendingScope.dispose();
|
|
365
|
+
releaseController();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
vue.watch(function () { return options.value; }, function (value) {
|
|
369
|
+
if (!disposed && controller && value != null && value !== controller.getHTML()) controller.setHTML(value);
|
|
274
370
|
});
|
|
275
371
|
|
|
276
372
|
return { mountRef: mountRef, editor: editor, state: state };
|