tinymce-rails 7.2.1 → 7.3.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 (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