@richscripts/richtexteditor 2.4.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.
Files changed (184) hide show
  1. package/README.md +360 -0
  2. package/admin/index.d.ts +100 -0
  3. package/admin/index.js +94 -0
  4. package/angular/component.ts +284 -0
  5. package/angular/index.d.ts +80 -0
  6. package/angular/index.ts +24 -0
  7. package/headless/index.d.ts +65 -0
  8. package/headless/index.js +272 -0
  9. package/index.d.ts +1412 -0
  10. package/integrations/shared.d.ts +138 -0
  11. package/integrations/shared.js +5182 -0
  12. package/package.json +130 -0
  13. package/react/index.d.ts +104 -0
  14. package/react/index.js +310 -0
  15. package/richtexteditor/CHANGELOG.md +1876 -0
  16. package/richtexteditor/all_plugins.js +31125 -0
  17. package/richtexteditor/all_plugins.min.js +78 -0
  18. package/richtexteditor/lang/rte-lang-af.js +193 -0
  19. package/richtexteditor/lang/rte-lang-ar.js +193 -0
  20. package/richtexteditor/lang/rte-lang-bg.js +193 -0
  21. package/richtexteditor/lang/rte-lang-bn.js +193 -0
  22. package/richtexteditor/lang/rte-lang-bs.js +193 -0
  23. package/richtexteditor/lang/rte-lang-ca.js +193 -0
  24. package/richtexteditor/lang/rte-lang-cs.js +193 -0
  25. package/richtexteditor/lang/rte-lang-cy.js +193 -0
  26. package/richtexteditor/lang/rte-lang-da.js +193 -0
  27. package/richtexteditor/lang/rte-lang-de.js +193 -0
  28. package/richtexteditor/lang/rte-lang-el.js +193 -0
  29. package/richtexteditor/lang/rte-lang-en.js +6 -0
  30. package/richtexteditor/lang/rte-lang-es.js +193 -0
  31. package/richtexteditor/lang/rte-lang-et.js +193 -0
  32. package/richtexteditor/lang/rte-lang-fa.js +193 -0
  33. package/richtexteditor/lang/rte-lang-fi.js +193 -0
  34. package/richtexteditor/lang/rte-lang-fil.js +193 -0
  35. package/richtexteditor/lang/rte-lang-fj.js +193 -0
  36. package/richtexteditor/lang/rte-lang-fr.js +193 -0
  37. package/richtexteditor/lang/rte-lang-ga.js +193 -0
  38. package/richtexteditor/lang/rte-lang-gu.js +193 -0
  39. package/richtexteditor/lang/rte-lang-he.js +193 -0
  40. package/richtexteditor/lang/rte-lang-hi.js +193 -0
  41. package/richtexteditor/lang/rte-lang-hr.js +193 -0
  42. package/richtexteditor/lang/rte-lang-ht.js +193 -0
  43. package/richtexteditor/lang/rte-lang-hu.js +193 -0
  44. package/richtexteditor/lang/rte-lang-id.js +193 -0
  45. package/richtexteditor/lang/rte-lang-is.js +193 -0
  46. package/richtexteditor/lang/rte-lang-it.js +193 -0
  47. package/richtexteditor/lang/rte-lang-ja.js +193 -0
  48. package/richtexteditor/lang/rte-lang-kn.js +193 -0
  49. package/richtexteditor/lang/rte-lang-ko.js +193 -0
  50. package/richtexteditor/lang/rte-lang-lt.js +193 -0
  51. package/richtexteditor/lang/rte-lang-lv.js +193 -0
  52. package/richtexteditor/lang/rte-lang-mg.js +193 -0
  53. package/richtexteditor/lang/rte-lang-mi.js +193 -0
  54. package/richtexteditor/lang/rte-lang-ml.js +193 -0
  55. package/richtexteditor/lang/rte-lang-mr.js +193 -0
  56. package/richtexteditor/lang/rte-lang-ms.js +193 -0
  57. package/richtexteditor/lang/rte-lang-mt.js +193 -0
  58. package/richtexteditor/lang/rte-lang-mww.js +193 -0
  59. package/richtexteditor/lang/rte-lang-nb.js +193 -0
  60. package/richtexteditor/lang/rte-lang-nl.js +193 -0
  61. package/richtexteditor/lang/rte-lang-otq.js +193 -0
  62. package/richtexteditor/lang/rte-lang-pa.js +193 -0
  63. package/richtexteditor/lang/rte-lang-pl.js +193 -0
  64. package/richtexteditor/lang/rte-lang-pt-pt.js +193 -0
  65. package/richtexteditor/lang/rte-lang-pt.js +193 -0
  66. package/richtexteditor/lang/rte-lang-ro.js +193 -0
  67. package/richtexteditor/lang/rte-lang-ru.js +193 -0
  68. package/richtexteditor/lang/rte-lang-sk.js +193 -0
  69. package/richtexteditor/lang/rte-lang-sl.js +193 -0
  70. package/richtexteditor/lang/rte-lang-sm.js +193 -0
  71. package/richtexteditor/lang/rte-lang-sr-Cyrl.js +193 -0
  72. package/richtexteditor/lang/rte-lang-sr-Latn.js +193 -0
  73. package/richtexteditor/lang/rte-lang-sv.js +193 -0
  74. package/richtexteditor/lang/rte-lang-sw.js +193 -0
  75. package/richtexteditor/lang/rte-lang-ta.js +193 -0
  76. package/richtexteditor/lang/rte-lang-te.js +193 -0
  77. package/richtexteditor/lang/rte-lang-th.js +193 -0
  78. package/richtexteditor/lang/rte-lang-tlh-Latn.js +193 -0
  79. package/richtexteditor/lang/rte-lang-tlh-Piqd.js +193 -0
  80. package/richtexteditor/lang/rte-lang-to.js +193 -0
  81. package/richtexteditor/lang/rte-lang-tr.js +193 -0
  82. package/richtexteditor/lang/rte-lang-ty.js +193 -0
  83. package/richtexteditor/lang/rte-lang-uk.js +193 -0
  84. package/richtexteditor/lang/rte-lang-ur.js +193 -0
  85. package/richtexteditor/lang/rte-lang-vi.js +193 -0
  86. package/richtexteditor/lang/rte-lang-yua.js +193 -0
  87. package/richtexteditor/lang/rte-lang-zh-Hans.js +193 -0
  88. package/richtexteditor/lang/rte-lang-zh-Hant.js +193 -0
  89. package/richtexteditor/lang/rte-lang.js +1 -0
  90. package/richtexteditor/plugins/-combine-plugin.txt +2 -0
  91. package/richtexteditor/plugins/-combine-plugins.bat +20 -0
  92. package/richtexteditor/plugins/a11yenhance.js +90 -0
  93. package/richtexteditor/plugins/accessibilitychecker.js +579 -0
  94. package/richtexteditor/plugins/aitoolkit.css +15830 -0
  95. package/richtexteditor/plugins/aitoolkit.js +19171 -0
  96. package/richtexteditor/plugins/all_plugins.js +31125 -0
  97. package/richtexteditor/plugins/all_plugins.min.js +78 -0
  98. package/richtexteditor/plugins/autoembed.js +174 -0
  99. package/richtexteditor/plugins/blocktypes.js +175 -0
  100. package/richtexteditor/plugins/bookmarkcard.js +226 -0
  101. package/richtexteditor/plugins/charlimit.js +195 -0
  102. package/richtexteditor/plugins/comments.js +672 -0
  103. package/richtexteditor/plugins/contentminimap.js +369 -0
  104. package/richtexteditor/plugins/crdt-engine.js +8905 -0
  105. package/richtexteditor/plugins/crdt-engine.min.js +5 -0
  106. package/richtexteditor/plugins/dialoga11y.js +174 -0
  107. package/richtexteditor/plugins/dictation.js +268 -0
  108. package/richtexteditor/plugins/documentimport.js +369 -0
  109. package/richtexteditor/plugins/documentoutline.js +341 -0
  110. package/richtexteditor/plugins/emailtoolkit.js +165 -0
  111. package/richtexteditor/plugins/emojiautocomplete.js +241 -0
  112. package/richtexteditor/plugins/foldheadings.js +181 -0
  113. package/richtexteditor/plugins/ghostcomplete.js +297 -0
  114. package/richtexteditor/plugins/html2pdf.js +158 -0
  115. package/richtexteditor/plugins/imageeditor.js +159 -0
  116. package/richtexteditor/plugins/insertcode.js +319 -0
  117. package/richtexteditor/plugins/insertemoji.js +229 -0
  118. package/richtexteditor/plugins/insertgallery.js +362 -0
  119. package/richtexteditor/plugins/inserttemplate.js +261 -0
  120. package/richtexteditor/plugins/localdraft.js +213 -0
  121. package/richtexteditor/plugins/markdownexport.js +110 -0
  122. package/richtexteditor/plugins/mathdialog.js +153 -0
  123. package/richtexteditor/plugins/mentionplugin.js +534 -0
  124. package/richtexteditor/plugins/mermaiddiagram.js +294 -0
  125. package/richtexteditor/plugins/readabilitystats.js +148 -0
  126. package/richtexteditor/plugins/readaloud.js +243 -0
  127. package/richtexteditor/plugins/restrictedediting.js +208 -0
  128. package/richtexteditor/plugins/revisionhistory.js +670 -0
  129. package/richtexteditor/plugins/samples/insertcode_v1.js +76 -0
  130. package/richtexteditor/plugins/slashcommand.js +705 -0
  131. package/richtexteditor/plugins/smartchips.js +250 -0
  132. package/richtexteditor/plugins/spellcheck.js +181 -0
  133. package/richtexteditor/plugins/todolist.js +137 -0
  134. package/richtexteditor/plugins/trackedchanges.js +658 -0
  135. package/richtexteditor/plugins/tui.image-editor/fabric.min.js +8 -0
  136. package/richtexteditor/plugins/tui.image-editor/note.txt +5 -0
  137. package/richtexteditor/plugins/tui.image-editor/svg/icon-a.svg +235 -0
  138. package/richtexteditor/plugins/tui.image-editor/svg/icon-b.svg +224 -0
  139. package/richtexteditor/plugins/tui.image-editor/svg/icon-c.svg +224 -0
  140. package/richtexteditor/plugins/tui.image-editor/svg/icon-d.svg +224 -0
  141. package/richtexteditor/plugins/tui.image-editor/tui-code-snippet.min.js +7 -0
  142. package/richtexteditor/plugins/tui.image-editor/tui-color-picker.min.css +6 -0
  143. package/richtexteditor/plugins/tui.image-editor/tui-color-picker.min.js +7 -0
  144. package/richtexteditor/plugins/tui.image-editor/tui-image-editor.min.css +7 -0
  145. package/richtexteditor/plugins/tui.image-editor/tui-image-editor.min.js +15 -0
  146. package/richtexteditor/plugins/typewriter.js +203 -0
  147. package/richtexteditor/plugins/wordexport.js +0 -0
  148. package/richtexteditor/plugins/yjscollab.js +693 -0
  149. package/richtexteditor/plugins/zz_richtextbox_dialog_style.js +335 -0
  150. package/richtexteditor/rte-config.js +933 -0
  151. package/richtexteditor/rte.js +943 -0
  152. package/richtexteditor/rte_mobile.css +234 -0
  153. package/richtexteditor/rte_theme_default.css +4819 -0
  154. package/richtexteditor/runtime/colorpicker_more_ns.htm +2613 -0
  155. package/richtexteditor/runtime/help.htm +162 -0
  156. package/richtexteditor/runtime/images/1x1.gif +0 -0
  157. package/richtexteditor/runtime/images/cpie_Color.cur +0 -0
  158. package/richtexteditor/runtime/images/cpie_GradientPositionDark.gif +0 -0
  159. package/richtexteditor/runtime/images/cpie_GradientPositionLight.gif +0 -0
  160. package/richtexteditor/runtime/images/cpie_VerticalPosition.gif +0 -0
  161. package/richtexteditor/runtime/images/cpie_WebSafe.gif +0 -0
  162. package/richtexteditor/runtime/images/cpie_gradients.png +0 -0
  163. package/richtexteditor/runtime/images/cpns_Color.cur +0 -0
  164. package/richtexteditor/runtime/images/cpns_ColorSpace1.png +0 -0
  165. package/richtexteditor/runtime/images/cpns_ColorSpace2.png +0 -0
  166. package/richtexteditor/runtime/images/cpns_GradientPositionDark.gif +0 -0
  167. package/richtexteditor/runtime/images/cpns_GradientPositionLight.gif +0 -0
  168. package/richtexteditor/runtime/images/cpns_Vertical1.png +0 -0
  169. package/richtexteditor/runtime/images/cpns_Vertical2.png +0 -0
  170. package/richtexteditor/runtime/images/cpns_VerticalPosition.gif +0 -0
  171. package/richtexteditor/runtime/images/cpns_WebSafe.gif +0 -0
  172. package/richtexteditor/runtime/images/cpns_gradients.png +0 -0
  173. package/richtexteditor/runtime/images/cpns_hue2.png +0 -0
  174. package/richtexteditor/runtime/images/formbn.gif +0 -0
  175. package/richtexteditor/runtime/images/multiclavier.gif +0 -0
  176. package/richtexteditor/runtime/richtexteditor_content.css +362 -0
  177. package/richtexteditor/runtime/richtexteditor_preview.css +302 -0
  178. package/richtexteditor/runtime/richtexteditor_preview.js +1 -0
  179. package/server/index.d.ts +21 -0
  180. package/server/index.js +23 -0
  181. package/svelte/index.d.ts +19 -0
  182. package/svelte/index.js +59 -0
  183. package/vue/index.d.ts +94 -0
  184. package/vue/index.js +291 -0
@@ -0,0 +1,579 @@
1
+ if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
2
+
3
+ RTE_DefaultConfig.plugin_accessibilitychecker = RTE_Plugin_AccessibilityChecker;
4
+
5
+ function RTE_Plugin_AccessibilityChecker() {
6
+ var obj = this;
7
+ var config;
8
+ var editor;
9
+ var shell = null;
10
+ var panel = null;
11
+ var list = null;
12
+ var empty = null;
13
+ var detail = null;
14
+ var refreshTimer = 0;
15
+ var lastResult = null;
16
+ var selectedIssueIndex = -1;
17
+
18
+ obj.PluginName = "AccessibilityChecker";
19
+
20
+ obj.InitConfig = function (argconfig) {
21
+ config = argconfig;
22
+ if (config.accessibilityCheckerEnabled === false) return;
23
+
24
+ if (typeof config.accessibilityCheckerAutoOpen !== "boolean") config.accessibilityCheckerAutoOpen = false;
25
+ config.accessibilityCheckerTitle = config.accessibilityCheckerTitle || "Accessibility";
26
+ config.accessibilityCheckerHint = config.accessibilityCheckerHint || "Review heading structure, image alt text, and table headers without leaving the editor.";
27
+ config.accessibilityCheckerEmptyText = config.accessibilityCheckerEmptyText || "No accessibility issues found in the current document.";
28
+
29
+ appendToolbarCommand("toolbar_default", "#{accessibilitychecker}");
30
+ appendToolbarCommand("toolbar_full", "#{accessibilitychecker}");
31
+ };
32
+
33
+ obj.InitEditor = function (argeditor) {
34
+ editor = argeditor;
35
+ if (config.accessibilityCheckerEnabled === false) return;
36
+
37
+ editor.accessibilityChecker = {
38
+ close: function () { closePanel(); },
39
+ getIssues: function () { return lastResult ? lastResult.issues.slice() : []; },
40
+ open: function () { openPanel(); },
41
+ refresh: function () { return runAudit(); },
42
+ repair: function (issueIndex, options) { return repairIssue(issueIndex, options); },
43
+ run: function () { return runAudit(); },
44
+ toggle: function () { togglePanel(); }
45
+ };
46
+
47
+ injectStyles();
48
+
49
+ editor.toolbarFactoryMap = editor.toolbarFactoryMap || {};
50
+ editor.toolbarFactoryMap["accessibilitychecker"] = function (cmd) {
51
+ return editor.createToolbarButton(cmd);
52
+ };
53
+
54
+ editor.attachEvent("exec_command_accessibilitychecker", function (state) {
55
+ state.returnValue = true;
56
+ state.stopBubble = true;
57
+ togglePanel();
58
+ });
59
+ editor.attachEvent("change", function () {
60
+ scheduleRefresh();
61
+ });
62
+
63
+ ensureShell();
64
+ runAudit();
65
+ if (config.accessibilityCheckerAutoOpen) openPanel();
66
+ };
67
+
68
+ function appendToolbarCommand(toolbar, item) {
69
+ if (!config[toolbar]) return;
70
+ if (config[toolbar].indexOf(item) !== -1) return;
71
+ config[toolbar] = config[toolbar] + item;
72
+ }
73
+
74
+ function injectStyles() {
75
+ var hostDoc = config.container.ownerDocument;
76
+ if (hostDoc.getElementById("rte-accessibility-checker-style")) return;
77
+ var style = hostDoc.createElement("style");
78
+ style.id = "rte-accessibility-checker-style";
79
+ style.innerHTML = [
80
+ ".rte-a11y-shell{display:flex;align-items:stretch;gap:10px;}",
81
+ ".rte-a11y-shell>.rte-a11y-host{flex:1 1 auto;min-width:0;}",
82
+ ".rte-a11y-panel{display:none;flex:0 0 310px;min-width:270px;max-width:min(360px,32vw);border:1px solid rgba(148,163,184,.22);border-radius:16px;background:linear-gradient(180deg,rgba(255,255,255,.98),rgba(248,251,255,.96));box-shadow:0 18px 42px rgba(29,78,216,.12),0 2px 8px rgba(15,23,42,.06);overflow:hidden;color:#172033;font-family:Aptos,'Segoe UI',sans-serif;}",
83
+ ".rte-a11y-shell.is-open>.rte-a11y-panel{display:flex;flex-direction:column;}",
84
+ ".rte-a11y-header{padding:12px 12px 9px 14px;border-bottom:1px solid rgba(148,163,184,.16);background:rgba(255,255,255,.72);}",
85
+ ".rte-a11y-kicker{font-size:10px;line-height:1.3;letter-spacing:.08em;text-transform:uppercase;color:#52657e;font-weight:850;}",
86
+ ".rte-a11y-title{margin-top:3px;font-size:15px;line-height:1.2;font-weight:850;color:#172033;}",
87
+ ".rte-a11y-copy{margin-top:5px;font-size:12px;line-height:1.42;color:#52657e;}",
88
+ ".rte-a11y-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 10px 8px 14px;border-bottom:1px solid rgba(148,163,184,.16);gap:10px;background:rgba(255,255,255,.52);}",
89
+ ".rte-a11y-count{min-width:0;font-size:12px;font-weight:750;color:#52657e;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}",
90
+ ".rte-a11y-actions{display:flex;align-items:center;gap:6px;}",
91
+ ".rte-a11y-link{appearance:none;border:1px solid rgba(100,116,139,.18);background:#fff;color:#315277;cursor:pointer;font-size:12px;font-weight:750;padding:6px 9px;border-radius:999px;line-height:1;}",
92
+ ".rte-a11y-link:hover,.rte-a11y-link:focus-visible{background:#eef4ff;color:#0f3f9f;border-color:rgba(37,99,235,.28);}",
93
+ ".rte-a11y-body{padding:6px;overflow:auto;min-height:160px;max-height:560px;display:flex;flex-direction:column;gap:8px;scrollbar-width:thin;}",
94
+ ".rte-a11y-list{display:flex;flex-direction:column;gap:6px;}",
95
+ ".rte-a11y-item{appearance:none;width:100%;text-align:left;border:1px solid rgba(148,163,184,.16);background:rgba(255,255,255,.84);cursor:pointer;border-radius:14px;padding:10px;box-shadow:0 8px 18px rgba(15,23,42,.04);transition:background 160ms ease,box-shadow 160ms ease,transform 160ms ease;}",
96
+ ".rte-a11y-item:hover,.rte-a11y-item:focus-visible{background:#f8fbff;border-color:rgba(37,99,235,.24);}",
97
+ ".rte-a11y-item.is-active{border-color:rgba(37,99,235,.36);background:#eef4ff;box-shadow:0 12px 28px rgba(37,99,235,.14);transform:translateY(-1px);}",
98
+ ".rte-a11y-item-top{display:flex;align-items:center;justify-content:space-between;gap:10px;}",
99
+ ".rte-a11y-badge{display:inline-flex;align-items:center;border-radius:999px;padding:4px 8px;font-size:10px;line-height:1;font-weight:850;letter-spacing:.08em;text-transform:uppercase;}",
100
+ ".rte-a11y-badge-warning{background:#fff8e8;color:#92400e;border:1px solid rgba(245,158,11,.18);}",
101
+ ".rte-a11y-badge-error{background:#fff1f2;color:#9f1239;border:1px solid rgba(159,18,57,.18);}",
102
+ ".rte-a11y-code{font-size:11px;color:#64748b;font-family:Consolas,'Cascadia Mono',monospace;}",
103
+ ".rte-a11y-message{margin-top:7px;font-size:13px;line-height:1.42;color:#172033;}",
104
+ ".rte-a11y-detail{border:1px solid rgba(148,163,184,.16);background:rgba(255,255,255,.86);border-radius:14px;padding:11px;display:flex;flex-direction:column;gap:9px;box-shadow:0 8px 18px rgba(15,23,42,.04);}",
105
+ ".rte-a11y-detail-title{font-size:13px;font-weight:850;color:#172033;}",
106
+ ".rte-a11y-detail-copy{font-size:12px;line-height:1.45;color:#52657e;}",
107
+ ".rte-a11y-field{display:flex;flex-direction:column;gap:6px;}",
108
+ ".rte-a11y-label{font-size:10px;line-height:1.3;letter-spacing:.08em;text-transform:uppercase;color:#52657e;font-weight:850;}",
109
+ ".rte-a11y-input{width:100%;border:1px solid rgba(148,163,184,.24);border-radius:12px;padding:9px 10px;font-size:13px;line-height:1.4;box-sizing:border-box;background:#fff;}",
110
+ ".rte-a11y-input:focus{outline:2px solid rgba(37,99,235,.18);border-color:rgba(37,99,235,.38);}",
111
+ ".rte-a11y-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}",
112
+ ".rte-a11y-button{appearance:none;border:1px solid #1d67ba;border-radius:999px;background:#1d67ba;color:#fff;padding:8px 12px;font-size:12px;font-weight:750;cursor:pointer;box-shadow:0 8px 16px rgba(29,103,186,.18);}",
113
+ ".rte-a11y-button-secondary{background:#fff;color:#315277;border-color:rgba(100,116,139,.18);box-shadow:none;}",
114
+ ".rte-a11y-button:hover,.rte-a11y-button:focus-visible{transform:translateY(-1px);}",
115
+ ".rte-a11y-empty{padding:14px;border-radius:14px;background:#fff;color:#52657e;font-size:13px;font-weight:700;line-height:1.55;border:1px dashed rgba(148,163,184,.34);}",
116
+ "@media (max-width: 1420px){.rte-a11y-shell{display:block;}.rte-a11y-panel{margin-top:12px;max-width:none;width:100%;}.rte-a11y-body{max-height:360px;}}"
117
+ ].join("");
118
+ hostDoc.head.appendChild(style);
119
+ }
120
+
121
+ function ensureShell() {
122
+ if (shell) return shell;
123
+ var container = config.container;
124
+ var hostDoc = container.ownerDocument;
125
+ shell = hostDoc.createElement("div");
126
+ shell.className = "rte-a11y-shell";
127
+
128
+ var host = hostDoc.createElement("div");
129
+ host.className = "rte-a11y-host";
130
+
131
+ var parent = container.parentNode;
132
+ parent.insertBefore(shell, container);
133
+ shell.appendChild(host);
134
+ host.appendChild(container);
135
+
136
+ panel = hostDoc.createElement("aside");
137
+ panel.className = "rte-a11y-panel";
138
+ panel.setAttribute("aria-label", config.accessibilityCheckerTitle);
139
+ panel.setAttribute("role", "complementary");
140
+
141
+ var header = hostDoc.createElement("div");
142
+ header.className = "rte-a11y-header";
143
+ header.innerHTML = '<div class="rte-a11y-kicker">Accessibility</div><div class="rte-a11y-title"></div><div class="rte-a11y-copy"></div>';
144
+ header.querySelector(".rte-a11y-title").innerText = config.accessibilityCheckerTitle;
145
+ header.querySelector(".rte-a11y-copy").innerText = config.accessibilityCheckerHint;
146
+
147
+ var toolbar = hostDoc.createElement("div");
148
+ toolbar.className = "rte-a11y-toolbar";
149
+ toolbar.innerHTML = '<div class="rte-a11y-count" data-rte-a11y-count="1"></div><div class="rte-a11y-actions"><button type="button" class="rte-a11y-link" data-rte-a11y-refresh="1">Refresh</button><button type="button" class="rte-a11y-link" data-rte-a11y-close="1" aria-label="Hide accessibility checker">Hide</button></div>';
150
+ toolbar.querySelector("[data-rte-a11y-refresh]").onclick = function () { runAudit(); };
151
+ toolbar.querySelector("[data-rte-a11y-close]").onclick = function () { closePanel(); };
152
+
153
+ var body = hostDoc.createElement("div");
154
+ body.className = "rte-a11y-body";
155
+ list = hostDoc.createElement("div");
156
+ list.className = "rte-a11y-list";
157
+ empty = hostDoc.createElement("div");
158
+ empty.className = "rte-a11y-empty";
159
+ empty.innerText = config.accessibilityCheckerEmptyText;
160
+ detail = hostDoc.createElement("div");
161
+ detail.className = "rte-a11y-detail";
162
+ body.appendChild(list);
163
+ body.appendChild(empty);
164
+ body.appendChild(detail);
165
+
166
+ panel.appendChild(header);
167
+ panel.appendChild(toolbar);
168
+ panel.appendChild(body);
169
+ shell.appendChild(panel);
170
+ return shell;
171
+ }
172
+
173
+ function togglePanel() {
174
+ if (shell && shell.classList.contains("is-open")) closePanel();
175
+ else openPanel();
176
+ }
177
+
178
+ function openPanel() {
179
+ ensureShell();
180
+ shell.classList.add("is-open");
181
+ renderPanel();
182
+ notifyResize();
183
+ }
184
+
185
+ function closePanel() {
186
+ if (!shell) return;
187
+ shell.classList.remove("is-open");
188
+ notifyResize();
189
+ }
190
+
191
+ // Opening / closing the panel changes the editor's available width. Editors
192
+ // that size their toolbar / editable on a width recompute (responsive wrap,
193
+ // sticky-toolbar geometry) need a nudge to re-lay-out for the new width —
194
+ // otherwise a fixed-width or sticky toolbar can appear stale or doubled.
195
+ // A resize notification is a harmless no-op when the editor is already fluid.
196
+ function notifyResize() {
197
+ var fire = function () {
198
+ try { if (editor && typeof editor.fireEvent === "function") editor.fireEvent("resize"); } catch (e) {}
199
+ try { if (editor && typeof editor.updateLayout === "function") editor.updateLayout(); } catch (e) {}
200
+ try {
201
+ var hostDoc = config.container.ownerDocument;
202
+ var win = hostDoc.defaultView || window;
203
+ win.dispatchEvent(new win.Event("resize"));
204
+ } catch (e) {}
205
+ };
206
+ fire();
207
+ var raf = (typeof requestAnimationFrame === "function") ? requestAnimationFrame : function (f) { return setTimeout(f, 16); };
208
+ raf(fire);
209
+ }
210
+
211
+ function scheduleRefresh() {
212
+ clearTimeout(refreshTimer);
213
+ refreshTimer = setTimeout(function () {
214
+ runAudit();
215
+ }, 120);
216
+ }
217
+
218
+ function runAudit() {
219
+ ensureShell();
220
+ var ctor = window.RichTextEditor;
221
+ var documentModel = editor.getJSON ? editor.getJSON() : null;
222
+ lastResult = ctor && typeof ctor.auditAccessibility === "function"
223
+ ? ctor.auditAccessibility(documentModel)
224
+ : auditDomAccessibility();
225
+ if (!lastResult.issues.length) selectedIssueIndex = -1;
226
+ else if (selectedIssueIndex < 0 || selectedIssueIndex >= lastResult.issues.length) selectedIssueIndex = 0;
227
+ renderPanel();
228
+ return lastResult;
229
+ }
230
+
231
+ function repairIssue(issueIndex, options) {
232
+ if (!lastResult || !lastResult.issues || !lastResult.issues[issueIndex]) return runAudit();
233
+ var ctor = window.RichTextEditor;
234
+ if (!ctor || typeof ctor.repairAccessibilityIssue !== "function") return repairDomIssue(lastResult.issues[issueIndex], options || {});
235
+ var nextDocument = ctor.repairAccessibilityIssue(editor.getJSON(), lastResult.issues[issueIndex], options || {});
236
+ editor.setJSON(nextDocument);
237
+ selectedIssueIndex = issueIndex;
238
+ return runAudit();
239
+ }
240
+
241
+ function focusIssue(issue) {
242
+ if (!issue) return;
243
+ if (issue._target && typeof issue._target.scrollIntoView === "function") {
244
+ issue._target.scrollIntoView({ behavior: "smooth", block: "center" });
245
+ editor.focus();
246
+ return;
247
+ }
248
+ var editable = editor.getEditable ? editor.getEditable() : null;
249
+ if (!editable) return;
250
+ var match = /^content\[(\d+)\]/.exec(issue.path || "");
251
+ if (!match) return;
252
+ var targetIndex = parseInt(match[1], 10);
253
+ var nodes = [];
254
+ for (var index = 0; index < editable.childNodes.length; index++) {
255
+ if (editable.childNodes[index] && editable.childNodes[index].nodeType === 1) {
256
+ nodes.push(editable.childNodes[index]);
257
+ }
258
+ }
259
+ var target = nodes[targetIndex];
260
+ if (target && typeof target.scrollIntoView === "function") {
261
+ target.scrollIntoView({ behavior: "smooth", block: "center" });
262
+ }
263
+ editor.focus();
264
+ }
265
+
266
+ function auditDomAccessibility() {
267
+ var editable = editor.getEditable ? editor.getEditable() : null;
268
+ var issues = [];
269
+ if (!editable) return { document: null, issues: issues, valid: true, source: "dom" };
270
+
271
+ var blocks = [];
272
+ for (var blockIndex = 0; blockIndex < editable.childNodes.length; blockIndex++) {
273
+ var block = editable.childNodes[blockIndex];
274
+ if (!block || block.nodeType !== 1) continue;
275
+ blocks.push(block);
276
+ }
277
+
278
+ var previousHeadingLevel = 0;
279
+ for (var index = 0; index < blocks.length; index++) {
280
+ var node = blocks[index];
281
+ var tag = String(node.nodeName || "").toLowerCase();
282
+ var path = "content[" + index + "]";
283
+
284
+ if (/^h[1-6]$/.test(tag)) {
285
+ var level = parseInt(tag.substring(1), 10);
286
+ var headingText = getText(node);
287
+ if (!headingText) {
288
+ issues.push({
289
+ code: "heading-empty",
290
+ severity: "warning",
291
+ message: "Heading is empty. Add a concise label or remove the heading.",
292
+ path: path,
293
+ _target: node
294
+ });
295
+ }
296
+ if (previousHeadingLevel && level > previousHeadingLevel + 1) {
297
+ issues.push({
298
+ code: "heading-level-skip",
299
+ severity: "warning",
300
+ message: "Heading jumps from H" + previousHeadingLevel + " to H" + level + ". Use the next heading level for a clearer outline.",
301
+ path: path + ".attrs.level",
302
+ _target: node
303
+ });
304
+ }
305
+ if (headingText) previousHeadingLevel = level;
306
+ }
307
+
308
+ var images = node.querySelectorAll ? node.querySelectorAll("img") : [];
309
+ for (var imageIndex = 0; imageIndex < images.length; imageIndex++) {
310
+ var image = images[imageIndex];
311
+ if (!String(image.getAttribute("alt") || "").replace(/^\s+|\s+$/g, "")) {
312
+ issues.push({
313
+ code: "image-missing-alt",
314
+ severity: "error",
315
+ message: "Image is missing alt text. Describe the image or mark it decorative in your content workflow.",
316
+ path: path + ".image[" + imageIndex + "]",
317
+ _target: image
318
+ });
319
+ }
320
+ }
321
+
322
+ var tables = tag === "table" ? [node] : (node.querySelectorAll ? node.querySelectorAll("table") : []);
323
+ for (var tableIndex = 0; tableIndex < tables.length; tableIndex++) {
324
+ var table = tables[tableIndex];
325
+ if (!table.querySelector("th")) {
326
+ issues.push({
327
+ code: "table-missing-header",
328
+ severity: "warning",
329
+ message: "Table has no header cells. Promote the first row to headers when it describes the columns.",
330
+ path: path + ".table[" + tableIndex + "]",
331
+ _target: table
332
+ });
333
+ }
334
+ }
335
+ }
336
+
337
+ return { document: null, issues: issues, valid: !issues.length, source: "dom" };
338
+ }
339
+
340
+ function repairDomIssue(issue, options) {
341
+ if (!issue || !issue._target) return runAudit();
342
+ var target = issue._target;
343
+
344
+ if (issue.code === "image-missing-alt") {
345
+ target.setAttribute("alt", String(options.altText || "").replace(/^\s+|\s+$/g, ""));
346
+ }
347
+ else if (issue.code === "heading-empty") {
348
+ target.textContent = String(options.headingText || "").replace(/^\s+|\s+$/g, "");
349
+ }
350
+ else if (issue.code === "heading-level-skip") {
351
+ var level = Math.max(1, Math.min(6, parseInt(options.targetLevel, 10) || 2));
352
+ var replacement = target.ownerDocument.createElement("h" + level);
353
+ while (target.firstChild) replacement.appendChild(target.firstChild);
354
+ copyAttributes(target, replacement);
355
+ target.parentNode.replaceChild(replacement, target);
356
+ }
357
+ else if (issue.code === "table-missing-header") {
358
+ promoteFirstTableRow(target);
359
+ }
360
+
361
+ selectedIssueIndex = 0;
362
+ scheduleEditorChange();
363
+ return runAudit();
364
+ }
365
+
366
+ function promoteFirstTableRow(table) {
367
+ var firstRow = table && table.rows && table.rows.length ? table.rows[0] : null;
368
+ if (!firstRow) return;
369
+ var doc = table.ownerDocument;
370
+ for (var index = 0; index < firstRow.cells.length; index++) {
371
+ var cell = firstRow.cells[index];
372
+ if (!cell || String(cell.nodeName || "").toLowerCase() === "th") continue;
373
+ var header = doc.createElement("th");
374
+ while (cell.firstChild) header.appendChild(cell.firstChild);
375
+ copyAttributes(cell, header);
376
+ header.setAttribute("scope", "col");
377
+ firstRow.replaceChild(header, cell);
378
+ }
379
+ }
380
+
381
+ function copyAttributes(source, target) {
382
+ if (!source || !target || !source.attributes) return;
383
+ for (var index = 0; index < source.attributes.length; index++) {
384
+ var attr = source.attributes[index];
385
+ if (!attr || !attr.name) continue;
386
+ target.setAttribute(attr.name, attr.value);
387
+ }
388
+ }
389
+
390
+ function scheduleEditorChange() {
391
+ try { if (editor && typeof editor.fireEvent === "function") editor.fireEvent("change"); } catch (e) {}
392
+ try { if (editor && typeof editor.fireEvent === "function") editor.fireEvent("contentchange"); } catch (e) {}
393
+ }
394
+
395
+ function getText(node) {
396
+ return String((node && (node.innerText || node.textContent)) || "").replace(/\s+/g, " ").replace(/^\s+|\s+$/g, "");
397
+ }
398
+
399
+ function renderPanel() {
400
+ ensureShell();
401
+ var issues = lastResult && lastResult.issues ? lastResult.issues : [];
402
+ while (list.firstChild) list.removeChild(list.firstChild);
403
+
404
+ var count = panel.querySelector("[data-rte-a11y-count]");
405
+ if (count) {
406
+ count.innerText = issues.length
407
+ ? (issues.length + " issue" + (issues.length === 1 ? "" : "s") + " to review")
408
+ : "Ready to publish";
409
+ }
410
+
411
+ empty.style.display = issues.length ? "none" : "block";
412
+
413
+ for (var index = 0; index < issues.length; index++) {
414
+ (function (issue, issueIndex) {
415
+ var button = panel.ownerDocument.createElement("button");
416
+ button.type = "button";
417
+ button.className = "rte-a11y-item" + (issueIndex === selectedIssueIndex ? " is-active" : "");
418
+ button.setAttribute("aria-selected", issueIndex === selectedIssueIndex ? "true" : "false");
419
+ button.innerHTML =
420
+ '<div class="rte-a11y-item-top">' +
421
+ '<span class="rte-a11y-badge rte-a11y-badge-' + issue.severity + '">' + issue.severity + '</span>' +
422
+ '<span class="rte-a11y-code">' + issue.code + '</span>' +
423
+ "</div>" +
424
+ '<div class="rte-a11y-message"></div>';
425
+ button.querySelector(".rte-a11y-message").innerText = issue.message;
426
+ button.onclick = function () {
427
+ selectedIssueIndex = issueIndex;
428
+ focusIssue(issue);
429
+ renderPanel();
430
+ };
431
+ list.appendChild(button);
432
+ })(issues[index], index);
433
+ }
434
+
435
+ renderDetail();
436
+ }
437
+
438
+ function renderDetail() {
439
+ while (detail.firstChild) detail.removeChild(detail.firstChild);
440
+
441
+ var issues = lastResult && lastResult.issues ? lastResult.issues : [];
442
+ if (!issues.length || selectedIssueIndex < 0 || !issues[selectedIssueIndex]) {
443
+ detail.innerHTML = '<div class="rte-a11y-detail-title">No fixes pending</div><div class="rte-a11y-detail-copy">Run the checker again after major content changes to keep headings, image descriptions, and tables in shape.</div>';
444
+ return;
445
+ }
446
+
447
+ var issue = issues[selectedIssueIndex];
448
+ var title = detail.ownerDocument.createElement("div");
449
+ title.className = "rte-a11y-detail-title";
450
+ title.innerText = issue.code;
451
+ var copy = detail.ownerDocument.createElement("div");
452
+ copy.className = "rte-a11y-detail-copy";
453
+ copy.innerText = issue.message;
454
+ detail.appendChild(title);
455
+ detail.appendChild(copy);
456
+
457
+ if (issue.code === "image-missing-alt") {
458
+ renderTextRepair("Alt text", "Describe the image for screen-reader users.", function (value) {
459
+ repairIssue(selectedIssueIndex, { altText: value });
460
+ });
461
+ return;
462
+ }
463
+
464
+ if (issue.code === "heading-empty") {
465
+ renderTextRepair("Heading text", "Add a concise heading label before publishing.", function (value) {
466
+ repairIssue(selectedIssueIndex, { headingText: value });
467
+ });
468
+ return;
469
+ }
470
+
471
+ if (issue.code === "heading-level-skip") {
472
+ var suggestedLevel = suggestHeadingLevel(issue);
473
+ var row = detail.ownerDocument.createElement("div");
474
+ row.className = "rte-a11y-row";
475
+ var normalize = detail.ownerDocument.createElement("button");
476
+ normalize.type = "button";
477
+ normalize.className = "rte-a11y-button";
478
+ normalize.innerText = "Normalize to H" + suggestedLevel;
479
+ normalize.onclick = function () {
480
+ repairIssue(selectedIssueIndex, { targetLevel: suggestedLevel });
481
+ };
482
+ var focus = detail.ownerDocument.createElement("button");
483
+ focus.type = "button";
484
+ focus.className = "rte-a11y-button rte-a11y-button-secondary";
485
+ focus.innerText = "Focus issue";
486
+ focus.onclick = function () { focusIssue(issue); };
487
+ row.appendChild(normalize);
488
+ row.appendChild(focus);
489
+ detail.appendChild(row);
490
+ return;
491
+ }
492
+
493
+ if (issue.code === "table-missing-header") {
494
+ var actionRow = detail.ownerDocument.createElement("div");
495
+ actionRow.className = "rte-a11y-row";
496
+ var promote = detail.ownerDocument.createElement("button");
497
+ promote.type = "button";
498
+ promote.className = "rte-a11y-button";
499
+ promote.innerText = "Promote first row to headers";
500
+ promote.onclick = function () {
501
+ repairIssue(selectedIssueIndex, {});
502
+ };
503
+ var review = detail.ownerDocument.createElement("button");
504
+ review.type = "button";
505
+ review.className = "rte-a11y-button rte-a11y-button-secondary";
506
+ review.innerText = "Focus issue";
507
+ review.onclick = function () { focusIssue(issue); };
508
+ actionRow.appendChild(promote);
509
+ actionRow.appendChild(review);
510
+ detail.appendChild(actionRow);
511
+ return;
512
+ }
513
+
514
+ detail.innerHTML += '<div class="rte-a11y-detail-copy">This issue is visible here, but does not have an automatic repair action yet.</div>';
515
+ }
516
+
517
+ function renderTextRepair(labelText, hintText, apply) {
518
+ var field = detail.ownerDocument.createElement("div");
519
+ field.className = "rte-a11y-field";
520
+ var label = detail.ownerDocument.createElement("div");
521
+ label.className = "rte-a11y-label";
522
+ label.innerText = labelText;
523
+ var input = detail.ownerDocument.createElement("input");
524
+ input.type = "text";
525
+ input.className = "rte-a11y-input";
526
+ input.placeholder = hintText;
527
+ var row = detail.ownerDocument.createElement("div");
528
+ row.className = "rte-a11y-row";
529
+ var button = detail.ownerDocument.createElement("button");
530
+ button.type = "button";
531
+ button.className = "rte-a11y-button";
532
+ button.innerText = "Apply fix";
533
+ button.onclick = function () {
534
+ var value = String(input.value || "").replace(/^\s+|\s+$/g, "");
535
+ if (!value) return;
536
+ apply(value);
537
+ };
538
+ var focus = detail.ownerDocument.createElement("button");
539
+ focus.type = "button";
540
+ focus.className = "rte-a11y-button rte-a11y-button-secondary";
541
+ focus.innerText = "Focus issue";
542
+ focus.onclick = function () {
543
+ var issues = lastResult && lastResult.issues ? lastResult.issues : [];
544
+ if (issues[selectedIssueIndex]) focusIssue(issues[selectedIssueIndex]);
545
+ };
546
+ row.appendChild(button);
547
+ row.appendChild(focus);
548
+ field.appendChild(label);
549
+ field.appendChild(input);
550
+ detail.appendChild(field);
551
+ detail.appendChild(row);
552
+ }
553
+
554
+ function suggestHeadingLevel(issue) {
555
+ var path = (issue && issue.path ? issue.path : "").replace(/\.attrs\.level$/, "");
556
+ var documentModel = editor.getJSON ? editor.getJSON() : null;
557
+ if (!documentModel || !documentModel.content) return 2;
558
+ var lastHeadingLevel = 0;
559
+
560
+ function visit(node, nodePath) {
561
+ if (!node || typeof node.type !== "string") return false;
562
+ if (nodePath === path) return true;
563
+ if (node.type === "heading" && node.attrs && typeof node.attrs.level === "number") {
564
+ lastHeadingLevel = node.attrs.level;
565
+ }
566
+ if (!node.content || !node.content.length) return false;
567
+ for (var index = 0; index < node.content.length; index++) {
568
+ if (visit(node.content[index], nodePath + ".content[" + index + "]")) return true;
569
+ }
570
+ return false;
571
+ }
572
+
573
+ for (var rootIndex = 0; rootIndex < documentModel.content.length; rootIndex++) {
574
+ if (visit(documentModel.content[rootIndex], "content[" + rootIndex + "]")) break;
575
+ }
576
+
577
+ return Math.max(1, Math.min(6, (lastHeadingLevel || 1) + (lastHeadingLevel ? 1 : 0)));
578
+ }
579
+ }