tinymce-rails 7.2.1 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -4
  3. data/app/assets/source/tinymce/tinymce.js +98 -76
  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 +1 -1
  20. data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
  22. data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
  23. data/vendor/assets/javascripts/tinymce/plugins/autosave/plugin.js +1 -1
  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 +1 -1
  32. data/vendor/assets/javascripts/tinymce/plugins/importcss/plugin.js +1 -1
  33. data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
  34. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
  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 +1 -1
  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 +1 -1
  45. data/vendor/assets/javascripts/tinymce/plugins/visualchars/plugin.js +1 -1
  46. data/vendor/assets/javascripts/tinymce/plugins/wordcount/plugin.js +1 -1
  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.js +2 -2
  95. metadata +9 -4
  96. /data/app/assets/{javascripts → sprockets}/tinymce/preinit.js.erb +0 -0
  97. /data/app/assets/{javascripts → sprockets}/tinymce.js +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ee5e9b71449a34d4aedddecdde6b1277984b25c1ee488a2329c7bf9ac17e8c6
4
- data.tar.gz: f7b1045d910db2562ed15b7a2e303a76399e98a0fcc3db4d4f8b648c0fecf360
3
+ metadata.gz: 3f2cff298fe1ce0fd108d0ebe03fe0dfd4952d2aaa0762649b29be1a1d4df3f9
4
+ data.tar.gz: a592e9e5d1d70c0ba1b0c06d02611236ec6120599991e4126409facc4cb410dc
5
5
  SHA512:
6
- metadata.gz: d09a0ebc460617da1fecea63297f6c3839ca6e703a149cd06e0e6cbd85c1898b2dbd6d3a66444c9854c7be8ce85bc664fcc6f0c946b0248b3977518b52ef1af7
7
- data.tar.gz: 33ead508c3782bc530b51bb1b1fb812f229026338930c57eaccc50c20fc1ae5e440715e730e1444f8495971710e586ae8b9fadecd1a17085e927d6d012969d71
6
+ metadata.gz: 4f0e2323551e3fd6d8dbf152121bda436bac579e380a079114ce6efa7192b30e71b6583a6995b355a5adc9744fbb4470b8ba8a93201b6568722d02f29e3a5981
7
+ data.tar.gz: 5e219df2c3e9014062ba1f1d464302010da46bd385a018fde27ba9b53750576c0fe98eeb5bf51cea5b820dd812e580e27857b0a2addf6baf9d291416b73ed9f3
data/README.md CHANGED
@@ -3,7 +3,7 @@ Rails Integration for TinyMCE
3
3
 
4
4
  The `tinymce-rails` gem integrates the [TinyMCE](https://www.tiny.cloud/) editor with the Rails asset pipeline.
5
5
 
6
- This gem is compatible with Rails 5.0 and higher.
6
+ This gem is compatible with Rails 5.1 and higher.
7
7
 
8
8
  This is the branch for **TinyMCE 7**.<br />
9
9
  Please see alternate branches for [TinyMCE 6](https://github.com/spohlenz/tinymce-rails/tree/tinymce-6), [TinyMCE 5](https://github.com/spohlenz/tinymce-rails/tree/tinymce-5), [TinyMCE 4](https://github.com/spohlenz/tinymce-rails/tree/tinymce-4) & [TinyMCE 3.5.x](https://github.com/spohlenz/tinymce-rails/tree/tinymce-3).
@@ -61,7 +61,7 @@ See the [TinyMCE 7 Documentation](https://www.tiny.cloud/docs/tinymce/7/) for a
61
61
 
62
62
  Use *one* of the following options to include TinyMCE assets.
63
63
 
64
- (1) Add to your application.js:
64
+ (1) Add to your application.js (Sprockets only):
65
65
 
66
66
  ```js
67
67
  //= require tinymce
@@ -70,10 +70,14 @@ Use *one* of the following options to include TinyMCE assets.
70
70
  or (2) add the script tag to your layout using the `tinymce_assets` helper:
71
71
 
72
72
  ```erb
73
- <%= tinymce_assets %>
74
- #=> <script type="text/javascript" src="/assets/tinymce.js">
73
+ <%= tinymce_assets data: { turbo_track: "reload" } %>
74
+ #=> <script type="text/javascript" src="/assets/tinymce.js" data-turbo-track="reload">
75
75
  ```
76
76
 
77
+ When using Propshaft, the `tinymce_assets` helper adds multiple script tags including the pre-init code (available via the `tinymce_preinit` helper), as well as `tinymce/tinymce.js` and `tinymce/rails.js`. You may prefer to selectively include these manually depending on your requirements.
78
+
79
+ For Sprockets, these are bundled together into one script tag.
80
+
77
81
 
78
82
  **4. Initialize TinyMCE**
79
83
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TinyMCE version 7.2.1 (2024-07-03)
2
+ * TinyMCE version 7.3.0 (2024-08-07)
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) {
@@ -10022,32 +10021,32 @@
10022
10021
  const SimRange = { create: create$9 };
10023
10022
 
10024
10023
  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 => {
10024
+ var _a;
10025
+ return Optional.from((_a = doc.caretPositionFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)).bind(pos => {
10027
10026
  if (pos.offsetNode === null) {
10028
10027
  return Optional.none();
10029
10028
  }
10030
- const r = doc.dom.createRange();
10029
+ const r = doc.createRange();
10031
10030
  r.setStart(pos.offsetNode, pos.offset);
10032
10031
  r.collapse();
10033
10032
  return Optional.some(r);
10034
10033
  });
10035
10034
  };
10036
10035
  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));
10036
+ var _a;
10037
+ return Optional.from((_a = doc.caretRangeFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y));
10039
10038
  };
10040
- const availableSearch = (() => {
10041
- if (document.caretPositionFromPoint) {
10042
- return caretPositionFromPoint;
10043
- } else if (document.caretRangeFromPoint) {
10044
- return caretRangeFromPoint;
10039
+ const availableSearch = (doc, x, y) => {
10040
+ if (doc.caretPositionFromPoint) {
10041
+ return caretPositionFromPoint(doc, x, y);
10042
+ } else if (doc.caretRangeFromPoint) {
10043
+ return caretRangeFromPoint(doc, x, y);
10045
10044
  } else {
10046
- return Optional.none;
10045
+ return Optional.none();
10047
10046
  }
10048
- })();
10047
+ };
10049
10048
  const fromPoint$1 = (win, x, y) => {
10050
- const doc = SugarElement.fromDom(win.document);
10049
+ const doc = win.document;
10051
10050
  return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
10052
10051
  };
10053
10052
 
@@ -10211,7 +10210,7 @@
10211
10210
  var _a;
10212
10211
  return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
10213
10212
  };
10214
- const hasContentEditableFalseParent = (root, node) => {
10213
+ const hasContentEditableFalseParent$1 = (root, node) => {
10215
10214
  let currentNode = node;
10216
10215
  while (currentNode && currentNode !== root) {
10217
10216
  if (isContentEditableFalse$b(currentNode)) {
@@ -10296,7 +10295,7 @@
10296
10295
  if (!collapsed && container === body.lastChild && isTable$2(container)) {
10297
10296
  return Optional.none();
10298
10297
  }
10299
- if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
10298
+ if (hasContentEditableFalseParent$1(body, container) || isCaretContainer$2(container)) {
10300
10299
  return Optional.none();
10301
10300
  }
10302
10301
  if (isDetails(container)) {
@@ -10924,6 +10923,7 @@
10924
10923
  };
10925
10924
 
10926
10925
  const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
10926
+ const hasContentEditableFalseParent = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'false') !== null;
10927
10927
  const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
10928
10928
  const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
10929
10929
  if (isTableSection(node)) {
@@ -10980,6 +10980,9 @@
10980
10980
  }
10981
10981
  const contentEditableHost = getContentEditableHost(editor, selection.getNode());
10982
10982
  if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
10983
+ if (!hasContentEditableFalseParent(editor, contentEditableHost)) {
10984
+ focusBody(body);
10985
+ }
10983
10986
  focusBody(contentEditableHost);
10984
10987
  if (!editor.hasEditableRoot()) {
10985
10988
  restoreBookmark(editor);
@@ -11997,7 +12000,7 @@
11997
12000
  return false;
11998
12001
  }
11999
12002
  };
12000
- const normalizeNbsps = (root, pos, schema) => {
12003
+ const normalizeNbsps$1 = (root, pos, schema) => {
12001
12004
  const container = pos.container();
12002
12005
  if (!isText$b(container)) {
12003
12006
  return Optional.none();
@@ -12015,7 +12018,7 @@
12015
12018
  const normalizeNbspsInEditor = editor => {
12016
12019
  const root = SugarElement.fromDom(editor.getBody());
12017
12020
  if (editor.selection.isCollapsed()) {
12018
- normalizeNbsps(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
12021
+ normalizeNbsps$1(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
12019
12022
  editor.selection.setRng(pos.toRange());
12020
12023
  });
12021
12024
  }
@@ -13663,6 +13666,35 @@
13663
13666
  return Optional.none();
13664
13667
  }
13665
13668
  };
13669
+ const normalizeNbsps = node => set(node, get$3(node).replace(new RegExp(`${ nbsp }$`), ' '));
13670
+ const normalizeNbspsBetween = (editor, caretContainer) => {
13671
+ const handler = () => {
13672
+ if (caretContainer !== null && !editor.dom.isEmpty(caretContainer)) {
13673
+ prevSibling(SugarElement.fromDom(caretContainer)).each(node => {
13674
+ if (isText$c(node)) {
13675
+ normalizeNbsps(node);
13676
+ } else {
13677
+ descendant$2(node, e => isText$c(e)).each(textNode => {
13678
+ if (isText$c(textNode)) {
13679
+ normalizeNbsps(textNode);
13680
+ }
13681
+ });
13682
+ }
13683
+ });
13684
+ }
13685
+ };
13686
+ editor.once('input', e => {
13687
+ if (e.data && !isWhiteSpace(e.data)) {
13688
+ if (!e.isComposing) {
13689
+ handler();
13690
+ } else {
13691
+ editor.once('compositionend', () => {
13692
+ handler();
13693
+ });
13694
+ }
13695
+ }
13696
+ });
13697
+ };
13666
13698
  const applyCaretFormat = (editor, name, vars) => {
13667
13699
  let caretContainer;
13668
13700
  const selection = editor.selection;
@@ -13690,6 +13722,7 @@
13690
13722
  textNode = caretContainer.firstChild;
13691
13723
  selectionRng.insertNode(caretContainer);
13692
13724
  offset = 1;
13725
+ normalizeNbspsBetween(editor, caretContainer);
13693
13726
  editor.formatter.apply(name, vars, caretContainer);
13694
13727
  } else {
13695
13728
  editor.formatter.apply(name, vars, caretContainer);
@@ -13753,6 +13786,7 @@
13753
13786
  removeCaretContainerNode(editor, caretContainer, isNonNullable(caretContainer));
13754
13787
  }
13755
13788
  selection.setCursorLocation(caretTextNode, 1);
13789
+ normalizeNbspsBetween(editor, newCaretContainer);
13756
13790
  if (dom.isEmpty(formatNode)) {
13757
13791
  dom.remove(formatNode);
13758
13792
  }
@@ -17363,6 +17397,8 @@
17363
17397
  }
17364
17398
  if (text.length === 0) {
17365
17399
  node.remove();
17400
+ } else if (text === ' ' && node.prev && node.prev.type === COMMENT && node.next && node.next.type === COMMENT) {
17401
+ node.remove();
17366
17402
  } else {
17367
17403
  node.value = text;
17368
17404
  }
@@ -17432,8 +17468,16 @@
17432
17468
  const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
17433
17469
  const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
17434
17470
  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;
17471
+ const makeWrap = () => {
17472
+ if (format === 'xhtml') {
17473
+ return `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>`;
17474
+ } else if (/^[\s]*<head/i.test(html) || /^[\s]*<html/i.test(html) || /^[\s]*<!DOCTYPE/i.test(html)) {
17475
+ return `<html>${ content }</html>`;
17476
+ } else {
17477
+ return `<body>${ content }</body>`;
17478
+ }
17479
+ };
17480
+ const body = parser.parseFromString(makeWrap(), mimeType).body;
17437
17481
  sanitizer.sanitizeHtmlElement(body, mimeType);
17438
17482
  return isSpecialRoot ? body.firstChild : body;
17439
17483
  };
@@ -19553,7 +19597,7 @@
19553
19597
  }
19554
19598
  reposition();
19555
19599
  });
19556
- editor.on('show ResizeEditor NodeChange', () => {
19600
+ editor.on('show ResizeEditor ResizeWindow NodeChange ToggleView FullscreenStateChanged', () => {
19557
19601
  requestAnimationFrame(reposition);
19558
19602
  });
19559
19603
  editor.on('remove', () => {
@@ -19858,7 +19902,7 @@
19858
19902
  let count = 0;
19859
19903
  const seed = () => {
19860
19904
  const rnd = () => {
19861
- return Math.round(Math.random() * 4294967295).toString(36);
19905
+ return Math.round(random() * 4294967295).toString(36);
19862
19906
  };
19863
19907
  const now = new Date().getTime();
19864
19908
  return 's' + now.toString(36) + rnd() + rnd() + rnd();
@@ -21304,26 +21348,12 @@
21304
21348
  };
21305
21349
  const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none();
21306
21350
 
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;
21351
+ const getChildrenUntilBlockBoundary = (block, schema) => {
21352
+ const children = children$1(block);
21353
+ return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index));
21314
21354
  };
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
- }
21324
- };
21325
- const extractChildren = (toBlock, fromBlock, schema, forwardDelete, extractsiblingsIfNested) => {
21326
- const children = getChildrenUntilBlockBoundary(toBlock, fromBlock, schema, forwardDelete, extractsiblingsIfNested);
21355
+ const extractChildren = (block, schema) => {
21356
+ const children = getChildrenUntilBlockBoundary(block, schema);
21327
21357
  each$e(children, remove$4);
21328
21358
  return children;
21329
21359
  };
@@ -21332,7 +21362,7 @@
21332
21362
  return find$2(parents.reverse(), element => isEmpty$2(schema, element)).each(remove$4);
21333
21363
  };
21334
21364
  const isEmptyBefore = (schema, el) => filter$5(prevSiblings(el), el => !isEmpty$2(schema, el)).length === 0;
21335
- const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, forward, insertionPoint) => {
21365
+ const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, insertionPoint) => {
21336
21366
  if (isEmpty$2(schema, toBlock)) {
21337
21367
  fillWithPaddingBr(toBlock);
21338
21368
  return firstPositionIn(toBlock.dom);
@@ -21341,14 +21371,14 @@
21341
21371
  before$3(insertionPoint, SugarElement.fromTag('br'));
21342
21372
  }
21343
21373
  const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
21344
- each$e(extractChildren(toBlock, fromBlock, schema, forward, false), child => {
21374
+ each$e(extractChildren(fromBlock, schema), child => {
21345
21375
  before$3(insertionPoint, child);
21346
21376
  });
21347
21377
  removeEmptyRoot(schema, rootNode, fromBlock);
21348
21378
  return position;
21349
21379
  };
21350
21380
  const isInline = (schema, node) => schema.isInline(name(node));
21351
- const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema, forwardDelete) => {
21381
+ const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema) => {
21352
21382
  if (isEmpty$2(schema, toBlock)) {
21353
21383
  if (isEmpty$2(schema, fromBlock)) {
21354
21384
  const getInlineToBlockDescendants = el => {
@@ -21366,12 +21396,8 @@
21366
21396
  return firstPositionIn(fromBlock.dom);
21367
21397
  }
21368
21398
  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
- }
21399
+ each$e(extractChildren(fromBlock, schema), child => {
21400
+ append$1(toBlock, child);
21375
21401
  });
21376
21402
  removeEmptyRoot(schema, rootNode, fromBlock);
21377
21403
  return position;
@@ -21384,26 +21410,17 @@
21384
21410
  const trimBr = (first, block) => {
21385
21411
  positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$4);
21386
21412
  };
21387
- const mergeBlockInto = (rootNode, fromBlock, toBlock, schema, forward) => {
21413
+ const mergeBlockInto = (rootNode, fromBlock, toBlock, schema) => {
21388
21414
  trimBr(true, fromBlock);
21389
21415
  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);
21416
+ return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema));
21401
21417
  };
21418
+ const mergeBlocks = (rootNode, forward, block1, block2, schema) => forward ? mergeBlockInto(rootNode, block2, block1, schema) : mergeBlockInto(rootNode, block1, block2, schema);
21402
21419
 
21403
21420
  const backspaceDelete$a = (editor, forward) => {
21404
21421
  const rootNode = SugarElement.fromDom(editor.getBody());
21405
21422
  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 => {
21423
+ mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema).each(pos => {
21407
21424
  editor.selection.setRng(pos.toRange());
21408
21425
  });
21409
21426
  });
@@ -28303,7 +28320,12 @@
28303
28320
  '?'
28304
28321
  ];
28305
28322
  const keyCodes = [32];
28306
- const getPatternSet = () => createPatternSet(getTextPatterns(editor), getTextPatternsLookup(editor));
28323
+ const getPatternSet = () => createPatternSet(getTextPatterns(editor).filter(pattern => {
28324
+ if (pattern.type === 'inline-command' || pattern.type === 'block-command') {
28325
+ return editor.queryCommandSupported(pattern.cmd);
28326
+ }
28327
+ return true;
28328
+ }), getTextPatternsLookup(editor));
28307
28329
  const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
28308
28330
  editor.on('keydown', e => {
28309
28331
  if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed()) {
@@ -31518,8 +31540,8 @@
31518
31540
  documentBaseURL: null,
31519
31541
  suffix: null,
31520
31542
  majorVersion: '7',
31521
- minorVersion: '2.1',
31522
- releaseDate: '2024-07-03',
31543
+ minorVersion: '3.0',
31544
+ releaseDate: '2024-08-07',
31523
31545
  i18n: I18n,
31524
31546
  activeEditor: null,
31525
31547
  focusedEditor: null,
@@ -1,4 +1,4 @@
1
- require "tinymce/rails/asset_installer/copy"
1
+ require_relative "copy"
2
2
 
3
3
  module TinyMCE
4
4
  module Rails
@@ -1,8 +1,8 @@
1
- require "tinymce/rails/asset_manifest"
1
+ require_relative "asset_manifest"
2
2
 
3
- require "tinymce/rails/asset_installer/copy"
4
- require "tinymce/rails/asset_installer/copy_no_preserve"
5
- require "tinymce/rails/asset_installer/compile"
3
+ require_relative "asset_installer/copy"
4
+ require_relative "asset_installer/copy_no_preserve"
5
+ require_relative "asset_installer/compile"
6
6
 
7
7
  module TinyMCE
8
8
  module Rails
@@ -0,0 +1,62 @@
1
+ module TinyMCE
2
+ module Rails
3
+ class JsonManifest < AssetManifest
4
+ def self.try(manifest_path, pattern=nil)
5
+ if pattern
6
+ paths = Dir[File.join(manifest_path, pattern)]
7
+ new(paths.first) if paths.any?
8
+ elsif File.file?(manifest_path)
9
+ new(manifest_path)
10
+ end
11
+ end
12
+
13
+ def initialize(file)
14
+ @file = file
15
+ @manifest = JSON.parse(File.read(file))
16
+ end
17
+
18
+ def append(logical_path, file)
19
+ stat = File.stat(file)
20
+
21
+ assets[logical_path] = logical_path
22
+ files[logical_path] = {
23
+ "logical_path" => logical_path,
24
+ "mtime" => stat.mtime.iso8601,
25
+ "size" => stat.size,
26
+ "digest" => nil
27
+ }
28
+ end
29
+
30
+ def remove(logical_path)
31
+ if digested = assets.delete(logical_path)
32
+ files.delete(digested)
33
+ end
34
+ end
35
+
36
+ def remove_digest(logical_path)
37
+ asset_path(logical_path) do |digested, logical_path|
38
+ assets[logical_path] = logical_path
39
+ files[logical_path] = files.delete(digested).tap { |f| f["digest"] = nil }
40
+
41
+ yield digested, logical_path if block_given?
42
+ end
43
+ end
44
+
45
+ def assets
46
+ @manifest["assets"]
47
+ end
48
+
49
+ def files
50
+ @manifest["files"]
51
+ end
52
+
53
+ def dump
54
+ JSON.generate(@manifest)
55
+ end
56
+
57
+ def write
58
+ File.open(@file, "wb") { |f| f.write(dump) }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,12 @@
1
+ module TinyMCE
2
+ module Rails
3
+ class NullManifest < AssetManifest
4
+ def append(*); end
5
+ def remove(*); end
6
+ def remove_digest(*); end
7
+ def assets; {}; end
8
+ def each(*); end
9
+ def write; end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,43 @@
1
+ module TinyMCE
2
+ module Rails
3
+ class PropshaftManifest < AssetManifest
4
+ def self.try(manifest_path)
5
+ json_file = File.join(manifest_path, ".manifest.json")
6
+ new(json_file) if File.exist?(json_file)
7
+ end
8
+
9
+ def initialize(file)
10
+ @file = file
11
+ @manifest = JSON.parse(File.read(file))
12
+ end
13
+
14
+ def append(logical_path, file)
15
+ assets[logical_path] = logical_path
16
+ end
17
+
18
+ def remove(logical_path)
19
+ assets.delete(logical_path)
20
+ end
21
+
22
+ def remove_digest(logical_path)
23
+ asset_path(logical_path) do |digested, logical_path|
24
+ assets[logical_path] = logical_path
25
+
26
+ yield digested, logical_path if block_given?
27
+ end
28
+ end
29
+
30
+ def assets
31
+ @manifest
32
+ end
33
+
34
+ def dump
35
+ JSON.generate(@manifest)
36
+ end
37
+
38
+ def write
39
+ File.open(@file, "wb") { |f| f.write(dump) }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ module TinyMCE
2
+ module Rails
3
+ class YamlManifest < AssetManifest
4
+ def self.try(manifest_path)
5
+ yaml_file = File.join(manifest_path, "manifest.yml")
6
+ new(yaml_file) if File.exist?(yaml_file)
7
+ end
8
+
9
+ def initialize(file)
10
+ @file = file
11
+ @manifest = YAML.load_file(file)
12
+ end
13
+
14
+ def append(logical_path, file)
15
+ assets[logical_path] = logical_path
16
+ end
17
+
18
+ def remove(logical_path)
19
+ assets.delete(logical_path)
20
+ end
21
+
22
+ def remove_digest(logical_path)
23
+ asset_path(logical_path) do |digested, logical_path|
24
+ assets[logical_path] = logical_path
25
+
26
+ yield digested, logical_path if block_given?
27
+ end
28
+ end
29
+
30
+ def assets
31
+ @manifest
32
+ end
33
+
34
+ def dump(io=nil)
35
+ YAML.dump(@manifest, io)
36
+ end
37
+
38
+ def write
39
+ File.open(@file, "wb") { |f| dump(f) }
40
+ end
41
+ end
42
+ end
43
+ end