@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
|
@@ -194,8 +194,11 @@ function RTE_Plugin_DocxExport() {
|
|
|
194
194
|
bold: inherited.bold, italic: inherited.italic, underline: inherited.underline,
|
|
195
195
|
strike: inherited.strike, sizeHalfPoints: inherited.sizeHalfPoints,
|
|
196
196
|
color: inherited.color, highlight: inherited.highlight, vertAlign: inherited.vertAlign,
|
|
197
|
-
mono: inherited.mono, font: inherited.font
|
|
197
|
+
mono: inherited.mono, font: inherited.font,
|
|
198
|
+
// 2026-10-15 small caps, letter spacing and the phrase's language were not exported. tools/docx/run-props.mjs
|
|
199
|
+
smallCaps: inherited.smallCaps, spacingTw: inherited.spacingTw, lang: inherited.lang
|
|
198
200
|
};
|
|
201
|
+
if (node.getAttribute && node.getAttribute("lang")) s.lang = String(node.getAttribute("lang")).replace(/[^A-Za-z0-9-]/g, "");
|
|
199
202
|
var tag = node.tagName ? node.tagName.toLowerCase() : "";
|
|
200
203
|
if (tag === "b" || tag === "strong") s.bold = true;
|
|
201
204
|
if (tag === "i" || tag === "em") s.italic = true;
|
|
@@ -224,6 +227,11 @@ function RTE_Plugin_DocxExport() {
|
|
|
224
227
|
var fam = String(css.fontFamily).split(",")[0].replace(/^\s*['"]?|['"]?\s*$/g, "");
|
|
225
228
|
if (fam) s.font = fam;
|
|
226
229
|
}
|
|
230
|
+
if (/small-caps/.test(css.fontVariant || "") || /small-caps/.test(css.fontVariantCaps || "")) s.smallCaps = true;
|
|
231
|
+
if (css.letterSpacing && css.letterSpacing !== "normal") {
|
|
232
|
+
var lsm = /^\s*(-?[\d.]+)\s*(px|pt|em)?\s*$/.exec(css.letterSpacing);
|
|
233
|
+
if (lsm) { var lsPx = parseFloat(lsm[1]) * (lsm[2] === "pt" ? 4 / 3 : lsm[2] === "em" ? 16 : 1); s.spacingTw = Math.round(lsPx * 15); }
|
|
234
|
+
}
|
|
227
235
|
if (css.fontSize) {
|
|
228
236
|
var pt = cssToPoints(css.fontSize);
|
|
229
237
|
// w:sz is in HALF-POINTS. Writing points here makes every
|
|
@@ -266,12 +274,15 @@ function RTE_Plugin_DocxExport() {
|
|
|
266
274
|
if (fontName) p += '<w:rFonts w:ascii="' + esc(fontName) + '" w:hAnsi="' + esc(fontName) + '"/>';
|
|
267
275
|
if (s.bold) p += "<w:b/>";
|
|
268
276
|
if (s.italic) p += "<w:i/>";
|
|
277
|
+
if (s.smallCaps) p += "<w:smallCaps/>";
|
|
269
278
|
if (s.underline) p += '<w:u w:val="single"/>';
|
|
270
279
|
if (s.strike) p += "<w:strike/>";
|
|
271
280
|
if (s.color) p += '<w:color w:val="' + s.color + '"/>';
|
|
281
|
+
if (s.spacingTw) p += '<w:spacing w:val="' + s.spacingTw + '"/>';
|
|
272
282
|
if (s.highlight) p += '<w:shd w:val="clear" w:color="auto" w:fill="' + s.highlight + '"/>';
|
|
273
283
|
if (s.vertAlign) p += '<w:vertAlign w:val="' + s.vertAlign + '"/>';
|
|
274
284
|
if (s.sizeHalfPoints) p += '<w:sz w:val="' + s.sizeHalfPoints + '"/><w:szCs w:val="' + s.sizeHalfPoints + '"/>';
|
|
285
|
+
if (s.lang) p += '<w:lang w:val="' + s.lang + '"/>';
|
|
275
286
|
return p ? "<w:rPr>" + p + "</w:rPr>" : "";
|
|
276
287
|
}
|
|
277
288
|
|
|
@@ -388,7 +399,12 @@ function RTE_Plugin_DocxExport() {
|
|
|
388
399
|
function noteBodyFor(doc, id) {
|
|
389
400
|
try {
|
|
390
401
|
var el = doc.querySelector('.rte-fn-note[data-fn-id="' + id + '"]');
|
|
391
|
-
|
|
402
|
+
if (!el) return "";
|
|
403
|
+
// 2026-10-15 without the "back to reference" arrow link: it was written into the Word footnote, and every
|
|
404
|
+
// round trip added another arrow to the note. tools/docx/footnote-text.mjs
|
|
405
|
+
var copy = el.cloneNode(true), backs = copy.querySelectorAll(".rte-fn-back");
|
|
406
|
+
for (var i = 0; i < backs.length; i++) backs[i].parentNode.removeChild(backs[i]);
|
|
407
|
+
return (copy.textContent || "").replace(/\s+/g, " ").trim();
|
|
392
408
|
} catch (e) { return ""; }
|
|
393
409
|
}
|
|
394
410
|
function noteRun(b, kind, text) {
|
|
@@ -404,8 +420,14 @@ function RTE_Plugin_DocxExport() {
|
|
|
404
420
|
b.media.push({ name: name, bytes: data.bytes });
|
|
405
421
|
var rid = b.rel("image", "media/" + name);
|
|
406
422
|
// EMU: 914400 per inch, and a CSS pixel is 1/96 inch.
|
|
407
|
-
|
|
408
|
-
|
|
423
|
+
// 2026-10-15 the size on the page is the image's width / height (attribute, or a px style), not its natural
|
|
424
|
+
// pixels: a picture resized in the editor came back full size. One given: the other keeps the ratio.
|
|
425
|
+
// tools/docx/image-alt-size.mjs
|
|
426
|
+
var dw = cssPx(img.getAttribute("width")) || cssPx(img.style && img.style.width), dh = cssPx(img.getAttribute("height")) || cssPx(img.style && img.style.height);
|
|
427
|
+
if (dw && !dh) dh = dw * data.height / data.width;
|
|
428
|
+
if (dh && !dw) dw = dh * data.width / data.height;
|
|
429
|
+
var cx = Math.round((dw || data.width) * 914400 / 96);
|
|
430
|
+
var cy = Math.round((dh || data.height) * 914400 / 96);
|
|
409
431
|
var docPrId = b.media.length;
|
|
410
432
|
return '<w:r><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0" ' +
|
|
411
433
|
'xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">' +
|
|
@@ -421,6 +443,9 @@ function RTE_Plugin_DocxExport() {
|
|
|
421
443
|
"</pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>";
|
|
422
444
|
}
|
|
423
445
|
|
|
446
|
+
// a plain number or a px length; a percentage or em cannot be turned into a page size here
|
|
447
|
+
function cssPx(v) { var r = /^\s*([\d.]+)\s*(px)?\s*$/.exec(v == null ? "" : String(v)); return r ? parseFloat(r[1]) : 0; }
|
|
448
|
+
|
|
424
449
|
function encodeImage(img) {
|
|
425
450
|
try {
|
|
426
451
|
var w = img.naturalWidth || img.width, h = img.naturalHeight || img.height;
|
|
@@ -449,18 +474,18 @@ function RTE_Plugin_DocxExport() {
|
|
|
449
474
|
// A compact LaTeX -> OMML writer, matching the reader in documentimport.js
|
|
450
475
|
// so equations survive the round trip instead of arriving as their source.
|
|
451
476
|
var TEX_GLYPH = {
|
|
452
|
-
alpha: "
|
|
453
|
-
theta: "
|
|
454
|
-
rho: "
|
|
455
|
-
psi: "
|
|
456
|
-
Pi: "
|
|
457
|
-
pm: "
|
|
458
|
-
approx: "
|
|
459
|
-
to: "
|
|
460
|
-
"in": "
|
|
461
|
-
emptyset: "
|
|
462
|
-
dots: "
|
|
463
|
-
lfloor: "
|
|
477
|
+
alpha: "\u03b1", beta: "\u03b2", gamma: "\u03b3", delta: "\u03b4", epsilon: "\u03b5", zeta: "\u03b6", eta: "\u03b7",
|
|
478
|
+
theta: "\u03b8", iota: "\u03b9", kappa: "\u03ba", lambda: "\u03bb", mu: "\u03bc", nu: "\u03bd", xi: "\u03be", pi: "\u03c0",
|
|
479
|
+
rho: "\u03c1", sigma: "\u03c3", tau: "\u03c4", upsilon: "\u03c5", phi: "\u03c6", varphi: "\u03c6", chi: "\u03c7",
|
|
480
|
+
psi: "\u03c8", omega: "\u03c9", Gamma: "\u0393", Delta: "\u0394", Theta: "\u0398", Lambda: "\u039b", Xi: "\u039e",
|
|
481
|
+
Pi: "\u03a0", Sigma: "\u03a3", Phi: "\u03a6", Psi: "\u03a8", Omega: "\u03a9",
|
|
482
|
+
pm: "\xb1", mp: "\u2213", times: "\xd7", div: "\xf7", cdot: "\u22c5", neq: "\u2260", leq: "\u2264", geq: "\u2265",
|
|
483
|
+
approx: "\u2248", equiv: "\u2261", propto: "\u221d", infty: "\u221e", partial: "\u2202", nabla: "\u2207",
|
|
484
|
+
to: "\u2192", rightarrow: "\u2192", leftarrow: "\u2190", Rightarrow: "\u21d2", Leftrightarrow: "\u21d4",
|
|
485
|
+
"in": "\u2208", notin: "\u2209", subset: "\u2282", subseteq: "\u2286", cup: "\u222a", cap: "\u2229",
|
|
486
|
+
emptyset: "\u2205", forall: "\u2200", exists: "\u2203", neg: "\xac", land: "\u2227", lor: "\u2228",
|
|
487
|
+
dots: "\u2026", ldots: "\u2026", cdots: "\u22ef", langle: "\u27e8", rangle: "\u27e9",
|
|
488
|
+
lfloor: "\u230a", rfloor: "\u230b", lceil: "\u2308", rceil: "\u2309", quad: " ", ",": " ", ";": " "
|
|
464
489
|
};
|
|
465
490
|
var TEX_FUNCS = /^(sin|cos|tan|cot|sec|csc|sinh|cosh|tanh|log|ln|lg|exp|det|dim|gcd|arg|max|min|sup|inf)$/;
|
|
466
491
|
|
|
@@ -508,7 +533,7 @@ function RTE_Plugin_DocxExport() {
|
|
|
508
533
|
"<m:deg>" + deg + "</m:deg><m:e>" + group() + "</m:e></m:rad>";
|
|
509
534
|
}
|
|
510
535
|
case "sum": case "prod": case "int": case "oint": case "bigcup": case "bigcap": {
|
|
511
|
-
var chr = { sum: "
|
|
536
|
+
var chr = { sum: "\u2211", prod: "\u220f", "int": "\u222b", oint: "\u222e", bigcup: "\u22c3", bigcap: "\u22c2" }[name];
|
|
512
537
|
var sub = "", sup = "";
|
|
513
538
|
for (var g = 0; g < 2; g++) {
|
|
514
539
|
skipWs();
|
|
@@ -543,7 +568,7 @@ function RTE_Plugin_DocxExport() {
|
|
|
543
568
|
case "operatorname":
|
|
544
569
|
return "<m:func><m:funcPr/><m:fName>" + group() + "</m:fName><m:e>" + group() + "</m:e></m:func>";
|
|
545
570
|
case "hat": case "vec": case "tilde": case "bar": case "overline": case "dot": case "ddot": {
|
|
546
|
-
var mark = { hat: "
|
|
571
|
+
var mark = { hat: "\u0302", vec: "\u20d7", tilde: "\u0303", dot: "\u0307", ddot: "\u0308" }[name];
|
|
547
572
|
if (name === "bar" || name === "overline") return "<m:bar><m:barPr><m:pos m:val=\"top\"/></m:barPr><m:e>" + group() + "</m:e></m:bar>";
|
|
548
573
|
return '<m:acc><m:accPr><m:chr m:val="' + mark + '"/></m:accPr><m:e>' + group() + "</m:e></m:acc>";
|
|
549
574
|
}
|
|
@@ -632,6 +657,14 @@ function RTE_Plugin_DocxExport() {
|
|
|
632
657
|
// spelled <blockquote>, which dragged the Quote style along with it -
|
|
633
658
|
// so indented body text arrived italic and accent-coloured.
|
|
634
659
|
// 1px = 0.75pt and 1pt = 20 twips, hence px * 15.
|
|
660
|
+
// a signed CSS length in twips (1px = 15 twips); 0 when it is not a plain length
|
|
661
|
+
function lengthTwips(raw) {
|
|
662
|
+
var m = /^\s*(-?[\d.]+)\s*(px|pt|in|cm|mm|em|rem)?\s*$/i.exec(raw == null ? "" : String(raw));
|
|
663
|
+
if (!m) return 0;
|
|
664
|
+
var n = parseFloat(m[1]), u = (m[2] || "px").toLowerCase();
|
|
665
|
+
var px = u === "px" ? n : u === "pt" ? n * 4 / 3 : u === "in" ? n * 96 : u === "cm" ? n * 37.795 : u === "mm" ? n * 3.7795 : n * 16;
|
|
666
|
+
return Math.round(px * 15);
|
|
667
|
+
}
|
|
635
668
|
function indentTwips(node) {
|
|
636
669
|
if (!node || !node.style) return 0;
|
|
637
670
|
var raw = node.style.marginLeft || node.style.paddingLeft || "";
|
|
@@ -656,13 +689,23 @@ function RTE_Plugin_DocxExport() {
|
|
|
656
689
|
if (opts.heading) pr += '<w:pStyle w:val="Heading' + opts.heading + '"/>';
|
|
657
690
|
if (opts.quote) pr += '<w:pStyle w:val="Quote"/><w:ind w:left="720"/>';
|
|
658
691
|
if (opts.pre) pr += '<w:pStyle w:val="Code"/>';
|
|
692
|
+
if (opts.caption) pr += '<w:pStyle w:val="Caption"/>';
|
|
659
693
|
if (opts.numId) pr += "<w:numPr><w:ilvl w:val=\"" + (opts.level || 0) + "\"/><w:numId w:val=\"" + opts.numId + "\"/></w:numPr>";
|
|
660
694
|
if (opts.pageBreakBefore) pr += "<w:pageBreakBefore/>";
|
|
695
|
+
// 2026-10-15 direction, line height and first-line / hanging indent were not written (only the left indent
|
|
696
|
+
// and alignment were): an RTL paragraph came back left-to-right, double spacing came back single.
|
|
697
|
+
// pPr order is bidi, spacing, ind, jc. tools/docx/paragraph-props.mjs
|
|
698
|
+
if (node && node.getAttribute && (String(node.getAttribute("dir") || "").toLowerCase() === "rtl" || (node.style && node.style.direction === "rtl"))) pr += "<w:bidi/>";
|
|
699
|
+
var lhRaw = node && node.style ? String(node.style.lineHeight || "") : "", lhm;
|
|
700
|
+
if ((lhm = /^\s*([\d.]+)\s*$/.exec(lhRaw)) && parseFloat(lhm[1]) > 0) pr += '<w:spacing w:line="' + Math.round(parseFloat(lhm[1]) * 240) + '" w:lineRule="auto"/>';
|
|
701
|
+
else if ((lhm = /^\s*([\d.]+)%\s*$/.exec(lhRaw)) && parseFloat(lhm[1]) > 0) pr += '<w:spacing w:line="' + Math.round(parseFloat(lhm[1]) * 2.4) + '" w:lineRule="auto"/>';
|
|
702
|
+
else if ((lhm = /^\s*([\d.]+)(px|pt)\s*$/.exec(lhRaw)) && parseFloat(lhm[1]) > 0) pr += '<w:spacing w:line="' + Math.round(parseFloat(lhm[1]) * (lhm[2] === "pt" ? 20 : 15)) + '" w:lineRule="exact"/>';
|
|
661
703
|
// Independent of the Quote style: a real blockquote already got
|
|
662
704
|
// its w:ind above, so only emit this for everything else.
|
|
663
705
|
if (!opts.quote) {
|
|
664
706
|
var indTw = indentTwips(node);
|
|
665
|
-
|
|
707
|
+
var tiTw = lengthTwips(node && node.style ? node.style.textIndent : "");
|
|
708
|
+
if (indTw > 0 || tiTw) pr += '<w:ind' + (indTw > 0 ? ' w:left="' + indTw + '"' : "") + (tiTw > 0 ? ' w:firstLine="' + tiTw + '"' : tiTw < 0 ? ' w:hanging="' + (-tiTw) + '"' : "") + '/>';
|
|
666
709
|
}
|
|
667
710
|
var align = node && node.style ? node.style.textAlign : "";
|
|
668
711
|
if (align === "center" || align === "right") pr += '<w:jc w:val="' + align + '"/>';
|
|
@@ -672,11 +715,52 @@ function RTE_Plugin_DocxExport() {
|
|
|
672
715
|
}
|
|
673
716
|
|
|
674
717
|
function list(node, style, level, pendingBreak) {
|
|
718
|
+
// 2026-10-15 a task list: Word has no plain-text checklist, so each item is an indented paragraph that
|
|
719
|
+
// starts with a ballot box, open (U+2610) or ticked (U+2612), as Google Docs exports it. It went out as an
|
|
720
|
+
// ordinary bulleted list and every tick was lost. tools/docx/task-list.mjs
|
|
721
|
+
if (node.classList && node.classList.contains("rte-task-list")) {
|
|
722
|
+
var txml = "";
|
|
723
|
+
for (var ti = 0; ti < node.childNodes.length; ti++) {
|
|
724
|
+
var tli = node.childNodes[ti];
|
|
725
|
+
if (tli.nodeType !== 1 || tli.tagName.toLowerCase() !== "li") continue;
|
|
726
|
+
var town = tli.ownerDocument.createElement("p");
|
|
727
|
+
for (var tk = 0; tk < tli.childNodes.length; tk++) {
|
|
728
|
+
var tch = tli.childNodes[tk];
|
|
729
|
+
if (tch.nodeType === 1 && (/^(ul|ol)$/.test(tch.tagName.toLowerCase()) || (tch.classList && tch.classList.contains("rte-task-checkbox")))) continue;
|
|
730
|
+
town.appendChild(tch.cloneNode(true));
|
|
731
|
+
}
|
|
732
|
+
var ticked = tli.getAttribute("data-checked") === "true";
|
|
733
|
+
town.insertBefore(tli.ownerDocument.createTextNode((ticked ? "\u2612" : "\u2610") + " "), town.firstChild);
|
|
734
|
+
town.style.marginLeft = (24 * (level + 1)) + "px";
|
|
735
|
+
txml += para(town, styleFrom(tli, style), { pageBreakBefore: pendingBreak });
|
|
736
|
+
pendingBreak = false;
|
|
737
|
+
for (var tj = 0; tj < tli.childNodes.length; tj++) {
|
|
738
|
+
var tsub = tli.childNodes[tj];
|
|
739
|
+
if (tsub.nodeType === 1 && /^(ul|ol)$/.test(tsub.tagName.toLowerCase())) txml += list(tsub, style, Math.min(8, level + 1), false);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return txml;
|
|
743
|
+
}
|
|
675
744
|
var ordered = node.tagName.toLowerCase() === "ol";
|
|
676
745
|
// One numId per list, so two adjacent lists restart rather than
|
|
677
746
|
// continuing each other's numbering.
|
|
678
747
|
var numId = ++b.numSeq;
|
|
679
748
|
b.numbering[numId] = ordered ? "decimal" : "bullet";
|
|
749
|
+
// 2026-10-04 an <ol start> starts its level there (it was always 1, so a list continued
|
|
750
|
+
// after a paragraph restarted in Word). tools/docx/ordered-start.mjs
|
|
751
|
+
var startAt = ordered ? parseInt(node.getAttribute("start"), 10) : 1;
|
|
752
|
+
if (isNaN(startAt)) startAt = 1;
|
|
753
|
+
if (startAt !== 1) (b.numStart || (b.numStart = {}))[numId] = { level: level, start: startAt };
|
|
754
|
+
// 2026-10-04 a lettered / Roman list keeps its numbering style in Word (it was always decimal).
|
|
755
|
+
// tools/docx/list-formats.mjs
|
|
756
|
+
if (ordered) {
|
|
757
|
+
var lst = String((node.style && node.style.listStyleType) || "").toLowerCase(), typ = node.getAttribute("type") || "";
|
|
758
|
+
var wf = /^(lower-alpha|lower-latin)$/.test(lst) || typ === "a" ? "lowerLetter"
|
|
759
|
+
: /^(upper-alpha|upper-latin)$/.test(lst) || typ === "A" ? "upperLetter"
|
|
760
|
+
: lst === "lower-roman" || typ === "i" ? "lowerRoman"
|
|
761
|
+
: lst === "upper-roman" || typ === "I" ? "upperRoman" : "";
|
|
762
|
+
if (wf) (b.numFmtAt || (b.numFmtAt = {}))[numId] = { level: level, fmt: wf };
|
|
763
|
+
}
|
|
680
764
|
var xml = "";
|
|
681
765
|
for (var i = 0; i < node.childNodes.length; i++) {
|
|
682
766
|
var li = node.childNodes[i];
|
|
@@ -703,14 +787,43 @@ function RTE_Plugin_DocxExport() {
|
|
|
703
787
|
return xml;
|
|
704
788
|
}
|
|
705
789
|
|
|
790
|
+
// 2026-10-15 the table's width and its column widths: a 30% / 70% layout came back as equal columns and a
|
|
791
|
+
// full-width table as shrink-to-fit. <col> widths (% of a 6.5in text column, or px) become <w:gridCol> twips;
|
|
792
|
+
// a % table width becomes <w:tblW w:type="pct"> (fiftieths of a percent). tools/docx/table-widths.mjs
|
|
793
|
+
var TEXT_TWIPS = 9360;
|
|
794
|
+
function tableGrid(node) {
|
|
795
|
+
var cols = [], kids = node.children;
|
|
796
|
+
for (var i = 0; i < kids.length; i++) if (kids[i].tagName && kids[i].tagName.toLowerCase() === "colgroup") {
|
|
797
|
+
for (var j = 0; j < kids[i].children.length; j++) if (kids[i].children[j].tagName.toLowerCase() === "col") cols.push(kids[i].children[j]);
|
|
798
|
+
}
|
|
799
|
+
if (!cols.length) return "";
|
|
800
|
+
var tw = [];
|
|
801
|
+
for (var k = 0; k < cols.length; k++) {
|
|
802
|
+
var w = (cols[k].style && cols[k].style.width) || cols[k].getAttribute("width") || "", m;
|
|
803
|
+
if ((m = /^\s*([\d.]+)%\s*$/.exec(w))) tw.push(Math.round(parseFloat(m[1]) / 100 * TEXT_TWIPS));
|
|
804
|
+
else if ((m = /^\s*([\d.]+)(px)?\s*$/.exec(w))) tw.push(Math.round(parseFloat(m[1]) * 15));
|
|
805
|
+
else return ""; // one column without a usable width: leave the layout to Word
|
|
806
|
+
}
|
|
807
|
+
return "<w:tblGrid>" + tw.map(function (t) { return '<w:gridCol w:w="' + t + '"/>'; }).join("") + "</w:tblGrid>";
|
|
808
|
+
}
|
|
809
|
+
function tableWidth(node) {
|
|
810
|
+
var m = /^\s*([\d.]+)%\s*$/.exec((node.style && node.style.width) || node.getAttribute("width") || "");
|
|
811
|
+
return m ? '<w:tblW w:w="' + Math.round(parseFloat(m[1]) * 50) + '" w:type="pct"/>' : '<w:tblW w:w="0" w:type="auto"/>';
|
|
812
|
+
}
|
|
706
813
|
function table(node, style) {
|
|
707
|
-
var xml = '<w:tbl><w:tblPr
|
|
814
|
+
var xml = '<w:tbl><w:tblPr>' + tableWidth(node) +
|
|
708
815
|
'<w:tblBorders>' +
|
|
709
816
|
["top", "left", "bottom", "right", "insideH", "insideV"].map(function (s) {
|
|
710
817
|
return '<w:' + s + ' w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/>';
|
|
711
818
|
}).join("") +
|
|
712
|
-
"</w:tblBorders></w:tblPr>";
|
|
819
|
+
"</w:tblBorders></w:tblPr>" + tableGrid(node);
|
|
713
820
|
var trs = node.getElementsByTagName("tr");
|
|
821
|
+
// 2026-10-15 rowspan: Word marks the first cell <w:vMerge w:val="restart"/> and puts an empty <w:vMerge/>
|
|
822
|
+
// continuation cell at the same grid column in every row it covers. It was not written at all, so a
|
|
823
|
+
// merged cell came back split. down[col] = { left: rows still covered, span: its colspan }.
|
|
824
|
+
// tools/docx/merged-cells.mjs
|
|
825
|
+
var down = {};
|
|
826
|
+
function continuation(col) { var d = down[col]; d.left--; var s = d.span; if (!d.left) delete down[col]; return '<w:tc><w:tcPr>' + (s > 1 ? '<w:gridSpan w:val="' + s + '"/>' : '') + '<w:vMerge/></w:tcPr><w:p/></w:tc>'; }
|
|
714
827
|
for (var r = 0; r < trs.length; r++) {
|
|
715
828
|
var cells = [];
|
|
716
829
|
for (var c = 0; c < trs[r].childNodes.length; c++) {
|
|
@@ -724,8 +837,12 @@ function RTE_Plugin_DocxExport() {
|
|
|
724
837
|
// or the continuation arrives as unlabelled numbers.
|
|
725
838
|
var isHeader = cells.length && cells[0].header;
|
|
726
839
|
xml += "<w:tr>" + (isHeader ? "<w:trPr><w:tblHeader/></w:trPr>" : "");
|
|
840
|
+
var gcol = 0;
|
|
727
841
|
for (var k = 0; k < cells.length; k++) {
|
|
842
|
+
while (down[gcol]) { var dspan = down[gcol].span; xml += continuation(gcol); gcol += dspan; }
|
|
728
843
|
var span = parseInt(cells[k].node.getAttribute("colspan") || "1", 10) || 1;
|
|
844
|
+
var rspan = parseInt(cells[k].node.getAttribute("rowspan") || "1", 10) || 1;
|
|
845
|
+
if (rspan > 1) down[gcol] = { left: rspan - 1, span: span };
|
|
729
846
|
var cs = styleFrom(cells[k].node, style);
|
|
730
847
|
if (cells[k].header) cs.bold = true;
|
|
731
848
|
var body = "";
|
|
@@ -738,9 +855,13 @@ function RTE_Plugin_DocxExport() {
|
|
|
738
855
|
if (!body) body = "<w:p/>";
|
|
739
856
|
xml += "<w:tc><w:tcPr>" +
|
|
740
857
|
(span > 1 ? '<w:gridSpan w:val="' + span + '"/>' : "") +
|
|
858
|
+
(rspan > 1 ? '<w:vMerge w:val="restart"/>' : "") +
|
|
741
859
|
(cells[k].header ? '<w:shd w:val="clear" w:color="auto" w:fill="F1F3F7"/>' : "") +
|
|
742
860
|
"</w:tcPr>" + body + "</w:tc>";
|
|
861
|
+
gcol += span;
|
|
743
862
|
}
|
|
863
|
+
// merges from above that reach past this row's last cell
|
|
864
|
+
for (var tail = gcol; tail < gcol + 64; tail++) { if (down[tail]) { var tspan = down[tail].span; xml += continuation(tail); tail += tspan - 1; } }
|
|
744
865
|
xml += "</w:tr>";
|
|
745
866
|
}
|
|
746
867
|
return xml + "</w:tbl><w:p/>";
|
|
@@ -761,11 +882,34 @@ function RTE_Plugin_DocxExport() {
|
|
|
761
882
|
|
|
762
883
|
if (c.getAttribute("data-rte-page-break") !== null || /always|page/.test((c.style && (c.style.pageBreakBefore || c.style.breakBefore)) || "")) {
|
|
763
884
|
pendingBreak = true;
|
|
885
|
+
// 2026-10-15 the editor's marker is only a marker: its label ("Insert Page Break") was written
|
|
886
|
+
// into the Word document as a paragraph of text. tools/docx/page-breaks.mjs
|
|
887
|
+
if (c.getAttribute("data-rte-page-break") !== null) continue;
|
|
764
888
|
}
|
|
765
889
|
|
|
766
890
|
if (tag === "hr") { xml += '<w:p><w:pPr><w:pBdr><w:bottom w:val="single" w:sz="6" w:space="1" w:color="C8CDD4"/></w:pBdr></w:pPr></w:p>'; continue; }
|
|
767
891
|
if (tag === "ul" || tag === "ol") { xml += list(c, style, 0, pendingBreak); pendingBreak = false; continue; }
|
|
768
|
-
|
|
892
|
+
// 2026-10-04 captions are Word captions: a table's above it (it was dropped), an image's in its own
|
|
893
|
+
// paragraph after the picture (it ran on in the picture's). tools/docx/captions.mjs
|
|
894
|
+
if (tag === "table") {
|
|
895
|
+
var tcap = c.caption; // its OWN caption, not a nested table's (2026-10-05 review)
|
|
896
|
+
if (tcap && (tcap.textContent || "").replace(/\s+/g, "")) xml += para(tcap, styleFrom(tcap, style), { caption: true });
|
|
897
|
+
xml += table(c, style); continue;
|
|
898
|
+
}
|
|
899
|
+
var ownFcap = null;
|
|
900
|
+
if (tag === "figure") for (var fci = 0; fci < c.children.length; fci++) if (c.children[fci].tagName.toLowerCase() === "figcaption") { ownFcap = c.children[fci]; break; }
|
|
901
|
+
if (tag === "figure" && ownFcap) {
|
|
902
|
+
var fcap = ownFcap;
|
|
903
|
+
// the caption is taken out for the picture's paragraph and put back (the image export
|
|
904
|
+
// keys on the original <img>, so a clone lost the picture)
|
|
905
|
+
var fcapParent = fcap.parentNode, fcapNext = fcap.nextSibling;
|
|
906
|
+
fcapParent.removeChild(fcap);
|
|
907
|
+
try { xml += para(c, styleFrom(c, style), { pageBreakBefore: pendingBreak }); }
|
|
908
|
+
finally { fcapParent.insertBefore(fcap, fcapNext); }
|
|
909
|
+
pendingBreak = false;
|
|
910
|
+
if ((fcap.textContent || "").replace(/\s+/g, "")) xml += para(fcap, styleFrom(fcap, style), { caption: true });
|
|
911
|
+
continue;
|
|
912
|
+
}
|
|
769
913
|
if (HEADING[tag]) { xml += para(c, styleFrom(c, style), { heading: HEADING[tag], pageBreakBefore: pendingBreak }); pendingBreak = false; continue; }
|
|
770
914
|
if (tag === "blockquote") { xml += para(c, styleFrom(c, style), { quote: true, pageBreakBefore: pendingBreak }); pendingBreak = false; continue; }
|
|
771
915
|
if (tag === "pre") { xml += para(c, styleFrom(c, style), { pre: true, pageBreakBefore: pendingBreak }); pendingBreak = false; continue; }
|
|
@@ -822,16 +966,39 @@ function RTE_Plugin_DocxExport() {
|
|
|
822
966
|
'" w:header="720" w:footer="720" w:gutter="0"/></w:sectPr>';
|
|
823
967
|
}
|
|
824
968
|
|
|
969
|
+
// 2026-10-04 The copy's <img> elements are NEW and have not loaded: exported straight after setHTMLCode()
|
|
970
|
+
// an image without width/height had naturalWidth 0 and was silently dropped. The copy is made first and
|
|
971
|
+
// its images are waited for (load or error, 5 s at most). tools/docx/unsized-image.mjs
|
|
825
972
|
function buildDocx(options) {
|
|
973
|
+
// 2026-10-05 a failure here (getHTMLCode, the copy) rejects the promise instead of throwing (review)
|
|
974
|
+
try { return buildDocxPrepared(options); } catch (e) { return Promise.reject(e); }
|
|
975
|
+
}
|
|
976
|
+
function buildDocxPrepared(options) {
|
|
977
|
+
var host = document.createElement("div");
|
|
978
|
+
// getHTMLCode() is the serialized document: presentational
|
|
979
|
+
// plugins strip their own chrome from it, so page overlays,
|
|
980
|
+
// watermarks and formatting marks never reach the file.
|
|
981
|
+
host.innerHTML = editor.getHTMLCode() || "";
|
|
982
|
+
// Resolve class-based list styling in the editing document, before the
|
|
983
|
+
// export copy leaves the stylesheet's scope. Do not change saved HTML.
|
|
984
|
+
var liveLists = editor.getEditable().querySelectorAll("ol,ul"), exportLists = host.querySelectorAll("ol,ul");
|
|
985
|
+
if (liveLists.length === exportLists.length) for (var li = 0; li < liveLists.length; li++) {
|
|
986
|
+
var listStyle = liveLists[li].ownerDocument.defaultView.getComputedStyle(liveLists[li]).listStyleType;
|
|
987
|
+
if (listStyle) exportLists[li].style.listStyleType = listStyle;
|
|
988
|
+
}
|
|
989
|
+
document.body.appendChild(host);
|
|
990
|
+
host.style.cssText = "position:absolute;left:-99999px;top:0;width:800px;";
|
|
991
|
+
var pending = [].slice.call(host.querySelectorAll("img")).filter(function (im) { return !(im.complete && im.naturalWidth); });
|
|
992
|
+
var ready = !pending.length ? Promise.resolve() : Promise.all(pending.map(function (im) {
|
|
993
|
+
return new Promise(function (done) {
|
|
994
|
+
im.addEventListener("load", done); im.addEventListener("error", done); setTimeout(done, 5000);
|
|
995
|
+
});
|
|
996
|
+
}));
|
|
997
|
+
return ready.then(function () { return buildFromHost(host, options); });
|
|
998
|
+
}
|
|
999
|
+
function buildFromHost(host, options) {
|
|
826
1000
|
return new Promise(function (resolve, reject) {
|
|
827
1001
|
try {
|
|
828
|
-
var host = document.createElement("div");
|
|
829
|
-
// getHTMLCode() is the serialized document: presentational
|
|
830
|
-
// plugins strip their own chrome from it, so page overlays,
|
|
831
|
-
// watermarks and formatting marks never reach the file.
|
|
832
|
-
host.innerHTML = editor.getHTMLCode() || "";
|
|
833
|
-
document.body.appendChild(host);
|
|
834
|
-
host.style.cssText = "position:absolute;left:-99999px;top:0;width:800px;";
|
|
835
1002
|
|
|
836
1003
|
var b = new Builder();
|
|
837
1004
|
var body = blocksXml(host, b);
|
|
@@ -916,7 +1083,11 @@ function RTE_Plugin_DocxExport() {
|
|
|
916
1083
|
}
|
|
917
1084
|
|
|
918
1085
|
zip(files).then(resolve, reject);
|
|
919
|
-
} catch (e) {
|
|
1086
|
+
} catch (e) {
|
|
1087
|
+
// 2026-10-05 the hidden copy never stays in the page (review)
|
|
1088
|
+
if (host && host.parentNode) host.parentNode.removeChild(host);
|
|
1089
|
+
reject(e);
|
|
1090
|
+
}
|
|
920
1091
|
});
|
|
921
1092
|
}
|
|
922
1093
|
|
|
@@ -936,6 +1107,7 @@ function RTE_Plugin_DocxExport() {
|
|
|
936
1107
|
heads +
|
|
937
1108
|
'<w:style w:type="paragraph" w:styleId="Quote"><w:name w:val="Quote"/><w:basedOn w:val="Normal"/><w:rPr><w:i/><w:color w:val="4A5568"/></w:rPr></w:style>' +
|
|
938
1109
|
'<w:style w:type="paragraph" w:styleId="Code"><w:name w:val="Code"/><w:basedOn w:val="Normal"/><w:rPr><w:rFonts w:ascii="Consolas" w:hAnsi="Consolas"/></w:rPr></w:style>' +
|
|
1110
|
+
'<w:style w:type="paragraph" w:styleId="Caption"><w:name w:val="caption"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:rPr><w:i/><w:color w:val="44546A"/><w:sz w:val="18"/><w:szCs w:val="18"/></w:rPr></w:style>' +
|
|
939
1111
|
"</w:styles>";
|
|
940
1112
|
}
|
|
941
1113
|
|
|
@@ -949,8 +1121,8 @@ function RTE_Plugin_DocxExport() {
|
|
|
949
1121
|
// Word distinguishes bullets from numbers ONLY here; the
|
|
950
1122
|
// document body stores every list identically.
|
|
951
1123
|
levels += '<w:lvl w:ilvl="' + lvl + '">' +
|
|
952
|
-
'<w:start w:val="1"/>' +
|
|
953
|
-
'<w:numFmt w:val="' + (fmt === "bullet" ? "bullet" : "decimal") + '"/>' +
|
|
1124
|
+
'<w:start w:val="' + (b.numStart && b.numStart[numId] && b.numStart[numId].level === lvl ? b.numStart[numId].start : 1) + '"/>' +
|
|
1125
|
+
'<w:numFmt w:val="' + (fmt === "bullet" ? "bullet" : (b.numFmtAt && b.numFmtAt[numId] && b.numFmtAt[numId].level === lvl ? b.numFmtAt[numId].fmt : "decimal")) + '"/>' +
|
|
954
1126
|
'<w:lvlText w:val="' + (fmt === "bullet" ? "\uF0B7" : "%" + (lvl + 1) + ".") + '"/>' +
|
|
955
1127
|
'<w:lvlJc w:val="left"/>' +
|
|
956
1128
|
'<w:pPr><w:ind w:left="' + (720 * (lvl + 1)) + '" w:hanging="360"/></w:pPr>' +
|