tinymce-rails 7.2.1 → 7.4.0

Sign up to get free protection for your applications and to get access to all the features.
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,