tinymce-rails 7.2.1 → 7.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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -4
  3. data/app/assets/source/tinymce/tinymce.js +263 -189
  4. data/lib/tinymce/rails/asset_installer/copy_no_preserve.rb +1 -1
  5. data/lib/tinymce/rails/asset_installer.rb +4 -4
  6. data/lib/tinymce/rails/asset_manifest/json_manifest.rb +62 -0
  7. data/lib/tinymce/rails/asset_manifest/null_manifest.rb +12 -0
  8. data/lib/tinymce/rails/asset_manifest/propshaft_manifest.rb +43 -0
  9. data/lib/tinymce/rails/asset_manifest/yaml_manifest.rb +43 -0
  10. data/lib/tinymce/rails/asset_manifest.rb +6 -108
  11. data/lib/tinymce/rails/engine.rb +15 -2
  12. data/lib/tinymce/rails/helper.rb +19 -5
  13. data/lib/tinymce/rails/propshaft/asset.rb +11 -0
  14. data/lib/tinymce/rails/version.rb +2 -2
  15. data/lib/tinymce/rails.rb +2 -2
  16. data/vendor/assets/javascripts/tinymce/icons/default/icons.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/models/dom/model.js +2 -2
  18. data/vendor/assets/javascripts/tinymce/plugins/accordion/plugin.js +2 -2
  19. data/vendor/assets/javascripts/tinymce/plugins/advlist/plugin.js +2 -2
  20. data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +2 -2
  22. data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
  23. data/vendor/assets/javascripts/tinymce/plugins/autosave/plugin.js +2 -2
  24. data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.js +1 -1
  25. data/vendor/assets/javascripts/tinymce/plugins/code/plugin.js +1 -1
  26. data/vendor/assets/javascripts/tinymce/plugins/codesample/plugin.js +1 -1
  27. data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.js +2 -2
  28. data/vendor/assets/javascripts/tinymce/plugins/emoticons/plugin.js +1 -1
  29. data/vendor/assets/javascripts/tinymce/plugins/fullscreen/plugin.js +2 -2
  30. data/vendor/assets/javascripts/tinymce/plugins/help/plugin.js +2 -2
  31. data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +2 -2
  32. data/vendor/assets/javascripts/tinymce/plugins/importcss/plugin.js +1 -1
  33. data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +2 -2
  34. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +2 -2
  35. data/vendor/assets/javascripts/tinymce/plugins/lists/plugin.js +2 -2
  36. data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
  37. data/vendor/assets/javascripts/tinymce/plugins/nonbreaking/plugin.js +1 -1
  38. data/vendor/assets/javascripts/tinymce/plugins/pagebreak/plugin.js +1 -1
  39. data/vendor/assets/javascripts/tinymce/plugins/preview/plugin.js +2 -2
  40. data/vendor/assets/javascripts/tinymce/plugins/quickbars/plugin.js +2 -2
  41. data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
  42. data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
  43. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +2 -2
  44. data/vendor/assets/javascripts/tinymce/plugins/visualblocks/plugin.js +2 -2
  45. data/vendor/assets/javascripts/tinymce/plugins/visualchars/plugin.js +2 -2
  46. data/vendor/assets/javascripts/tinymce/plugins/wordcount/plugin.js +2 -2
  47. data/vendor/assets/javascripts/tinymce/skins/content/dark/content.js +1 -2
  48. data/vendor/assets/javascripts/tinymce/skins/content/default/content.js +1 -2
  49. data/vendor/assets/javascripts/tinymce/skins/content/document/content.js +1 -2
  50. data/vendor/assets/javascripts/tinymce/skins/content/tinymce-5/content.js +1 -2
  51. data/vendor/assets/javascripts/tinymce/skins/content/tinymce-5-dark/content.js +1 -2
  52. data/vendor/assets/javascripts/tinymce/skins/content/writer/content.js +1 -2
  53. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.css +1 -1
  54. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.css +1 -1
  55. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.js +1 -2
  56. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.min.css +1 -1
  57. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.js +1 -2
  58. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.min.css +1 -1
  59. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.css +1 -1
  60. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.js +1 -2
  61. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.min.css +1 -1
  62. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.shadowdom.js +1 -2
  63. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.css +1 -1
  64. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.css +1 -1
  65. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.js +1 -2
  66. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.min.css +1 -1
  67. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.js +1 -2
  68. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.min.css +1 -1
  69. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.css +1 -1
  70. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.js +1 -2
  71. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.min.css +1 -1
  72. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.shadowdom.js +1 -2
  73. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.css +1 -1
  74. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.css +1 -1
  75. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.js +1 -2
  76. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.min.css +1 -1
  77. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.js +1 -2
  78. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.min.css +1 -1
  79. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.css +1 -1
  80. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.js +1 -2
  81. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.min.css +1 -1
  82. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.shadowdom.js +1 -2
  83. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.css +1 -1
  84. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.css +1 -1
  85. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.js +1 -2
  86. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css +1 -1
  87. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.js +1 -2
  88. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.min.css +1 -1
  89. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.css +1 -1
  90. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.js +1 -2
  91. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.min.css +1 -1
  92. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.js +1 -2
  93. data/vendor/assets/javascripts/tinymce/themes/silver/theme.js +2 -2
  94. data/vendor/assets/javascripts/tinymce/tinymce.d.ts +23 -0
  95. data/vendor/assets/javascripts/tinymce/tinymce.js +2 -2
  96. metadata +13 -8
  97. /data/app/assets/{javascripts → sprockets}/tinymce/preinit.js.erb +0 -0
  98. /data/app/assets/{javascripts → sprockets}/tinymce.js +0 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TinyMCE version 7.2.1 (2024-07-03)
2
+ * TinyMCE version 7.4.0 (2024-10-09)
3
3
  */
4
4
 
5
5
  (function () {
@@ -955,10 +955,10 @@
955
955
  const PlatformDetection = { detect: detect$2 };
956
956
 
957
957
  const mediaMatch = query => window.matchMedia(query).matches;
958
- let platform$4 = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
958
+ let platform$4 = cached(() => PlatformDetection.detect(window.navigator.userAgent, Optional.from(window.navigator.userAgentData), mediaMatch));
959
959
  const detect$1 = () => platform$4();
960
960
 
961
- const userAgent = navigator.userAgent;
961
+ const userAgent = window.navigator.userAgent;
962
962
  const platform$3 = detect$1();
963
963
  const browser$3 = platform$3.browser;
964
964
  const os$1 = platform$3.os;
@@ -1402,9 +1402,7 @@
1402
1402
  };
1403
1403
 
1404
1404
  const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
1405
- const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
1406
- const isSupported$1 = constant(supported);
1407
- const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
1405
+ const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode());
1408
1406
  const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
1409
1407
  const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
1410
1408
  const getShadowRoot = e => {
@@ -1413,7 +1411,7 @@
1413
1411
  };
1414
1412
  const getShadowHost = e => SugarElement.fromDom(e.dom.host);
1415
1413
  const getOriginalEventTarget = event => {
1416
- if (isSupported$1() && isNonNullable(event.target)) {
1414
+ if (isNonNullable(event.target)) {
1417
1415
  const el = SugarElement.fromDom(event.target);
1418
1416
  if (isElement$7(el) && isOpenShadowHost(el)) {
1419
1417
  if (event.composed && event.composedPath) {
@@ -5455,13 +5453,16 @@
5455
5453
  };
5456
5454
  };
5457
5455
 
5456
+ const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
5457
+ const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295;
5458
+
5458
5459
  let unique = 0;
5459
5460
  const generate$1 = prefix => {
5460
5461
  const date = new Date();
5461
5462
  const time = date.getTime();
5462
- const random = Math.floor(Math.random() * 1000000000);
5463
+ const random$1 = Math.floor(random() * 1000000000);
5463
5464
  unique++;
5464
- return prefix + '_' + random + unique + String(time);
5465
+ return prefix + '_' + random$1 + unique + String(time);
5465
5466
  };
5466
5467
 
5467
5468
  const add = (element, classes) => {
@@ -5858,8 +5859,6 @@
5858
5859
  };
5859
5860
  const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
5860
5861
 
5861
- const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
5862
-
5863
5862
  const getSelectedNode = range => {
5864
5863
  const startContainer = range.startContainer, startOffset = range.startOffset;
5865
5864
  if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
@@ -7291,6 +7290,19 @@
7291
7290
  processor: 'boolean',
7292
7291
  default: false
7293
7292
  });
7293
+ registerOption('allow_mathml_annotation_encodings', {
7294
+ processor: value => {
7295
+ const valid = isArrayOf(value, isString);
7296
+ return valid ? {
7297
+ value,
7298
+ valid
7299
+ } : {
7300
+ valid: false,
7301
+ message: 'Must be an array of strings.'
7302
+ };
7303
+ },
7304
+ default: []
7305
+ });
7294
7306
  registerOption('convert_fonts_to_spans', {
7295
7307
  processor: 'boolean',
7296
7308
  default: true,
@@ -7949,7 +7961,7 @@
7949
7961
  const isContentEditableTrue$1 = isContentEditableTrue$3;
7950
7962
  const isContentEditableFalse$7 = isContentEditableFalse$b;
7951
7963
  const isMedia = isMedia$2;
7952
- const isBlockLike = matchStyleValues('display', 'block table table-cell table-caption list-item');
7964
+ const isBlockLike = matchStyleValues('display', 'block table table-cell table-row table-caption list-item');
7953
7965
  const isCaretContainer = isCaretContainer$2;
7954
7966
  const isCaretContainerBlock = isCaretContainerBlock$1;
7955
7967
  const isElement$2 = isElement$6;
@@ -9636,7 +9648,7 @@
9636
9648
  };
9637
9649
  const isResizable = elm => {
9638
9650
  const selector = getObjectResizing(editor);
9639
- if (!selector) {
9651
+ if (!selector || editor.mode.isReadOnly()) {
9640
9652
  return false;
9641
9653
  }
9642
9654
  if (elm.getAttribute('data-mce-resize') === 'false') {
@@ -10022,32 +10034,32 @@
10022
10034
  const SimRange = { create: create$9 };
10023
10035
 
10024
10036
  const caretPositionFromPoint = (doc, x, y) => {
10025
- var _a, _b;
10026
- return Optional.from((_b = (_a = doc.dom).caretPositionFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y)).bind(pos => {
10037
+ var _a;
10038
+ return Optional.from((_a = doc.caretPositionFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)).bind(pos => {
10027
10039
  if (pos.offsetNode === null) {
10028
10040
  return Optional.none();
10029
10041
  }
10030
- const r = doc.dom.createRange();
10042
+ const r = doc.createRange();
10031
10043
  r.setStart(pos.offsetNode, pos.offset);
10032
10044
  r.collapse();
10033
10045
  return Optional.some(r);
10034
10046
  });
10035
10047
  };
10036
10048
  const caretRangeFromPoint = (doc, x, y) => {
10037
- var _a, _b;
10038
- return Optional.from((_b = (_a = doc.dom).caretRangeFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y));
10049
+ var _a;
10050
+ return Optional.from((_a = doc.caretRangeFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y));
10039
10051
  };
10040
- const availableSearch = (() => {
10041
- if (document.caretPositionFromPoint) {
10042
- return caretPositionFromPoint;
10043
- } else if (document.caretRangeFromPoint) {
10044
- return caretRangeFromPoint;
10052
+ const availableSearch = (doc, x, y) => {
10053
+ if (doc.caretPositionFromPoint) {
10054
+ return caretPositionFromPoint(doc, x, y);
10055
+ } else if (doc.caretRangeFromPoint) {
10056
+ return caretRangeFromPoint(doc, x, y);
10045
10057
  } else {
10046
- return Optional.none;
10058
+ return Optional.none();
10047
10059
  }
10048
- })();
10060
+ };
10049
10061
  const fromPoint$1 = (win, x, y) => {
10050
- const doc = SugarElement.fromDom(win.document);
10062
+ const doc = win.document;
10051
10063
  return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
10052
10064
  };
10053
10065
 
@@ -10211,7 +10223,7 @@
10211
10223
  var _a;
10212
10224
  return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
10213
10225
  };
10214
- const hasContentEditableFalseParent = (root, node) => {
10226
+ const hasContentEditableFalseParent$1 = (root, node) => {
10215
10227
  let currentNode = node;
10216
10228
  while (currentNode && currentNode !== root) {
10217
10229
  if (isContentEditableFalse$b(currentNode)) {
@@ -10296,7 +10308,7 @@
10296
10308
  if (!collapsed && container === body.lastChild && isTable$2(container)) {
10297
10309
  return Optional.none();
10298
10310
  }
10299
- if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
10311
+ if (hasContentEditableFalseParent$1(body, container) || isCaretContainer$2(container)) {
10300
10312
  return Optional.none();
10301
10313
  }
10302
10314
  if (isDetails(container)) {
@@ -10924,6 +10936,7 @@
10924
10936
  };
10925
10937
 
10926
10938
  const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
10939
+ const hasContentEditableFalseParent = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'false') !== null;
10927
10940
  const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
10928
10941
  const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
10929
10942
  if (isTableSection(node)) {
@@ -10980,6 +10993,9 @@
10980
10993
  }
10981
10994
  const contentEditableHost = getContentEditableHost(editor, selection.getNode());
10982
10995
  if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
10996
+ if (!hasContentEditableFalseParent(editor, contentEditableHost)) {
10997
+ focusBody(body);
10998
+ }
10983
10999
  focusBody(contentEditableHost);
10984
11000
  if (!editor.hasEditableRoot()) {
10985
11001
  restoreBookmark(editor);
@@ -11997,7 +12013,7 @@
11997
12013
  return false;
11998
12014
  }
11999
12015
  };
12000
- const normalizeNbsps = (root, pos, schema) => {
12016
+ const normalizeNbsps$1 = (root, pos, schema) => {
12001
12017
  const container = pos.container();
12002
12018
  if (!isText$b(container)) {
12003
12019
  return Optional.none();
@@ -12015,7 +12031,7 @@
12015
12031
  const normalizeNbspsInEditor = editor => {
12016
12032
  const root = SugarElement.fromDom(editor.getBody());
12017
12033
  if (editor.selection.isCollapsed()) {
12018
- normalizeNbsps(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
12034
+ normalizeNbsps$1(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
12019
12035
  editor.selection.setRng(pos.toRange());
12020
12036
  });
12021
12037
  }
@@ -13240,6 +13256,9 @@
13240
13256
  if (node && node.attr('id') === 'mce_marker') {
13241
13257
  const marker = node;
13242
13258
  for (node = node.prev; node; node = node.walk(true)) {
13259
+ if (node.name === 'table') {
13260
+ break;
13261
+ }
13243
13262
  if (node.type === 3 || !dom.isBlock(node.name)) {
13244
13263
  if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) {
13245
13264
  node.parent.insert(marker, node, node.name === 'br');
@@ -13663,6 +13682,35 @@
13663
13682
  return Optional.none();
13664
13683
  }
13665
13684
  };
13685
+ const normalizeNbsps = node => set(node, get$3(node).replace(new RegExp(`${ nbsp }$`), ' '));
13686
+ const normalizeNbspsBetween = (editor, caretContainer) => {
13687
+ const handler = () => {
13688
+ if (caretContainer !== null && !editor.dom.isEmpty(caretContainer)) {
13689
+ prevSibling(SugarElement.fromDom(caretContainer)).each(node => {
13690
+ if (isText$c(node)) {
13691
+ normalizeNbsps(node);
13692
+ } else {
13693
+ descendant$2(node, e => isText$c(e)).each(textNode => {
13694
+ if (isText$c(textNode)) {
13695
+ normalizeNbsps(textNode);
13696
+ }
13697
+ });
13698
+ }
13699
+ });
13700
+ }
13701
+ };
13702
+ editor.once('input', e => {
13703
+ if (e.data && !isWhiteSpace(e.data)) {
13704
+ if (!e.isComposing) {
13705
+ handler();
13706
+ } else {
13707
+ editor.once('compositionend', () => {
13708
+ handler();
13709
+ });
13710
+ }
13711
+ }
13712
+ });
13713
+ };
13666
13714
  const applyCaretFormat = (editor, name, vars) => {
13667
13715
  let caretContainer;
13668
13716
  const selection = editor.selection;
@@ -13690,6 +13738,7 @@
13690
13738
  textNode = caretContainer.firstChild;
13691
13739
  selectionRng.insertNode(caretContainer);
13692
13740
  offset = 1;
13741
+ normalizeNbspsBetween(editor, caretContainer);
13693
13742
  editor.formatter.apply(name, vars, caretContainer);
13694
13743
  } else {
13695
13744
  editor.formatter.apply(name, vars, caretContainer);
@@ -13753,6 +13802,7 @@
13753
13802
  removeCaretContainerNode(editor, caretContainer, isNonNullable(caretContainer));
13754
13803
  }
13755
13804
  selection.setCursorLocation(caretTextNode, 1);
13805
+ normalizeNbspsBetween(editor, newCaretContainer);
13756
13806
  if (dom.isEmpty(formatNode)) {
13757
13807
  dom.remove(formatNode);
13758
13808
  }
@@ -17196,37 +17246,55 @@
17196
17246
  }
17197
17247
  return config;
17198
17248
  };
17199
- const sanitizeNamespaceElement = ele => {
17249
+ const sanitizeSvgElement = ele => {
17250
+ const xlinkAttrs = [
17251
+ 'type',
17252
+ 'href',
17253
+ 'role',
17254
+ 'arcrole',
17255
+ 'title',
17256
+ 'show',
17257
+ 'actuate',
17258
+ 'label',
17259
+ 'from',
17260
+ 'to'
17261
+ ].map(name => `xlink:${ name }`);
17262
+ const config = {
17263
+ IN_PLACE: true,
17264
+ USE_PROFILES: {
17265
+ html: true,
17266
+ svg: true,
17267
+ svgFilters: true
17268
+ },
17269
+ ALLOWED_ATTR: xlinkAttrs
17270
+ };
17271
+ purify().sanitize(ele, config);
17272
+ };
17273
+ const sanitizeMathmlElement = (node, settings) => {
17274
+ const config = {
17275
+ IN_PLACE: true,
17276
+ USE_PROFILES: { mathMl: true }
17277
+ };
17278
+ const purify$1 = purify();
17279
+ purify$1.addHook('uponSanitizeElement', (node, evt) => {
17280
+ var _a;
17281
+ const lcTagName = (_a = evt.tagName) !== null && _a !== void 0 ? _a : node.nodeName.toLowerCase();
17282
+ const allowedEncodings = settings.allow_mathml_annotation_encodings;
17283
+ if (lcTagName === 'annotation' && isArray$1(allowedEncodings) && allowedEncodings.length > 0) {
17284
+ const encoding = node.getAttribute('encoding');
17285
+ if (isString(encoding) && contains$2(allowedEncodings, encoding)) {
17286
+ evt.allowedTags[lcTagName] = true;
17287
+ }
17288
+ }
17289
+ });
17290
+ purify$1.sanitize(node, config);
17291
+ };
17292
+ const mkSanitizeNamespaceElement = settings => ele => {
17200
17293
  const namespaceType = toScopeType(ele);
17201
17294
  if (namespaceType === 'svg') {
17202
- const xlinkAttrs = [
17203
- 'type',
17204
- 'href',
17205
- 'role',
17206
- 'arcrole',
17207
- 'title',
17208
- 'show',
17209
- 'actuate',
17210
- 'label',
17211
- 'from',
17212
- 'to'
17213
- ].map(name => `xlink:${ name }`);
17214
- const config = {
17215
- IN_PLACE: true,
17216
- USE_PROFILES: {
17217
- html: true,
17218
- svg: true,
17219
- svgFilters: true
17220
- },
17221
- ALLOWED_ATTR: xlinkAttrs
17222
- };
17223
- purify().sanitize(ele, config);
17295
+ sanitizeSvgElement(ele);
17224
17296
  } else if (namespaceType === 'math') {
17225
- const config = {
17226
- IN_PLACE: true,
17227
- USE_PROFILES: { mathMl: true }
17228
- };
17229
- purify().sanitize(ele, config);
17297
+ sanitizeMathmlElement(ele, settings);
17230
17298
  } else {
17231
17299
  throw new Error('Not a namespace element');
17232
17300
  }
@@ -17242,7 +17310,7 @@
17242
17310
  };
17243
17311
  return {
17244
17312
  sanitizeHtmlElement,
17245
- sanitizeNamespaceElement
17313
+ sanitizeNamespaceElement: mkSanitizeNamespaceElement(settings)
17246
17314
  };
17247
17315
  } else {
17248
17316
  const sanitizeHtmlElement = (body, _mimeType) => {
@@ -17363,6 +17431,8 @@
17363
17431
  }
17364
17432
  if (text.length === 0) {
17365
17433
  node.remove();
17434
+ } else if (text === ' ' && node.prev && node.prev.type === COMMENT && node.next && node.next.type === COMMENT) {
17435
+ node.remove();
17366
17436
  } else {
17367
17437
  node.value = text;
17368
17438
  }
@@ -17432,8 +17502,16 @@
17432
17502
  const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
17433
17503
  const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
17434
17504
  const content = isSpecialRoot ? `<${ rootName }>${ html }</${ rootName }>` : html;
17435
- const wrappedHtml = format === 'xhtml' ? `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>` : `<body>${ content }</body>`;
17436
- const body = parser.parseFromString(wrappedHtml, mimeType).body;
17505
+ const makeWrap = () => {
17506
+ if (format === 'xhtml') {
17507
+ return `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>`;
17508
+ } else if (/^[\s]*<head/i.test(html) || /^[\s]*<html/i.test(html) || /^[\s]*<!DOCTYPE/i.test(html)) {
17509
+ return `<html>${ content }</html>`;
17510
+ } else {
17511
+ return `<body>${ content }</body>`;
17512
+ }
17513
+ };
17514
+ const body = parser.parseFromString(makeWrap(), mimeType).body;
17437
17515
  sanitizer.sanitizeHtmlElement(body, mimeType);
17438
17516
  return isSpecialRoot ? body.firstChild : body;
17439
17517
  };
@@ -18699,6 +18777,9 @@
18699
18777
  return !sel || rng.collapsed;
18700
18778
  };
18701
18779
  const isEditable = () => {
18780
+ if (editor.mode.isReadOnly()) {
18781
+ return false;
18782
+ }
18702
18783
  const rng = getRng$1();
18703
18784
  const fakeSelectedElements = editor.getBody().querySelectorAll('[data-mce-selected="1"]');
18704
18785
  if (fakeSelectedElements.length > 0) {
@@ -19553,7 +19634,7 @@
19553
19634
  }
19554
19635
  reposition();
19555
19636
  });
19556
- editor.on('show ResizeEditor NodeChange', () => {
19637
+ editor.on('show ResizeEditor ResizeWindow NodeChange ToggleView FullscreenStateChanged', () => {
19557
19638
  requestAnimationFrame(reposition);
19558
19639
  });
19559
19640
  editor.on('remove', () => {
@@ -19858,7 +19939,7 @@
19858
19939
  let count = 0;
19859
19940
  const seed = () => {
19860
19941
  const rnd = () => {
19861
- return Math.round(Math.random() * 4294967295).toString(36);
19942
+ return Math.round(random() * 4294967295).toString(36);
19862
19943
  };
19863
19944
  const now = new Date().getTime();
19864
19945
  return 's' + now.toString(36) + rnd() + rnd() + rnd();
@@ -21304,26 +21385,12 @@
21304
21385
  };
21305
21386
  const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none();
21306
21387
 
21307
- const getChildrenFromNestedUntilBlockBoundary = (block, schema, forwardDelete) => {
21308
- const allSiblingsInDirection = forwardDelete ? prevSiblings(block).reverse() : nextSiblings(block);
21309
- const siblingsToMergeIn = findIndex$2(allSiblingsInDirection, element => schema.isBlock(name(element))).fold(constant(allSiblingsInDirection), index => allSiblingsInDirection.slice(0, index));
21310
- if (forwardDelete) {
21311
- return siblingsToMergeIn.reverse();
21312
- }
21313
- return siblingsToMergeIn;
21314
- };
21315
- const getChildrenUntilBlockBoundary = (toBlock, fromBlock, schema, forwardDelete, extractsiblingsIfNested) => {
21316
- if (extractsiblingsIfNested && contains(toBlock, fromBlock)) {
21317
- return getChildrenFromNestedUntilBlockBoundary(fromBlock, schema, forwardDelete);
21318
- } else if (extractsiblingsIfNested && contains(fromBlock, toBlock)) {
21319
- return getChildrenFromNestedUntilBlockBoundary(toBlock, schema, forwardDelete);
21320
- } else {
21321
- const children = children$1(fromBlock);
21322
- return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index));
21323
- }
21388
+ const getChildrenUntilBlockBoundary = (block, schema) => {
21389
+ const children = children$1(block);
21390
+ return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index));
21324
21391
  };
21325
- const extractChildren = (toBlock, fromBlock, schema, forwardDelete, extractsiblingsIfNested) => {
21326
- const children = getChildrenUntilBlockBoundary(toBlock, fromBlock, schema, forwardDelete, extractsiblingsIfNested);
21392
+ const extractChildren = (block, schema) => {
21393
+ const children = getChildrenUntilBlockBoundary(block, schema);
21327
21394
  each$e(children, remove$4);
21328
21395
  return children;
21329
21396
  };
@@ -21332,7 +21399,7 @@
21332
21399
  return find$2(parents.reverse(), element => isEmpty$2(schema, element)).each(remove$4);
21333
21400
  };
21334
21401
  const isEmptyBefore = (schema, el) => filter$5(prevSiblings(el), el => !isEmpty$2(schema, el)).length === 0;
21335
- const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, forward, insertionPoint) => {
21402
+ const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, insertionPoint) => {
21336
21403
  if (isEmpty$2(schema, toBlock)) {
21337
21404
  fillWithPaddingBr(toBlock);
21338
21405
  return firstPositionIn(toBlock.dom);
@@ -21341,14 +21408,14 @@
21341
21408
  before$3(insertionPoint, SugarElement.fromTag('br'));
21342
21409
  }
21343
21410
  const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
21344
- each$e(extractChildren(toBlock, fromBlock, schema, forward, false), child => {
21411
+ each$e(extractChildren(fromBlock, schema), child => {
21345
21412
  before$3(insertionPoint, child);
21346
21413
  });
21347
21414
  removeEmptyRoot(schema, rootNode, fromBlock);
21348
21415
  return position;
21349
21416
  };
21350
21417
  const isInline = (schema, node) => schema.isInline(name(node));
21351
- const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema, forwardDelete) => {
21418
+ const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema) => {
21352
21419
  if (isEmpty$2(schema, toBlock)) {
21353
21420
  if (isEmpty$2(schema, fromBlock)) {
21354
21421
  const getInlineToBlockDescendants = el => {
@@ -21366,12 +21433,8 @@
21366
21433
  return firstPositionIn(fromBlock.dom);
21367
21434
  }
21368
21435
  const position = lastPositionIn(toBlock.dom);
21369
- each$e(extractChildren(toBlock, fromBlock, schema, forwardDelete, true), child => {
21370
- if (forwardDelete && contains(fromBlock, toBlock)) {
21371
- prepend(toBlock, child);
21372
- } else {
21373
- append$1(toBlock, child);
21374
- }
21436
+ each$e(extractChildren(fromBlock, schema), child => {
21437
+ append$1(toBlock, child);
21375
21438
  });
21376
21439
  removeEmptyRoot(schema, rootNode, fromBlock);
21377
21440
  return position;
@@ -21384,26 +21447,17 @@
21384
21447
  const trimBr = (first, block) => {
21385
21448
  positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$4);
21386
21449
  };
21387
- const mergeBlockInto = (rootNode, fromBlock, toBlock, schema, forward) => {
21450
+ const mergeBlockInto = (rootNode, fromBlock, toBlock, schema) => {
21388
21451
  trimBr(true, fromBlock);
21389
21452
  trimBr(false, toBlock);
21390
- return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema, forward), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema, forward));
21391
- };
21392
- const mergeBlocks = (rootNode, forward, block1, block2, schema, mergeNotDelete = false) => {
21393
- if (mergeNotDelete) {
21394
- if (contains(block2, block1)) {
21395
- return mergeBlockInto(rootNode, block2, block1, schema, !forward);
21396
- } else if (contains(block1, block2)) {
21397
- return mergeBlockInto(rootNode, block1, block2, schema, forward);
21398
- }
21399
- }
21400
- return forward ? mergeBlockInto(rootNode, block2, block1, schema, forward) : mergeBlockInto(rootNode, block1, block2, schema, !forward);
21453
+ return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema));
21401
21454
  };
21455
+ const mergeBlocks = (rootNode, forward, block1, block2, schema) => forward ? mergeBlockInto(rootNode, block2, block1, schema) : mergeBlockInto(rootNode, block1, block2, schema);
21402
21456
 
21403
21457
  const backspaceDelete$a = (editor, forward) => {
21404
21458
  const rootNode = SugarElement.fromDom(editor.getBody());
21405
21459
  const position = read$1(editor.schema, rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => {
21406
- mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema, true).each(pos => {
21460
+ mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema).each(pos => {
21407
21461
  editor.selection.setRng(pos.toRange());
21408
21462
  });
21409
21463
  });
@@ -22642,6 +22696,9 @@
22642
22696
  const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el));
22643
22697
  const handle = (editor, command) => {
22644
22698
  var _a, _b;
22699
+ if (editor.mode.isReadOnly()) {
22700
+ return;
22701
+ }
22645
22702
  const {dom} = editor;
22646
22703
  const indentation = getIndentation(editor);
22647
22704
  const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px';
@@ -23381,6 +23438,9 @@
23381
23438
  return getCellFirstCursorPosition(cell);
23382
23439
  });
23383
23440
  }, current => {
23441
+ if (editor.mode.isReadOnly()) {
23442
+ return Optional.none();
23443
+ }
23384
23444
  editor.execCommand('mceTableInsertRowAfter');
23385
23445
  return tabForward(editor, isRoot, current);
23386
23446
  });
@@ -24061,7 +24121,8 @@
24061
24121
  optionalTooltip,
24062
24122
  optionalIcon,
24063
24123
  optionalText,
24064
- onSetup
24124
+ onSetup,
24125
+ defaultedString('context', 'mode:design')
24065
24126
  ];
24066
24127
 
24067
24128
  const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
@@ -24924,9 +24985,12 @@
24924
24985
  const isEmptyAnchor = (dom, elm) => {
24925
24986
  return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
24926
24987
  };
24927
- const containerAndSiblingName = (container, nodeName) => {
24988
+ const containerAndPreviousSiblingName = (container, nodeName) => {
24928
24989
  return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
24929
24990
  };
24991
+ const containerAndNextSiblingName = (container, nodeName) => {
24992
+ return container.nodeName === nodeName || container.nextSibling && container.nextSibling.nodeName === nodeName;
24993
+ };
24930
24994
  const canSplitBlock = (dom, node) => {
24931
24995
  return isNonNullable(node) && dom.isBlock(node) && !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) && !/^(fixed|absolute)/i.test(node.style.position) && dom.isEditable(node.parentNode) && dom.getContentEditable(node) !== 'false';
24932
24996
  };
@@ -25068,7 +25132,10 @@
25068
25132
  if (start && isElement$6(container) && container === parentBlock.firstChild) {
25069
25133
  return true;
25070
25134
  }
25071
- if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
25135
+ if (containerAndPreviousSiblingName(container, 'TABLE') || containerAndPreviousSiblingName(container, 'HR')) {
25136
+ if (containerAndNextSiblingName(container, 'BR')) {
25137
+ return !start;
25138
+ }
25072
25139
  return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
25073
25140
  }
25074
25141
  const walker = new DomTreeWalker(container, parentBlock);
@@ -25186,7 +25253,7 @@
25186
25253
  const afterBr = isAfterBr(parentBlockSugar, caretPos, editor.schema);
25187
25254
  const prevBrOpt = afterBr ? findPreviousBr(parentBlockSugar, caretPos, editor.schema).bind(pos => Optional.from(pos.getNode())) : Optional.none();
25188
25255
  newBlock = parentBlockParent.insertBefore(createNewBlock$1(), parentBlock);
25189
- const root = containerAndSiblingName(parentBlock, 'HR') || afterTable ? newBlock : prevBrOpt.getOr(parentBlock);
25256
+ const root = containerAndPreviousSiblingName(parentBlock, 'HR') || afterTable ? newBlock : prevBrOpt.getOr(parentBlock);
25190
25257
  moveToCaretPosition(editor, root);
25191
25258
  } else {
25192
25259
  const tmpRng = includeZwspInRange(rng).cloneRange();
@@ -25446,6 +25513,9 @@
25446
25513
  };
25447
25514
 
25448
25515
  const insertBreak = (breakType, editor, evt) => {
25516
+ if (editor.mode.isReadOnly()) {
25517
+ return;
25518
+ }
25449
25519
  if (!editor.selection.isCollapsed()) {
25450
25520
  execEditorDeleteCommand(editor);
25451
25521
  }
@@ -25461,6 +25531,9 @@
25461
25531
  }
25462
25532
  };
25463
25533
  const insert$1 = (editor, evt) => {
25534
+ if (editor.mode.isReadOnly()) {
25535
+ return;
25536
+ }
25464
25537
  const br = () => insertBreak(linebreak, editor, evt);
25465
25538
  const block = () => insertBreak(blockbreak, editor, evt);
25466
25539
  const logicalAction = getAction(editor, evt);
@@ -25823,16 +25896,17 @@
25823
25896
  });
25824
25897
  }
25825
25898
  nodeChanged(args = {}) {
25826
- const selection = this.editor.selection;
25899
+ const editor = this.editor;
25900
+ const selection = editor.selection;
25827
25901
  let node;
25828
- if (this.editor.initialized && selection && !shouldDisableNodeChange(this.editor) && !this.editor.mode.isReadOnly()) {
25829
- const root = this.editor.getBody();
25902
+ if (editor.initialized && selection && !shouldDisableNodeChange(editor)) {
25903
+ const root = editor.getBody();
25830
25904
  node = selection.getStart(true) || root;
25831
- if (node.ownerDocument !== this.editor.getDoc() || !this.editor.dom.isChildOf(node, root)) {
25905
+ if (node.ownerDocument !== editor.getDoc() || !editor.dom.isChildOf(node, root)) {
25832
25906
  node = root;
25833
25907
  }
25834
25908
  const parents = [];
25835
- this.editor.dom.getParent(node, node => {
25909
+ editor.dom.getParent(node, node => {
25836
25910
  if (node === root) {
25837
25911
  return true;
25838
25912
  } else {
@@ -25840,7 +25914,7 @@
25840
25914
  return false;
25841
25915
  }
25842
25916
  });
25843
- this.editor.dispatch('NodeChange', {
25917
+ editor.dispatch('NodeChange', {
25844
25918
  ...args,
25845
25919
  element: node,
25846
25920
  parents
@@ -28303,10 +28377,15 @@
28303
28377
  '?'
28304
28378
  ];
28305
28379
  const keyCodes = [32];
28306
- const getPatternSet = () => createPatternSet(getTextPatterns(editor), getTextPatternsLookup(editor));
28380
+ const getPatternSet = () => createPatternSet(getTextPatterns(editor).filter(pattern => {
28381
+ if (pattern.type === 'inline-command' || pattern.type === 'block-command') {
28382
+ return editor.queryCommandSupported(pattern.cmd);
28383
+ }
28384
+ return true;
28385
+ }), getTextPatternsLookup(editor));
28307
28386
  const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
28308
28387
  editor.on('keydown', e => {
28309
- if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed()) {
28388
+ if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed() && editor.selection.isEditable()) {
28310
28389
  const patternSet = filterByTrigger(getPatternSet(), 'enter');
28311
28390
  const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
28312
28391
  if (hasPatterns && handleEnter(editor, patternSet)) {
@@ -28315,7 +28394,7 @@
28315
28394
  }
28316
28395
  }, true);
28317
28396
  editor.on('keydown', e => {
28318
- if (e.keyCode === 32 && editor.selection.isCollapsed()) {
28397
+ if (e.keyCode === 32 && editor.selection.isCollapsed() && editor.selection.isEditable()) {
28319
28398
  const patternSet = filterByTrigger(getPatternSet(), 'space');
28320
28399
  const hasPatterns = patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
28321
28400
  if (hasPatterns && handleBlockPatternOnSpace(editor, patternSet)) {
@@ -28324,7 +28403,7 @@
28324
28403
  }
28325
28404
  }, true);
28326
28405
  const handleInlineTrigger = () => {
28327
- if (editor.selection.isCollapsed()) {
28406
+ if (editor.selection.isCollapsed() && editor.selection.isEditable()) {
28328
28407
  const patternSet = filterByTrigger(getPatternSet(), 'space');
28329
28408
  const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns();
28330
28409
  if (hasPatterns) {
@@ -28772,6 +28851,7 @@
28772
28851
  allow_svg_data_urls: getOption('allow_svg_data_urls'),
28773
28852
  allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'),
28774
28853
  allow_script_urls: getOption('allow_script_urls'),
28854
+ allow_mathml_annotation_encodings: getOption('allow_mathml_annotation_encodings'),
28775
28855
  allow_unsafe_link_target: getOption('allow_unsafe_link_target'),
28776
28856
  convert_unsafe_embeds: getOption('convert_unsafe_embeds'),
28777
28857
  convert_fonts_to_spans: getOption('convert_fonts_to_spans'),
@@ -29054,7 +29134,7 @@
29054
29134
  body.disabled = true;
29055
29135
  editor.readonly = isReadOnly$1(editor);
29056
29136
  editor._editableRoot = hasEditableRoot$1(editor);
29057
- if (!editor.readonly && editor.hasEditableRoot()) {
29137
+ if (editor.hasEditableRoot()) {
29058
29138
  if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') {
29059
29139
  body.style.position = 'relative';
29060
29140
  }
@@ -29313,7 +29393,8 @@
29313
29393
  hide: Optional.from(api.hide).getOr(noop),
29314
29394
  isEnabled: Optional.from(api.isEnabled).getOr(always),
29315
29395
  setEnabled: state => {
29316
- if (!editor.mode.isReadOnly()) {
29396
+ const shouldSkip = state && editor.mode.get() === 'readonly';
29397
+ if (!shouldSkip) {
29317
29398
  Optional.from(api.setEnabled).each(f => f(state));
29318
29399
  }
29319
29400
  }
@@ -29526,10 +29607,8 @@
29526
29607
  const setEditableRoot = (editor, state) => {
29527
29608
  if (editor._editableRoot !== state) {
29528
29609
  editor._editableRoot = state;
29529
- if (!editor.readonly) {
29530
- editor.getBody().contentEditable = String(editor.hasEditableRoot());
29531
- editor.nodeChanged();
29532
- }
29610
+ editor.getBody().contentEditable = String(editor.hasEditableRoot());
29611
+ editor.nodeChanged();
29533
29612
  fireEditableRootStateChange(editor, state);
29534
29613
  }
29535
29614
  };
@@ -29970,6 +30049,9 @@
29970
30049
 
29971
30050
  const registerCommands$4 = editor => {
29972
30051
  const applyLinkToSelection = (_command, _ui, value) => {
30052
+ if (editor.mode.isReadOnly()) {
30053
+ return;
30054
+ }
29973
30055
  const linkDetails = isString(value) ? { href: value } : value;
29974
30056
  const anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
29975
30057
  if (isObject(linkDetails) && isString(linkDetails.href)) {
@@ -30007,6 +30089,9 @@
30007
30089
  return Optional.from(topParentBlock).map(SugarElement.fromDom);
30008
30090
  };
30009
30091
  const insert = (editor, before) => {
30092
+ if (editor.mode.isReadOnly()) {
30093
+ return;
30094
+ }
30010
30095
  const dom = editor.dom;
30011
30096
  const rng = editor.selection.getRng();
30012
30097
  const node = before ? editor.selection.getStart() : editor.selection.getEnd();
@@ -30211,7 +30296,6 @@
30211
30296
  }
30212
30297
  }
30213
30298
 
30214
- const internalContentEditableAttr = 'data-mce-contenteditable';
30215
30299
  const toggleClass = (elm, cls, state) => {
30216
30300
  if (has(elm, cls) && !state) {
30217
30301
  remove$6(elm, cls);
@@ -30228,18 +30312,6 @@
30228
30312
  const setContentEditable = (elm, state) => {
30229
30313
  elm.dom.contentEditable = state ? 'true' : 'false';
30230
30314
  };
30231
- const switchOffContentEditableTrue = elm => {
30232
- each$e(descendants(elm, '*[contenteditable="true"]'), elm => {
30233
- set$3(elm, internalContentEditableAttr, 'true');
30234
- setContentEditable(elm, false);
30235
- });
30236
- };
30237
- const switchOnContentEditableTrue = elm => {
30238
- each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => {
30239
- remove$9(elm, internalContentEditableAttr);
30240
- setContentEditable(elm, true);
30241
- });
30242
- };
30243
30315
  const removeFakeSelection = editor => {
30244
30316
  Optional.from(editor.selection.getNode()).each(elm => {
30245
30317
  elm.removeAttribute('data-mce-selected');
@@ -30248,60 +30320,42 @@
30248
30320
  const restoreFakeSelection = editor => {
30249
30321
  editor.selection.setRng(editor.selection.getRng());
30250
30322
  };
30323
+ const setCommonEditorCommands = (editor, state) => {
30324
+ setEditorCommandState(editor, 'StyleWithCSS', state);
30325
+ setEditorCommandState(editor, 'enableInlineTableEditing', state);
30326
+ setEditorCommandState(editor, 'enableObjectResizing', state);
30327
+ };
30328
+ const setEditorReadonly = editor => {
30329
+ editor.readonly = true;
30330
+ editor.selection.controlSelection.hideResizeRect();
30331
+ editor._selectionOverrides.hideFakeCaret();
30332
+ removeFakeSelection(editor);
30333
+ };
30334
+ const unsetEditorReadonly = (editor, body) => {
30335
+ editor.readonly = false;
30336
+ if (editor.hasEditableRoot()) {
30337
+ setContentEditable(body, true);
30338
+ }
30339
+ setCommonEditorCommands(editor, false);
30340
+ if (hasEditorOrUiFocus(editor)) {
30341
+ editor.focus();
30342
+ }
30343
+ restoreFakeSelection(editor);
30344
+ editor.nodeChanged();
30345
+ };
30251
30346
  const toggleReadOnly = (editor, state) => {
30252
30347
  const body = SugarElement.fromDom(editor.getBody());
30253
30348
  toggleClass(body, 'mce-content-readonly', state);
30254
30349
  if (state) {
30255
- editor.selection.controlSelection.hideResizeRect();
30256
- editor._selectionOverrides.hideFakeCaret();
30257
- removeFakeSelection(editor);
30258
- editor.readonly = true;
30259
- setContentEditable(body, false);
30260
- switchOffContentEditableTrue(body);
30261
- } else {
30262
- editor.readonly = false;
30350
+ setEditorReadonly(editor);
30263
30351
  if (editor.hasEditableRoot()) {
30264
30352
  setContentEditable(body, true);
30265
30353
  }
30266
- switchOnContentEditableTrue(body);
30267
- setEditorCommandState(editor, 'StyleWithCSS', false);
30268
- setEditorCommandState(editor, 'enableInlineTableEditing', false);
30269
- setEditorCommandState(editor, 'enableObjectResizing', false);
30270
- if (hasEditorOrUiFocus(editor)) {
30271
- editor.focus();
30272
- }
30273
- restoreFakeSelection(editor);
30274
- editor.nodeChanged();
30275
- }
30276
- };
30277
- const isReadOnly = editor => editor.readonly;
30278
- const registerFilters = editor => {
30279
- editor.parser.addAttributeFilter('contenteditable', nodes => {
30280
- if (isReadOnly(editor)) {
30281
- each$e(nodes, node => {
30282
- node.attr(internalContentEditableAttr, node.attr('contenteditable'));
30283
- node.attr('contenteditable', 'false');
30284
- });
30285
- }
30286
- });
30287
- editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => {
30288
- if (isReadOnly(editor)) {
30289
- each$e(nodes, node => {
30290
- node.attr('contenteditable', node.attr(internalContentEditableAttr));
30291
- });
30292
- }
30293
- });
30294
- editor.serializer.addTempAttr(internalContentEditableAttr);
30295
- };
30296
- const registerReadOnlyContentFilters = editor => {
30297
- if (editor.serializer) {
30298
- registerFilters(editor);
30299
30354
  } else {
30300
- editor.on('PreInit', () => {
30301
- registerFilters(editor);
30302
- });
30355
+ unsetEditorReadonly(editor, body);
30303
30356
  }
30304
30357
  };
30358
+ const isReadOnly = editor => editor.readonly;
30305
30359
  const isClickEvent = e => e.type === 'click';
30306
30360
  const allowedEvents = ['copy'];
30307
30361
  const isReadOnlyAllowedEvent = e => contains$2(allowedEvents, e.type);
@@ -30328,16 +30382,32 @@
30328
30382
  }
30329
30383
  };
30330
30384
  const registerReadOnlySelectionBlockers = editor => {
30331
- editor.on('ShowCaret', e => {
30385
+ editor.on('beforeinput paste cut dragend dragover draggesture dragdrop drop drag', e => {
30332
30386
  if (isReadOnly(editor)) {
30333
30387
  e.preventDefault();
30334
30388
  }
30335
30389
  });
30336
- editor.on('ObjectSelected', e => {
30337
- if (isReadOnly(editor)) {
30390
+ editor.on('BeforeExecCommand', e => {
30391
+ if ((e.command === 'Undo' || e.command === 'Redo') && isReadOnly(editor)) {
30338
30392
  e.preventDefault();
30339
30393
  }
30340
30394
  });
30395
+ editor.on('input', e => {
30396
+ if (!e.isComposing && isReadOnly(editor)) {
30397
+ const undoLevel = editor.undoManager.add();
30398
+ if (isNonNullable(undoLevel)) {
30399
+ editor.undoManager.undo();
30400
+ }
30401
+ }
30402
+ });
30403
+ editor.on('compositionend', () => {
30404
+ if (isReadOnly(editor)) {
30405
+ const undoLevel = editor.undoManager.add();
30406
+ if (isNonNullable(undoLevel)) {
30407
+ editor.undoManager.undo();
30408
+ }
30409
+ }
30410
+ });
30341
30411
  };
30342
30412
 
30343
30413
  const nativeEvents = Tools.makeMap('focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange ' + 'mouseout mouseenter mouseleave wheel keydown keypress keyup input beforeinput contextmenu dragstart dragend dragover ' + 'draggesture dragdrop drop drag submit ' + 'compositionstart compositionend compositionupdate touchstart touchmove touchend touchcancel', ' ');
@@ -30531,7 +30601,7 @@
30531
30601
  }
30532
30602
  return editor.getBody();
30533
30603
  };
30534
- const isListening = editor => !editor.hidden && !isReadOnly(editor);
30604
+ const isListening = editor => !editor.hidden;
30535
30605
  const fireEvent = (editor, eventName, e) => {
30536
30606
  if (isListening(editor)) {
30537
30607
  editor.dispatch(eventName, e);
@@ -30850,7 +30920,6 @@
30850
30920
  editorReadOnly: true
30851
30921
  }
30852
30922
  });
30853
- registerReadOnlyContentFilters(editor);
30854
30923
  registerReadOnlySelectionBlockers(editor);
30855
30924
  return {
30856
30925
  isReadOnly: () => isReadOnly(editor),
@@ -31026,6 +31095,7 @@
31026
31095
  const icons = {};
31027
31096
  const contextMenus = {};
31028
31097
  const contextToolbars = {};
31098
+ const contexts = {};
31029
31099
  const sidebars = {};
31030
31100
  const views = {};
31031
31101
  const add = (collection, type) => (name, spec) => {
@@ -31035,6 +31105,7 @@
31035
31105
  };
31036
31106
  };
31037
31107
  const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData;
31108
+ const addContext = (name, pred) => contexts[name.toLowerCase()] = pred;
31038
31109
  return {
31039
31110
  addButton: add(buttons, 'button'),
31040
31111
  addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'),
@@ -31051,6 +31122,7 @@
31051
31122
  addSidebar: add(sidebars, 'sidebar'),
31052
31123
  addView: add(views, 'views'),
31053
31124
  addIcon,
31125
+ addContext,
31054
31126
  getAll: () => ({
31055
31127
  buttons,
31056
31128
  menuItems,
@@ -31059,7 +31131,8 @@
31059
31131
  contextMenus,
31060
31132
  contextToolbars,
31061
31133
  sidebars,
31062
- views
31134
+ views,
31135
+ contexts
31063
31136
  })
31064
31137
  };
31065
31138
  };
@@ -31082,6 +31155,7 @@
31082
31155
  addGroupToolbarButton: bridge.addGroupToolbarButton,
31083
31156
  addToggleMenuItem: bridge.addToggleMenuItem,
31084
31157
  addView: bridge.addView,
31158
+ addContext: bridge.addContext,
31085
31159
  getAll: bridge.getAll
31086
31160
  };
31087
31161
  };
@@ -31518,8 +31592,8 @@
31518
31592
  documentBaseURL: null,
31519
31593
  suffix: null,
31520
31594
  majorVersion: '7',
31521
- minorVersion: '2.1',
31522
- releaseDate: '2024-07-03',
31595
+ minorVersion: '4.0',
31596
+ releaseDate: '2024-10-09',
31523
31597
  i18n: I18n,
31524
31598
  activeEditor: null,
31525
31599
  focusedEditor: null,