tinymce-rails 7.2.0 → 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 +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