@richscripts/richtexteditor 2.5.3 → 2.6.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 +449 -360
- package/package.json +142 -142
- package/richtexteditor/CHANGELOG.md +2714 -2201
- package/richtexteditor/all_plugins.js +1064 -310
- package/richtexteditor/all_plugins.min.js +52 -52
- package/richtexteditor/plugins/accessibilitychecker.js +67 -4
- package/richtexteditor/plugins/aitoolkit.js +24 -6
- package/richtexteditor/plugins/aitoolkit.min.css +1 -0
- package/richtexteditor/plugins/all_plugins.js +1064 -310
- package/richtexteditor/plugins/all_plugins.min.js +52 -52
- package/richtexteditor/plugins/keyboarda11y.js +370 -342
- package/richtexteditor/plugins/layouttable.js +383 -0
- package/richtexteditor/plugins/shadowdom.js +252 -0
- package/richtexteditor/plugins/slashcommand.js +8 -0
- package/richtexteditor/rte-watchdog.js +303 -0
- package/richtexteditor/rte-webcomponent.js +351 -0
- package/richtexteditor/rte_mobile.min.css +1 -0
- package/richtexteditor/rte_theme_default.css +1 -1
- package/richtexteditor/rte_theme_default.min.css +1 -0
- package/richtexteditor/runtime/richtexteditor_content.min.css +1 -0
- package/richtexteditor/runtime/richtexteditor_preview.min.css +1 -0
|
@@ -408,7 +408,13 @@ function RTE_Plugin_AccessibilityChecker() {
|
|
|
408
408
|
if (headingText) previousHeadingLevel = level;
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
-
|
|
411
|
+
// querySelectorAll only returns DESCENDANTS, so an image that is
|
|
412
|
+
// itself a top-level block — which is exactly where a pasted or
|
|
413
|
+
// dropped image lands in an empty editor — was never checked, and
|
|
414
|
+
// missing alt text went unreported. The table rule below already
|
|
415
|
+
// guards this case; the image rule did not. Measured 2026-08-27:
|
|
416
|
+
// bare top-level img => 0 issues, the same img inside a <p> => 1.
|
|
417
|
+
var images = tag === "img" ? [node] : (node.querySelectorAll ? node.querySelectorAll("img") : []);
|
|
412
418
|
for (var imageIndex = 0; imageIndex < images.length; imageIndex++) {
|
|
413
419
|
var image = images[imageIndex];
|
|
414
420
|
if (!String(image.getAttribute("alt") || "").replace(/^\s+|\s+$/g, "")) {
|
|
@@ -425,11 +431,33 @@ function RTE_Plugin_AccessibilityChecker() {
|
|
|
425
431
|
var tables = tag === "table" ? [node] : (node.querySelectorAll ? node.querySelectorAll("table") : []);
|
|
426
432
|
for (var tableIndex = 0; tableIndex < tables.length; tableIndex++) {
|
|
427
433
|
var table = tables[tableIndex];
|
|
428
|
-
|
|
434
|
+
var tableRole = String(table.getAttribute("role") || "").toLowerCase();
|
|
435
|
+
var isLayoutTable = (tableRole === "presentation" || tableRole === "none");
|
|
436
|
+
|
|
437
|
+
// 2026-08-30 A layout table MUST NOT have headers, so demanding
|
|
438
|
+
// them here produced an error the author could never clear —
|
|
439
|
+
// which is how a checker teaches people to ignore it. Presentation
|
|
440
|
+
// tables are held to the opposite rule instead: they must not
|
|
441
|
+
// carry data-table semantics, because <th>/scope/<caption> make a
|
|
442
|
+
// screen reader announce relationships that do not exist
|
|
443
|
+
// (WCAG 1.3.1). See layouttable.js.
|
|
444
|
+
if (isLayoutTable) {
|
|
445
|
+
var semantic = table.querySelector("th, [scope], caption") || table.getAttribute("summary");
|
|
446
|
+
if (semantic) {
|
|
447
|
+
issues.push({
|
|
448
|
+
code: "layout-table-semantics",
|
|
449
|
+
severity: "error",
|
|
450
|
+
message: "Layout table still carries data-table markup (header cells, scope or a caption). A screen reader will announce relationships this table does not have.",
|
|
451
|
+
path: path + ".table[" + tableIndex + "]",
|
|
452
|
+
_target: table
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
else if (!table.querySelector("th")) {
|
|
429
457
|
issues.push({
|
|
430
458
|
code: "table-missing-header",
|
|
431
459
|
severity: "warning",
|
|
432
|
-
message: "Table has no header cells. Promote the first row to headers when it
|
|
460
|
+
message: "Table has no header cells. Promote the first row to headers, or mark it as a layout table when it only positions content.",
|
|
433
461
|
path: path + ".table[" + tableIndex + "]",
|
|
434
462
|
_target: table
|
|
435
463
|
});
|
|
@@ -460,7 +488,13 @@ function RTE_Plugin_AccessibilityChecker() {
|
|
|
460
488
|
target.parentNode.replaceChild(replacement, target);
|
|
461
489
|
}
|
|
462
490
|
else if (issue.code === "table-missing-header") {
|
|
463
|
-
|
|
491
|
+
// Two valid outcomes, and only the author knows which: the table
|
|
492
|
+
// describes data (give it headers) or only positions it (say so).
|
|
493
|
+
if (options && options.markLayout) markTableAsLayout(target);
|
|
494
|
+
else promoteFirstTableRow(target);
|
|
495
|
+
}
|
|
496
|
+
else if (issue.code === "layout-table-semantics") {
|
|
497
|
+
markTableAsLayout(target);
|
|
464
498
|
}
|
|
465
499
|
else if (issue.code === "language-of-parts") {
|
|
466
500
|
markLanguageRuns(target, options && options.lang ? options.lang : issue._lang, issue._script);
|
|
@@ -545,6 +579,35 @@ function RTE_Plugin_AccessibilityChecker() {
|
|
|
545
579
|
}
|
|
546
580
|
}
|
|
547
581
|
|
|
582
|
+
// Delegates to layouttable.js when it is loaded so there is ONE definition of
|
|
583
|
+
// what "layout table" means; the fallback keeps the repair working in builds
|
|
584
|
+
// where that plugin was left out of the bundle.
|
|
585
|
+
function markTableAsLayout(table) {
|
|
586
|
+
if (!table) return;
|
|
587
|
+
if (editor && typeof editor.setTableLayoutMode === "function") {
|
|
588
|
+
try { editor.setTableLayoutMode("layout", table); return; } catch (e) {}
|
|
589
|
+
}
|
|
590
|
+
table.setAttribute("role", "presentation");
|
|
591
|
+
table.removeAttribute("summary");
|
|
592
|
+
var caption = table.querySelector("caption");
|
|
593
|
+
if (caption && caption.parentNode === table) caption.parentNode.removeChild(caption);
|
|
594
|
+
var cells = table.querySelectorAll("th,[scope]");
|
|
595
|
+
for (var i = 0; i < cells.length; i++) {
|
|
596
|
+
var cell = cells[i];
|
|
597
|
+
// Tables nest — do not strip the headers of a data table that
|
|
598
|
+
// happens to sit inside a cell of this one.
|
|
599
|
+
if (cell.closest && cell.closest("table") !== table) continue;
|
|
600
|
+
cell.removeAttribute("scope");
|
|
601
|
+
cell.removeAttribute("headers");
|
|
602
|
+
if (String(cell.nodeName || "").toLowerCase() !== "th") continue;
|
|
603
|
+
var td = table.ownerDocument.createElement("td");
|
|
604
|
+
while (cell.firstChild) td.appendChild(cell.firstChild);
|
|
605
|
+
copyAttributes(cell, td);
|
|
606
|
+
td.removeAttribute("scope");
|
|
607
|
+
cell.parentNode.replaceChild(td, cell);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
548
611
|
function copyAttributes(source, target) {
|
|
549
612
|
if (!source || !target || !source.attributes) return;
|
|
550
613
|
for (var index = 0; index < source.attributes.length; index++) {
|
|
@@ -12,7 +12,9 @@ if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
|
|
|
12
12
|
var existing = document.querySelectorAll("link[rel=stylesheet]");
|
|
13
13
|
for (var i = 0; i < existing.length; i++) {
|
|
14
14
|
var href = existing[i].getAttribute("href") || "";
|
|
15
|
-
|
|
15
|
+
// Matches the minified variant too - a host page that links either one
|
|
16
|
+
// must not get a second copy injected.
|
|
17
|
+
if (/(?:^|\/)aitoolkit(?:\.min)?\.css(?:\?.*)?$/i.test(href)) return;
|
|
16
18
|
}
|
|
17
19
|
// Locate our own script tag (aitoolkit.js or all_plugins.js) so we
|
|
18
20
|
// can resolve aitoolkit.css next to it. Matches a custom mount path.
|
|
@@ -26,14 +28,30 @@ if (!window.RTE_DefaultConfig) window.RTE_DefaultConfig = {};
|
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
var srcAttr = ourScript ? ourScript.getAttribute("src") : "";
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
// Prefer the minified stylesheet. aitoolkit.css is 537 KB unminified - larger
|
|
32
|
+
// than the obfuscated rte.js - and every page that loads the AI toolkit was
|
|
33
|
+
// paying for it. The readable .css is still shipped and still the one to edit
|
|
34
|
+
// or override; this only changes what gets fetched by default.
|
|
35
|
+
function resolve(name) {
|
|
36
|
+
return srcAttr
|
|
37
|
+
? srcAttr.replace(/[^/]+$/, name)
|
|
38
|
+
: (((window.RTE_DefaultConfig && window.RTE_DefaultConfig.url_base) || "/richtexteditor") + "/plugins/" + name);
|
|
39
|
+
}
|
|
40
|
+
function bust(href) { return href.indexOf("?") < 0 ? href + "?v=20260830a" : href; }
|
|
41
|
+
|
|
33
42
|
var link = document.createElement("link");
|
|
34
43
|
link.rel = "stylesheet";
|
|
35
|
-
link.href =
|
|
44
|
+
link.href = bust(resolve("aitoolkit.min.css"));
|
|
36
45
|
link.setAttribute("data-rte-auto-injected", "aitoolkit");
|
|
46
|
+
// .min.css is newer than .css. An install that predates it - an unpacked older
|
|
47
|
+
// zip, a tier the mirror missed - would otherwise lose ALL AI toolkit styling
|
|
48
|
+
// silently, which is a far worse failure than shipping the larger file. Fall
|
|
49
|
+
// back to the readable stylesheet if the minified one is not there.
|
|
50
|
+
link.onerror = function () {
|
|
51
|
+
if (link.getAttribute("data-rte-css-fallback")) return;
|
|
52
|
+
link.setAttribute("data-rte-css-fallback", "1");
|
|
53
|
+
link.href = bust(resolve("aitoolkit.css"));
|
|
54
|
+
};
|
|
37
55
|
(document.head || document.documentElement).appendChild(link);
|
|
38
56
|
})();
|
|
39
57
|
|