tinymce-rails 7.2.0 → 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 +84 -35
  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 +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 +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: a3d8e59d489555f3c9025c77f367daedc97aaa51c790a343ddbb43a6ea74fde3
4
- data.tar.gz: a2965c692e2763103b0896b82496f66e35151c7139e876e0ea440014bfa76aa6
3
+ metadata.gz: 3f2cff298fe1ce0fd108d0ebe03fe0dfd4952d2aaa0762649b29be1a1d4df3f9
4
+ data.tar.gz: a592e9e5d1d70c0ba1b0c06d02611236ec6120599991e4126409facc4cb410dc
5
5
  SHA512:
6
- metadata.gz: 2ee08355adcec31ef59e297505ff58a23c759e6dba194fd6385babb1b77e55ee68604654ff32f0f10204c547e4513f714fe1356f9628ac19f3e6c3220df539c5
7
- data.tar.gz: 1444057af973cd6781f81554a358507a6d062507fcfa399e59a5bb2be8a3d3dcfbf70ea81eceb704218115b70c60ad06651e5cdc21f14c9971a3053bb13ba743
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.0 (2024-06-19)
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();
@@ -28276,7 +28320,12 @@
28276
28320
  '?'
28277
28321
  ];
28278
28322
  const keyCodes = [32];
28279
- 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));
28280
28329
  const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
28281
28330
  editor.on('keydown', e => {
28282
28331
  if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed()) {
@@ -31491,8 +31540,8 @@
31491
31540
  documentBaseURL: null,
31492
31541
  suffix: null,
31493
31542
  majorVersion: '7',
31494
- minorVersion: '2.0',
31495
- releaseDate: '2024-06-19',
31543
+ minorVersion: '3.0',
31544
+ releaseDate: '2024-08-07',
31496
31545
  i18n: I18n,
31497
31546
  activeEditor: null,
31498
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
@@ -4,7 +4,8 @@ module TinyMCE
4
4
  attr_reader :file
5
5
 
6
6
  def self.load(manifest_path)
7
- JsonManifest.try(manifest_path, ".sprockets-manifest*.json") ||
7
+ PropshaftManifest.try(manifest_path) ||
8
+ JsonManifest.try(manifest_path, ".sprockets-manifest*.json") ||
8
9
  JsonManifest.try(manifest_path, "manifest*.json") ||
9
10
  JsonManifest.try(manifest_path) ||
10
11
  YamlManifest.try(manifest_path) ||
@@ -35,112 +36,9 @@ module TinyMCE
35
36
  end
36
37
  end
37
38
 
38
- class YamlManifest < AssetManifest
39
- def self.try(manifest_path)
40
- yaml_file = File.join(manifest_path, "manifest.yml")
41
- new(yaml_file) if File.exist?(yaml_file)
42
- end
43
-
44
- def initialize(file)
45
- @file = file
46
- @manifest = YAML.load_file(file)
47
- end
48
-
49
- def append(logical_path, file)
50
- assets[logical_path] = logical_path
51
- end
52
-
53
- def remove(logical_path)
54
- assets.delete(logical_path)
55
- end
56
-
57
- def remove_digest(logical_path)
58
- asset_path(logical_path) do |digested, logical_path|
59
- assets[logical_path] = logical_path
60
-
61
- yield digested, logical_path if block_given?
62
- end
63
- end
64
-
65
- def assets
66
- @manifest
67
- end
68
-
69
- def dump(io=nil)
70
- YAML.dump(@manifest, io)
71
- end
72
-
73
- def write
74
- File.open(@file, "wb") { |f| dump(f) }
75
- end
76
- end
77
-
78
- class JsonManifest < AssetManifest
79
- def self.try(manifest_path, pattern=nil)
80
- if pattern
81
- paths = Dir[File.join(manifest_path, pattern)]
82
- new(paths.first) if paths.any?
83
- elsif File.file?(manifest_path)
84
- new(manifest_path)
85
- end
86
- end
87
-
88
- def initialize(file)
89
- @file = file
90
- @manifest = JSON.parse(File.read(file))
91
- end
92
-
93
- def append(logical_path, file)
94
- stat = File.stat(file)
95
-
96
- assets[logical_path] = logical_path
97
- files[logical_path] = {
98
- "logical_path" => logical_path,
99
- "mtime" => stat.mtime.iso8601,
100
- "size" => stat.size,
101
- "digest" => nil
102
- }
103
- end
104
-
105
- def remove(logical_path)
106
- if digested = assets.delete(logical_path)
107
- files.delete(digested)
108
- end
109
- end
110
-
111
- def remove_digest(logical_path)
112
- asset_path(logical_path) do |digested, logical_path|
113
- assets[logical_path] = logical_path
114
- files[logical_path] = files.delete(digested).tap { |f| f["digest"] = nil }
115
-
116
- yield digested, logical_path if block_given?
117
- end
118
- end
119
-
120
- def assets
121
- @manifest["assets"]
122
- end
123
-
124
- def files
125
- @manifest["files"]
126
- end
127
-
128
- def dump
129
- JSON.generate(@manifest)
130
- end
131
-
132
- def write
133
- File.open(@file, "wb") { |f| f.write(dump) }
134
- end
135
- end
136
-
137
- class NullManifest < AssetManifest
138
- def append(*); end
139
- def remove(*); end
140
- def remove_digest(*); end
141
- def assets; {}; end
142
- def each(*); end
143
- def write; end
144
- end
39
+ require_relative "asset_manifest/json_manifest"
40
+ require_relative "asset_manifest/null_manifest"
41
+ require_relative "asset_manifest/propshaft_manifest"
42
+ require_relative "asset_manifest/yaml_manifest"
145
43
  end
146
44
  end
@@ -13,14 +13,27 @@ module TinyMCE::Rails
13
13
  # :copy - copies across the TinyMCE assets statically
14
14
  config.tinymce.install = :compile
15
15
 
16
+ # Set default attributes for script source tags (defaults to data-turbolinks-track="reload" for backwards compatibility)
17
+ config.tinymce.default_script_attributes = { "data-turbolinks-track" => "reload" }
18
+
16
19
  initializer "precompile", :group => :all do |app|
17
20
  if config.tinymce.install == :compile
18
21
  app.config.assets.precompile << "tinymce-rails.manifest.js" # Sprockets 4 manifest
19
22
  app.config.assets.precompile << "tinymce/*" # Sprockets 3
20
23
  end
21
24
 
22
- app.config.assets.precompile << "tinymce.js"
23
- end
25
+ app.config.assets.precompile << "tinymce.js" << "tinymce-jquery.js"
26
+ end if defined?(Sprockets)
27
+
28
+ initializer "propshaft" do |app|
29
+ config.assets.excluded_paths << root.join("app/assets/sprockets")
30
+
31
+ if config.assets.server
32
+ # Monkey-patch Propshaft::Asset to enable access
33
+ # of TinyMCE assets without a hash digest.
34
+ require_relative "propshaft/asset"
35
+ end
36
+ end if defined?(Propshaft)
24
37
 
25
38
  initializer "helper" do |app|
26
39
  ActiveSupport.on_load(:action_view) do