@themarioga/grid-editor 6.0.0-beta.5 → 7.0.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 (147) hide show
  1. package/AUTO_SAVE.md +2 -2
  2. package/BUILDING.md +45 -29
  3. package/CHANGELOG.md +54 -0
  4. package/README.md +140 -89
  5. package/UPGRADING.md +146 -2
  6. package/dist/grideditor.bundle.min.js +14 -0
  7. package/dist/grideditor.d.ts +335 -0
  8. package/dist/grideditor.esm.js +3977 -0
  9. package/dist/grideditor.jquery.js +253 -0
  10. package/dist/grideditor.jquery.min.js +1 -0
  11. package/dist/grideditor.jquery.min.js.map +7 -0
  12. package/dist/grideditor.js +3983 -0
  13. package/dist/grideditor.min.js +6 -0
  14. package/dist/grideditor.min.js.map +7 -0
  15. package/dist/locales/grideditor.es.esm.js +158 -0
  16. package/dist/locales/grideditor.es.js +164 -170
  17. package/dist/locales/grideditor.es.min.js +6 -2
  18. package/dist/locales/grideditor.es.min.js.map +7 -1
  19. package/dist/plugins/grideditor.accordion.esm.js +294 -0
  20. package/dist/plugins/grideditor.accordion.js +286 -180
  21. package/dist/plugins/grideditor.accordion.min.js +1 -2
  22. package/dist/plugins/grideditor.accordion.min.js.map +7 -1
  23. package/dist/plugins/grideditor.alignment.esm.js +55 -0
  24. package/dist/plugins/grideditor.alignment.js +58 -77
  25. package/dist/plugins/grideditor.alignment.min.js +1 -2
  26. package/dist/plugins/grideditor.alignment.min.js.map +7 -1
  27. package/dist/plugins/grideditor.card.esm.js +73 -0
  28. package/dist/plugins/grideditor.card.js +74 -64
  29. package/dist/plugins/grideditor.card.min.js +1 -2
  30. package/dist/plugins/grideditor.card.min.js.map +7 -1
  31. package/dist/plugins/grideditor.ckeditor.esm.js +500 -0
  32. package/dist/plugins/grideditor.ckeditor.js +482 -493
  33. package/dist/plugins/grideditor.ckeditor.min.js +1 -2
  34. package/dist/plugins/grideditor.ckeditor.min.js.map +7 -1
  35. package/dist/plugins/grideditor.clipboard.esm.js +326 -0
  36. package/dist/plugins/grideditor.clipboard.js +298 -235
  37. package/dist/plugins/grideditor.clipboard.min.js +1 -2
  38. package/dist/plugins/grideditor.clipboard.min.js.map +7 -1
  39. package/dist/plugins/grideditor.codemirror-inline.esm.js +205 -0
  40. package/dist/plugins/grideditor.codemirror-inline.js +188 -168
  41. package/dist/plugins/grideditor.codemirror-inline.min.js +1 -2
  42. package/dist/plugins/grideditor.codemirror-inline.min.js.map +7 -1
  43. package/dist/plugins/grideditor.codemirror.esm.js +63 -0
  44. package/dist/plugins/grideditor.codemirror.js +60 -71
  45. package/dist/plugins/grideditor.codemirror.min.js +1 -2
  46. package/dist/plugins/grideditor.codemirror.min.js.map +7 -1
  47. package/dist/plugins/grideditor.elements.esm.js +271 -0
  48. package/dist/plugins/grideditor.elements.js +256 -149
  49. package/dist/plugins/grideditor.elements.min.js +1 -2
  50. package/dist/plugins/grideditor.elements.min.js.map +7 -1
  51. package/dist/plugins/grideditor.float.esm.js +34 -0
  52. package/dist/plugins/grideditor.float.js +37 -52
  53. package/dist/plugins/grideditor.float.min.js +1 -2
  54. package/dist/plugins/grideditor.float.min.js.map +7 -1
  55. package/dist/plugins/grideditor.gutters.esm.js +143 -0
  56. package/dist/plugins/grideditor.gutters.js +134 -131
  57. package/dist/plugins/grideditor.gutters.min.js +1 -2
  58. package/dist/plugins/grideditor.gutters.min.js.map +7 -1
  59. package/dist/plugins/grideditor.order.esm.js +189 -0
  60. package/dist/plugins/grideditor.order.js +170 -182
  61. package/dist/plugins/grideditor.order.min.js +1 -2
  62. package/dist/plugins/grideditor.order.min.js.map +7 -1
  63. package/dist/plugins/grideditor.popup.esm.js +187 -0
  64. package/dist/plugins/grideditor.popup.js +183 -134
  65. package/dist/plugins/grideditor.popup.min.js +1 -2
  66. package/dist/plugins/grideditor.popup.min.js.map +7 -1
  67. package/dist/plugins/grideditor.sections.esm.js +271 -0
  68. package/dist/plugins/grideditor.sections.js +250 -173
  69. package/dist/plugins/grideditor.sections.min.js +1 -2
  70. package/dist/plugins/grideditor.sections.min.js.map +7 -1
  71. package/dist/plugins/grideditor.spacing.esm.js +318 -0
  72. package/dist/plugins/grideditor.spacing.js +296 -272
  73. package/dist/plugins/grideditor.spacing.min.js +1 -2
  74. package/dist/plugins/grideditor.spacing.min.js.map +7 -1
  75. package/dist/plugins/grideditor.summernote.esm.js +509 -0
  76. package/dist/plugins/grideditor.summernote.js +491 -471
  77. package/dist/plugins/grideditor.summernote.min.js +1 -2
  78. package/dist/plugins/grideditor.summernote.min.js.map +7 -1
  79. package/dist/plugins/grideditor.tabs.esm.js +237 -0
  80. package/dist/plugins/grideditor.tabs.js +233 -139
  81. package/dist/plugins/grideditor.tabs.min.js +1 -2
  82. package/dist/plugins/grideditor.tabs.min.js.map +7 -1
  83. package/dist/plugins/grideditor.textalign.esm.js +40 -0
  84. package/dist/plugins/grideditor.textalign.js +43 -56
  85. package/dist/plugins/grideditor.textalign.min.js +1 -2
  86. package/dist/plugins/grideditor.textalign.min.js.map +7 -1
  87. package/dist/plugins/grideditor.tinymce.esm.js +519 -0
  88. package/dist/plugins/grideditor.tinymce.js +500 -534
  89. package/dist/plugins/grideditor.tinymce.min.js +1 -2
  90. package/dist/plugins/grideditor.tinymce.min.js.map +7 -1
  91. package/dist/plugins/grideditor.visibility.esm.js +158 -0
  92. package/dist/plugins/grideditor.visibility.js +140 -149
  93. package/dist/plugins/grideditor.visibility.min.js +1 -2
  94. package/dist/plugins/grideditor.visibility.min.js.map +7 -1
  95. package/docs/events.md +47 -21
  96. package/docs/locale-keys.md +7 -4
  97. package/docs/plugins.md +49 -27
  98. package/example/adapter.html +112 -0
  99. package/example/attributes.html +85 -61
  100. package/example/autocols.html +9 -9
  101. package/example/autosave.html +13 -14
  102. package/example/basic.html +4 -5
  103. package/example/breakpoints.html +5 -6
  104. package/example/ckeditor.html +4 -5
  105. package/example/clipboard.html +11 -10
  106. package/example/codemirror.html +9 -7
  107. package/example/containers.html +7 -8
  108. package/example/custom_editor.html +53 -34
  109. package/example/elements.html +10 -11
  110. package/example/index.html +16 -2
  111. package/example/locale.html +6 -7
  112. package/example/plugins.html +44 -29
  113. package/example/summernote.html +6 -5
  114. package/example/utilities.html +17 -13
  115. package/example/wrap_content.html +9 -9
  116. package/package.json +43 -12
  117. package/src/js/dom.js +401 -0
  118. package/src/js/grideditor.classic.js +16 -0
  119. package/src/js/grideditor.jquery.js +325 -0
  120. package/src/js/{jquery.grideditor.js → grideditor.js} +1284 -1124
  121. package/src/js/locales/grideditor.es.js +163 -158
  122. package/src/js/plugins/grideditor.accordion.js +97 -77
  123. package/src/js/plugins/grideditor.alignment.js +5 -7
  124. package/src/js/plugins/grideditor.card.js +23 -23
  125. package/src/js/plugins/grideditor.ckeditor.js +107 -106
  126. package/src/js/plugins/grideditor.clipboard.js +49 -37
  127. package/src/js/plugins/grideditor.codemirror-inline.js +50 -37
  128. package/src/js/plugins/grideditor.codemirror.js +9 -10
  129. package/src/js/plugins/grideditor.elements.js +57 -33
  130. package/src/js/plugins/grideditor.float.js +4 -6
  131. package/src/js/plugins/grideditor.gutters.js +20 -15
  132. package/src/js/plugins/grideditor.order.js +28 -25
  133. package/src/js/plugins/grideditor.popup.js +63 -51
  134. package/src/js/plugins/grideditor.sections.js +39 -32
  135. package/src/js/plugins/grideditor.spacing.js +42 -45
  136. package/src/js/plugins/grideditor.summernote.js +112 -76
  137. package/src/js/plugins/grideditor.tabs.js +65 -57
  138. package/src/js/plugins/grideditor.textalign.js +4 -6
  139. package/src/js/plugins/grideditor.tinymce.js +147 -139
  140. package/src/js/plugins/grideditor.visibility.js +24 -25
  141. package/src/js/register.js +18 -0
  142. package/src/js/text/grideditor.text.js +81 -106
  143. package/types/grideditor.d.ts +335 -0
  144. package/dist/jquery.grideditor.bundle.min.js +0 -10
  145. package/dist/jquery.grideditor.js +0 -4927
  146. package/dist/jquery.grideditor.min.js +0 -2
  147. package/dist/jquery.grideditor.min.js.map +0 -1
@@ -1,515 +1,504 @@
1
- /**
2
- * Text for grid-editor: what the text editor plugins share.
3
- *
4
- * Not a file a page loads. The build puts it at the top of each text editor
5
- * plugin - grideditor.tinymce.js, grideditor.ckeditor.js,
6
- * grideditor.summernote.js - and whichever of them loads first installs it:
7
- * a page with two editors has one of these.
8
- *
9
- * It is a feature plugin, `text`, that the `plugins` setting does not choose
10
- * (content_types does), and it is everything a text is to the editor: the
11
- * text block's drawer, the Text buttons in the toolbar and the Add text tool
12
- * in each column, createText, opening an editor on a click and closing it
13
- * again with the host's attributes put back, and making the host's plain
14
- * content a text through the core's `textTypes` hook.
15
- *
16
- * Each editor registers under $.fn.gridEditor.texts, which is this file's own
17
- * registry and not a contract: an editor of a host's own is a feature plugin
18
- * of its own, as example/custom_editor.html shows.
19
- */
20
- (function($) {
21
-
22
- if ($.fn.gridEditor.features.text) { return; }
23
-
24
- $.extend($.fn.gridEditor.locales.en, {
25
- 'tool.add_text': 'Add text',
26
- 'tool.add_text_type': 'Add {editor} text',
27
- 'text.add': 'Text',
28
- 'text.add_type': 'Text ({editor})',
29
- 'panel.editor': 'Editor',
30
- 'panel.kind_text': 'Text',
1
+ (() => {
2
+ // src/js/register.js
3
+ var GridEditor = window.GridEditor;
4
+ if (!GridEditor || typeof GridEditor.get !== "function") {
5
+ throw new Error("grid-editor: load grideditor.js (or grideditor.bundle.min.js) before its plugins, its locales and grideditor.jquery.js");
6
+ }
7
+
8
+ // src/js/dom.js
9
+ function all(root, selector) {
10
+ return root ? Array.prototype.slice.call(root.querySelectorAll(selector)) : [];
11
+ }
12
+ function children(node, selector) {
13
+ if (!node) {
14
+ return [];
15
+ }
16
+ return Array.prototype.filter.call(node.children, function(each) {
17
+ return !selector || each.matches(selector);
31
18
  });
32
-
33
- /** The text editors, by the content type each edits. */
34
- $.fn.gridEditor.texts = $.fn.gridEditor.texts || {};
35
-
36
- /** What a text editor puts on a content area while it is open, whenever it likes. */
37
- var EDITOR_CLASS = /^(mce-|cke|note-)|^(active|ge-rte-active)$/;
38
- var EDITOR_ATTRIBUTE = /^(data-mce-|contenteditable$|spellcheck$)/;
39
-
40
- function attributesOf(element) {
41
- var found = {};
42
- $.each($.makeArray(element.attributes), function(i, attribute) {
43
- found[attribute.name] = attribute.value;
44
- });
45
- return found;
19
+ }
20
+ function child(node, selector) {
21
+ return children(node, selector)[0] || null;
22
+ }
23
+ function closest(node, selector, stopAt) {
24
+ var found = node && node.nodeType === 1 ? node.closest(selector) : null;
25
+ if (found && stopAt && found !== stopAt && !stopAt.contains(found)) {
26
+ return null;
46
27
  }
47
-
48
- function classesIn(value) {
49
- return (value || '').split(/\s+/).filter(function(name) {
50
- return name !== '' && !EDITOR_CLASS.test(name);
51
- });
28
+ return found;
29
+ }
30
+ function element(tag, attributes, text) {
31
+ var node = document.createElement(tag);
32
+ Object.keys(attributes || {}).forEach(function(name) {
33
+ var value = attributes[name];
34
+ if (value !== null && value !== void 0 && value !== false) {
35
+ node.setAttribute(name, value);
36
+ }
37
+ });
38
+ if (text !== void 0 && text !== null) {
39
+ node.textContent = text;
52
40
  }
53
-
54
- /** The host's markup, with what changed from `ready` to `open` played back onto it. */
55
- function restoreAttributes(block, before, ready, open) {
56
- var result = $.extend({}, before);
57
-
58
- $.each($.extend({}, ready, open), function(name) {
59
- if (name === 'class' || EDITOR_ATTRIBUTE.test(name) || ready[name] === open[name]) { return; }
60
-
61
- if (open[name] === undefined) {
62
- delete result[name];
63
- } else {
64
- result[name] = open[name];
65
- }
66
- });
67
-
68
- var readyClasses = classesIn(ready['class']);
69
- var openClasses = classesIn(open['class']);
70
- var classes = classesIn(before['class']).filter(function(name) {
71
- return openClasses.indexOf(name) !== -1 || readyClasses.indexOf(name) === -1;
72
- });
73
- openClasses.forEach(function(name) {
74
- if (readyClasses.indexOf(name) === -1 && classes.indexOf(name) === -1) { classes.push(name); }
75
- });
76
-
77
- // In the host's order, class where it was: getHtml should not
78
- // shuffle a node's attributes because it was edited
79
- if (classes.length) { result['class'] = classes.join(' '); } else { delete result['class']; }
80
-
81
- $.each(attributesOf(block[0]), function(name) { block.removeAttr(name); });
82
- $.each(result, function(name, value) { block.attr(name, value); });
41
+ return node;
42
+ }
43
+ function setHtml(node, html) {
44
+ node.innerHTML = html === void 0 || html === null ? "" : String(html);
45
+ return node;
46
+ }
47
+ function addClass(node, names) {
48
+ split(names).forEach(function(name) {
49
+ node.classList.add(name);
50
+ });
51
+ return node;
52
+ }
53
+ function removeClass(node, names) {
54
+ split(names).forEach(function(name) {
55
+ node.classList.remove(name);
56
+ });
57
+ return node;
58
+ }
59
+ function hasClass(node, name) {
60
+ return !!node && node.nodeType === 1 && node.classList.contains(name);
61
+ }
62
+ function split(names) {
63
+ return String(names || "").split(/\s+/).filter(Boolean);
64
+ }
65
+ function hide(node) {
66
+ node.style.display = "none";
67
+ return node;
68
+ }
69
+ function visible(node) {
70
+ return !!(node.offsetWidth || node.offsetHeight || node.getClientRects().length);
71
+ }
72
+ function delegate(root, types, selector, handler, options) {
73
+ var listener = function(event) {
74
+ var match = closest(event.target, selector, root);
75
+ if (match && root.contains(match)) {
76
+ return handler.call(match, event);
77
+ }
78
+ return void 0;
79
+ };
80
+ split(types).forEach(function(type) {
81
+ root.addEventListener(type, listener, options);
82
+ });
83
+ return listener;
84
+ }
85
+ var DEFAULT_DURATION = 400;
86
+ function animateAway(node, frames, duration, done) {
87
+ duration = duration === void 0 ? DEFAULT_DURATION : duration;
88
+ var finish = function() {
89
+ hide(node);
90
+ if (done) {
91
+ done();
92
+ }
93
+ };
94
+ if (!visible(node) || !node.animate || duration <= 0) {
95
+ window.setTimeout(finish, 0);
96
+ return;
83
97
  }
84
-
85
- function textFeature(ge) {
86
-
87
- var settings = ge.settings;
88
- var TEXTS = {};
89
- var warned = {};
90
-
91
- $.each($.fn.gridEditor.texts, function(type, factory) {
92
- TEXTS[type] = factory(ge);
93
- });
94
-
95
- // Every editor loaded, in the order the page loaded them, unless the
96
- // host names the ones it wants
97
- if (!Array.isArray(settings.content_types)) { settings.content_types = Object.keys(TEXTS); }
98
- if (!Array.isArray(settings.text_tools)) { settings.text_tools = []; }
99
- if (!Array.isArray(settings.text_classes)) { settings.text_classes = []; }
100
-
101
- /** The text editors this editor offers, in content_types order: the ones loaded. */
102
- function offeredTexts() {
103
- return settings.content_types.filter(function(type) { return !!TEXTS[type]; });
98
+ var animation = node.animate(frames(getComputedStyle(node)), {
99
+ duration,
100
+ easing: "ease-in-out"
101
+ });
102
+ var called = false;
103
+ var once = function() {
104
+ if (called) {
105
+ return;
106
+ }
107
+ called = true;
108
+ finish();
109
+ };
110
+ animation.onfinish = once;
111
+ animation.oncancel = once;
112
+ }
113
+ function slideUp(node, duration, done) {
114
+ if (typeof duration === "function") {
115
+ done = duration;
116
+ duration = void 0;
117
+ }
118
+ node.style.overflow = "hidden";
119
+ animateAway(node, function(style) {
120
+ return [
121
+ {
122
+ height: style.height,
123
+ paddingTop: style.paddingTop,
124
+ paddingBottom: style.paddingBottom,
125
+ marginTop: style.marginTop,
126
+ marginBottom: style.marginBottom
127
+ },
128
+ { height: "0px", paddingTop: "0px", paddingBottom: "0px", marginTop: "0px", marginBottom: "0px" }
129
+ ];
130
+ }, duration, function() {
131
+ node.style.removeProperty("overflow");
132
+ if (done) {
133
+ done();
134
+ }
135
+ });
136
+ }
137
+
138
+ // src/js/text/grideditor.text.js
139
+ if (!GridEditor.features.text) {
140
+ let attributesOf = function(element2) {
141
+ var found = {};
142
+ Array.prototype.slice.call(element2.attributes).forEach(function(attribute) {
143
+ found[attribute.name] = attribute.value;
144
+ });
145
+ return found;
146
+ }, classesIn = function(value) {
147
+ return (value || "").split(/\s+/).filter(function(name) {
148
+ return name !== "" && !EDITOR_CLASS.test(name);
149
+ });
150
+ }, restoreAttributes = function(block, before, ready, open) {
151
+ var result = Object.assign({}, before);
152
+ Object.keys(Object.assign({}, ready, open)).forEach(function(name) {
153
+ if (name === "class" || EDITOR_ATTRIBUTE.test(name) || ready[name] === open[name]) {
154
+ return;
104
155
  }
105
-
106
- /** What a text editor is called: its plugin's label, or its type. */
107
- function textLabel(type) {
108
- var text = TEXTS[type];
109
- return text && text.labelKey ? ge.t(text.labelKey) : type;
156
+ if (open[name] === void 0) {
157
+ delete result[name];
158
+ } else {
159
+ result[name] = open[name];
110
160
  }
111
-
112
- /** A detached content area of `type`, holding `content` or the editor's initial content. */
113
- function makeText(type, content) {
114
- var text = TEXTS[type];
115
-
116
- return $('<div class="ge-content" />')
117
- .addClass('ge-content-type-' + type)
118
- .attr('data-ge-content-type', type)
119
- .html(content !== undefined ? content : (text && text.initialContent) || '');
161
+ });
162
+ var readyClasses = classesIn(ready["class"]);
163
+ var openClasses = classesIn(open["class"]);
164
+ var classes = classesIn(before["class"]).filter(function(name) {
165
+ return openClasses.indexOf(name) !== -1 || readyClasses.indexOf(name) === -1;
166
+ });
167
+ openClasses.forEach(function(name) {
168
+ if (readyClasses.indexOf(name) === -1 && classes.indexOf(name) === -1) {
169
+ classes.push(name);
120
170
  }
121
-
122
- /** A text block at the end of a column, through the add events. */
123
- function addTextTo(col, type) {
124
- return ge.place(makeText(type), 'text', { appendTo: col, source: 'tool' });
171
+ });
172
+ if (classes.length) {
173
+ result["class"] = classes.join(" ");
174
+ } else {
175
+ delete result["class"];
176
+ }
177
+ Object.keys(attributesOf(block)).forEach(function(name) {
178
+ block.removeAttribute(name);
179
+ });
180
+ Object.keys(result).forEach(function(name) {
181
+ block.setAttribute(name, result[name]);
182
+ });
183
+ }, textFeature = function(ge) {
184
+ var settings = ge.settings;
185
+ var TEXTS = {};
186
+ var warned = {};
187
+ Object.keys(GridEditor.texts).forEach(function(type) {
188
+ TEXTS[type] = GridEditor.texts[type](ge);
189
+ });
190
+ if (!Array.isArray(settings.content_types)) {
191
+ settings.content_types = Object.keys(TEXTS);
192
+ }
193
+ if (!Array.isArray(settings.text_tools)) {
194
+ settings.text_tools = [];
195
+ }
196
+ if (!Array.isArray(settings.text_classes)) {
197
+ settings.text_classes = [];
198
+ }
199
+ function offeredTexts() {
200
+ return settings.content_types.filter(function(type) {
201
+ return !!TEXTS[type];
202
+ });
203
+ }
204
+ function textLabel(type) {
205
+ var text = TEXTS[type];
206
+ return text && text.labelKey ? ge.t(text.labelKey) : type;
207
+ }
208
+ function makeText(type, content) {
209
+ var text = TEXTS[type];
210
+ var block = element("div", {
211
+ "class": "ge-content ge-content-type-" + type,
212
+ "data-ge-content-type": type
213
+ });
214
+ if (content && content.nodeType) {
215
+ block.appendChild(content);
216
+ } else {
217
+ setHtml(block, content !== void 0 ? content : text && text.initialContent || "");
125
218
  }
126
-
127
- /**
128
- * createText(type?, options?): a content area of a text editor's,
129
- * detached unless a placement is given. The type is the first one
130
- * offered by default. `options.content` is its html.
131
- */
132
- function apiCreateText(type, options) {
133
- if (type && typeof type === 'object') {
134
- options = type;
135
- type = undefined;
136
- }
137
- options = options || {};
138
- type = type || offeredTexts()[0];
139
-
140
- if (!type || !TEXTS[type]) {
141
- if (!warned['createText:' + type]) {
142
- warned['createText:' + type] = true;
143
- ge.warn('createText: no text editor "' + type + '" is loaded; ' +
144
- 'load its plugin and name it in content_types');
145
- }
146
- return null;
147
- }
148
-
149
- return ge.place(makeText(type, options.content), 'text', options);
219
+ return block;
220
+ }
221
+ function apiCreateText(type, options) {
222
+ if (type && typeof type === "object") {
223
+ options = type;
224
+ type = void 0;
150
225
  }
151
-
152
- /** Whether a content area is a text of one of the editors loaded here. */
153
- function isOurs(block) {
154
- return !!TEXTS[block.attr('data-ge-content-type')];
226
+ options = options || {};
227
+ type = type || offeredTexts()[0];
228
+ if (!type || !TEXTS[type]) {
229
+ if (!warned["createText:" + type]) {
230
+ warned["createText:" + type] = true;
231
+ ge.warn('createText: no text editor "' + type + '" is loaded; load its plugin and name it in content_types');
232
+ }
233
+ return null;
155
234
  }
156
-
157
- /** Open the editor on a text, once: until it is closed again. */
158
- function startText(block) {
159
- if (block.hasClass('ge-rte-active')) { return; }
160
-
161
- // A content area nobody can see - a tab that is not the open one,
162
- // a closed accordion item - has no geometry for an editor to lay
163
- // its toolbar out against, and nothing anyone can type into
164
- if (!block.is(':visible')) { return; }
165
-
166
- // The attribute, not jQuery's cached copy of it: it is markup, and
167
- // the drawer reads it the same way
168
- var text = TEXTS[block.attr('data-ge-content-type')];
169
- if (!text) { return; }
170
-
171
- // Not marked active, so the next click tries again: the library
172
- // may be loaded by then
173
- if (text.available && !text.available()) {
174
- if (text.missingKey) { console.error(ge.t(text.missingKey)); }
175
- return;
176
- }
177
-
178
- block.data('ge-text-before', attributesOf(block[0])).removeData('ge-text-ready');
179
- block.addClass('ge-rte-active');
180
- text.start(block);
235
+ return ge.place(makeText(type, options.content), "text", options);
236
+ }
237
+ function isOurs(block) {
238
+ return !!TEXTS[block.getAttribute("data-ge-content-type")];
239
+ }
240
+ function startText(block) {
241
+ if (hasClass(block, "ge-rte-active")) {
242
+ return;
181
243
  }
182
-
183
- function onClick() {
184
- startText($(this));
244
+ if (!visible(block)) {
245
+ return;
185
246
  }
186
-
187
- /**
188
- * Close the text editor on one content area, and leave the content
189
- * area's own attributes as the host left them.
190
- *
191
- * An editor adds attributes of its own while it is open, and takes
192
- * them off again, more or less: CKEditor leaves aria-readonly behind.
193
- * tinyMCE does worse, and puts back every attribute as it was when it
194
- * opened, so an id, a class or a plugin's attribute given while it was
195
- * open is lost. So the attributes are read three times - before the
196
- * editor opens, once it has opened, and before it closes - and what
197
- * changed between the second and the third, the host's doing, is
198
- * played back onto the first, the host's markup. What the editor did
199
- * is left out either way.
200
- */
201
- function closeText(block) {
202
- var text = TEXTS[block.attr('data-ge-content-type')];
203
- var before = block.data('ge-text-before');
204
- var open = before ? attributesOf(block[0]) : null;
205
-
206
- // Every content area is told, as in 5.x: one whose editor never
207
- // started is the plugin's to ignore
208
- if (text) { text.stop(block); }
209
-
210
- // After stop, not before: an editor that restores the class
211
- // attribute it snapshotted would put ge-rte-active back
212
- block.removeClass('ge-rte-active');
213
-
214
- if (before) {
215
- restoreAttributes(block, before, block.data('ge-text-ready') || before, open);
216
- block.removeData('ge-text-before').removeData('ge-text-ready');
217
- }
247
+ var text = TEXTS[block.getAttribute("data-ge-content-type")];
248
+ if (!text) {
249
+ return;
218
250
  }
219
-
220
- function createTextControls(textBlock) {
221
- var block = textBlock.children('.ge-content');
222
- var type = block.attr('data-ge-content-type');
223
- var drawer = $('<div class="ge-tools-drawer ge-text-drawer" />').prependTo(textBlock);
224
-
225
- ge.createMoveTool(drawer);
226
-
227
- var details = ge.addSettingsTool(drawer, block, settings.text_classes);
228
-
229
- // Which editor edits it, first in its settings: something to
230
- // know about it, not something to do with it
231
- $('<div class="ge-field ge-text-editor" />')
232
- .append($('<span class="ge-field-label" />').text(ge.t('panel.editor')))
233
- .append($('<span class="ge-field-value" />').text(textLabel(type)))
234
- .prependTo(details.children('.ge-details-general'));
235
-
236
- settings.text_tools.forEach(function(hostTool) {
237
- ge.createTool(drawer, hostTool.title || '', hostTool.className || '',
238
- hostTool.iconClass || 'bi bi-wrench', hostTool.on);
239
- });
240
-
241
- ge.createTool(drawer, ge.t('tool.delete_text'), 'ge-delete-text', 'bi bi-trash', function() {
242
- ge.deleteNode('text', block, ge.t('confirm.delete_text'), function(removed) {
243
- // Its editor lets go first: removed while open, it would
244
- // be left behind, attached to nothing
245
- closeText(block);
246
- textBlock.slideUp(function() {
247
- textBlock.remove();
248
- removed();
249
- });
250
- });
251
- });
251
+ if (text.available && !text.available()) {
252
+ if (text.missingKey) {
253
+ console.error(ge.t(text.missingKey));
254
+ }
255
+ return;
252
256
  }
253
-
254
- /** A drawer for each text of ours in a text block that has none yet. */
255
- function markTexts() {
256
- ge.canvas.find('.ge-text-block').each(function() {
257
- var textBlock = $(this);
258
- if (textBlock.children('.ge-tools-drawer').length) { return; }
259
- if (!isOurs(textBlock.children('.ge-content'))) { return; }
260
-
261
- createTextControls(textBlock);
262
- });
257
+ readBefore.set(block, attributesOf(block));
258
+ readReady.delete(block);
259
+ addClass(block, "ge-rte-active");
260
+ text.start([block]);
261
+ }
262
+ function onClick() {
263
+ startText(this);
264
+ }
265
+ function closeText(block) {
266
+ var text = TEXTS[block.getAttribute("data-ge-content-type")];
267
+ var before = readBefore.get(block);
268
+ var open = before ? attributesOf(block) : null;
269
+ if (text) {
270
+ text.stop([block]);
263
271
  }
264
-
272
+ removeClass(block, "ge-rte-active");
273
+ if (before) {
274
+ restoreAttributes(block, before, readReady.get(block) || before, open);
275
+ readBefore.delete(block);
276
+ readReady.delete(block);
277
+ }
278
+ }
279
+ function createTextControls(textBlock) {
280
+ var block = child(textBlock, ".ge-content");
281
+ var type = block.getAttribute("data-ge-content-type");
282
+ var drawer = element("div", { "class": "ge-tools-drawer ge-text-drawer" });
283
+ textBlock.insertBefore(drawer, textBlock.firstChild);
284
+ ge.createMoveTool(drawer);
285
+ var details = ge.addSettingsTool(drawer, block, settings.text_classes);
286
+ var general = child(details, ".ge-details-general");
287
+ var editor = element("div", { "class": "ge-field ge-text-editor" });
288
+ editor.appendChild(element("span", { "class": "ge-field-label" }, ge.t("panel.editor")));
289
+ editor.appendChild(element("span", { "class": "ge-field-value" }, textLabel(type)));
290
+ general.insertBefore(editor, general.firstChild);
291
+ settings.text_tools.forEach(function(hostTool) {
292
+ ge.createTool(
293
+ drawer,
294
+ hostTool.title || "",
295
+ hostTool.className || "",
296
+ hostTool.iconClass || "bi bi-wrench",
297
+ hostTool.on
298
+ );
299
+ });
300
+ ge.createTool(drawer, ge.t("tool.delete_text"), "ge-delete-text", "bi bi-trash", function() {
301
+ ge.deleteNode("text", block, ge.t("confirm.delete_text"), function(removed) {
302
+ closeText(block);
303
+ slideUp(textBlock, function() {
304
+ textBlock.remove();
305
+ removed();
306
+ });
307
+ });
308
+ });
309
+ }
310
+ function markTexts() {
311
+ all(ge.canvas, ".ge-text-block").forEach(function(textBlock) {
312
+ if (child(textBlock, ".ge-tools-drawer")) {
313
+ return;
314
+ }
315
+ var block = child(textBlock, ".ge-content");
316
+ if (!block || !isOurs(block)) {
317
+ return;
318
+ }
319
+ createTextControls(textBlock);
320
+ });
321
+ }
322
+ var texts = offeredTexts();
323
+ var clicks = null;
324
+ return {
325
+ methods: {
326
+ createText: apiCreateText
327
+ },
265
328
  /**
266
- * The add text tool, in each column's drawer before its add row tool:
267
- * a text of the first editor offered, or, held, of the one chosen.
329
+ * The types this plugin edits, for the core: every editor loaded
330
+ * is the owner of its texts, and the ones offered are what the
331
+ * host's plain content can be made.
268
332
  */
269
- function addTextTools() {
270
- var texts = offeredTexts();
271
- if (!texts.length) { return; }
272
-
273
- ge.canvas.find('.column').each(function() {
274
- var col = $(this);
275
- var drawer = col.children('.ge-tools-drawer');
276
- if (!drawer.length || drawer.children('.ge-add-text').length) { return; }
277
-
278
- ge.createTool(drawer, ge.t('tool.add_text'), 'ge-add-text', 'bi bi-type', function() {
279
- if (ge.closePicker()) { return; } // The picker was open: that was the answer
280
-
281
- addTextTo(col, texts[0]);
282
- });
283
-
284
- var tool = drawer.children('.ge-add-text');
285
- var addRow = drawer.children('.ge-add-row');
286
- if (addRow.length) { tool.insertBefore(addRow); }
287
-
288
- if (texts.length > 1) {
289
- ge.attachPicker(tool, function() {
290
- ge.openPicker(tool, texts.map(function(type) {
291
- return {
292
- label: textLabel(type),
293
- title: ge.t('tool.add_text_type', { editor: textLabel(type) }),
294
- attributes: { 'data-ge-content-type': type },
295
- choose: function() { addTextTo(col, type); },
296
- };
297
- }), 'ge-text-picker');
298
- });
299
- }
300
- });
301
- }
302
-
303
- var texts = offeredTexts();
304
-
305
- return {
306
- methods: {
307
- createText: apiCreateText,
308
- },
309
-
310
- /**
311
- * The types this plugin edits, for the core: every editor loaded
312
- * is the owner of its texts, and the ones offered are what the
313
- * host's plain content can be made.
314
- */
315
- textTypes: function() {
316
- var offered = offeredTexts();
317
- var others = Object.keys(TEXTS).filter(function(type) { return offered.indexOf(type) === -1; });
318
-
319
- return offered.concat(others).map(function(type) {
320
- var text = TEXTS[type];
321
-
322
- return {
323
- type: type,
324
- label: textLabel(type),
325
- offered: offered.indexOf(type) !== -1,
326
- available: text.available ? function() { return text.available(); } : null,
327
- missingKey: text.missingKey,
328
- edit: function(block) {
329
- var textBlock = block.parent('.ge-text-block');
330
- if (textBlock.length && !textBlock.children('.ge-tools-drawer').length) {
331
- createTextControls(textBlock);
332
- }
333
-
334
- startText(block);
335
- },
336
- };
337
- });
338
- },
339
-
340
- // A text block of each editor offered. Like a container, it goes
341
- // into a row of its own when clicked, or where it is dropped
342
- toolbar: texts.map(function(type) {
343
- return {
344
- label: function() {
345
- return texts.length > 1 ? ge.t('text.add_type', { editor: textLabel(type) }) : ge.t('text.add');
346
- },
347
- iconClass: TEXTS[type].iconClass,
348
- className: 'ge-add-text-button',
349
- kind: 'text',
350
- inColumn: true,
351
- create: function() { return makeText(type); },
352
- };
353
- }),
354
-
355
- onInit: function() {
356
- markTexts();
357
- addTextTools();
358
-
359
- ge.canvas.off('click.ge-text').on('click.ge-text', '.ge-content', onClick);
360
- },
361
-
362
- // While the drawers and the text blocks are still there, as the
363
- // editors left them
364
- onBeforeDeinit: function() {
365
- ge.canvas.find('.ge-content').each(function() {
366
- if (isOurs($(this))) { closeText($(this)); }
367
- });
368
- },
369
-
370
- onDeinit: function() {
371
- ge.canvas.off('click.ge-text');
372
- },
373
-
374
- // The first time only: an undo says ready again, and by then the
375
- // host may have changed the content area itself
376
- onContentReady: function(area) {
377
- if (area.data('ge-text-before') && !area.data('ge-text-ready')) {
378
- area.data('ge-text-ready', attributesOf(area[0]));
333
+ textTypes: function() {
334
+ var offered = offeredTexts();
335
+ var others = Object.keys(TEXTS).filter(function(type) {
336
+ return offered.indexOf(type) === -1;
337
+ });
338
+ return offered.concat(others).map(function(type) {
339
+ var text = TEXTS[type];
340
+ return {
341
+ type,
342
+ label: textLabel(type),
343
+ offered: offered.indexOf(type) !== -1,
344
+ available: text.available ? function() {
345
+ return text.available();
346
+ } : null,
347
+ missingKey: text.missingKey,
348
+ edit: function(block) {
349
+ var textBlock = block.parentElement;
350
+ if (hasClass(textBlock, "ge-text-block") && !child(textBlock, ".ge-tools-drawer")) {
351
+ createTextControls(textBlock);
379
352
  }
353
+ startText(block);
354
+ }
355
+ };
356
+ });
357
+ },
358
+ // A text block of each editor offered. Like a container, it goes
359
+ // into a row of its own when clicked, or where it is dropped
360
+ toolbar: texts.map(function(type) {
361
+ return {
362
+ label: function() {
363
+ return texts.length > 1 ? ge.t("text.add_type", { editor: textLabel(type) }) : ge.t("text.add");
380
364
  },
381
- };
382
- }
383
-
384
- // Whatever the plugins setting says: content_types chooses the editors
385
- textFeature.always = true;
386
-
387
- $.fn.gridEditor.features.text = textFeature;
388
-
389
- })(jQuery);
390
-
391
- /**
392
- * CKEditor for grid-editor's content areas.
393
- *
394
- * A text editor plugin: load this file after the editor, and CKEditor 4
395
- * after or before it, and a text of the ckeditor type is edited with an
396
- * inline CKEditor. What it can ask the editor for is the handle its
397
- * factory is called with, described in docs/plugins.md.
398
- *
399
- * <script src="ckeditor/ckeditor.js"></script>
400
- * <script src="dist/jquery.grideditor.min.js"></script>
401
- * <script src="dist/plugins/grideditor.ckeditor.min.js"></script>
402
- *
403
- * Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
404
- * loaded on its own, like every plugin. The built file starts with what
405
- * every text editor shares - text blocks, the Text button and the Add text
406
- * tool, createText, making the host's plain content a text - from
407
- * src/js/text/grideditor.text.js, installed once however many editors a
408
- * page loads.
409
- */
410
- (function($) {
411
-
412
- $.extend($.fn.gridEditor.locales.en, {
413
- 'text.ckeditor': 'CKEditor',
365
+ iconClass: TEXTS[type].iconClass,
366
+ className: "ge-add-text-button",
367
+ kind: "text",
368
+ inColumn: true,
369
+ create: function() {
370
+ return makeText(type);
371
+ }
372
+ };
373
+ }),
374
+ onInit: function() {
375
+ markTexts();
376
+ if (clicks) {
377
+ ge.canvas.removeEventListener("click", clicks);
378
+ }
379
+ clicks = delegate(ge.canvas, "click", ".ge-content", onClick);
380
+ },
381
+ // While the drawers and the text blocks are still there, as the
382
+ // editors left them
383
+ onBeforeDeinit: function() {
384
+ all(ge.canvas, ".ge-content").forEach(function(block) {
385
+ if (isOurs(block)) {
386
+ closeText(block);
387
+ }
388
+ });
389
+ },
390
+ onDeinit: function() {
391
+ if (clicks) {
392
+ ge.canvas.removeEventListener("click", clicks);
393
+ }
394
+ clicks = null;
395
+ },
396
+ // The first time only: an undo says ready again, and by then the
397
+ // host may have changed the content area itself
398
+ onContentReady: function(area) {
399
+ if (readBefore.has(area) && !readReady.has(area)) {
400
+ readReady.set(area, attributesOf(area));
401
+ }
402
+ }
403
+ };
404
+ };
405
+ Object.assign(GridEditor.locales.en, {
406
+ "text.add": "Text",
407
+ "text.add_type": "Text ({editor})",
408
+ "panel.editor": "Editor",
409
+ "panel.kind_text": "Text"
414
410
  });
415
-
416
- var INITIAL_CONTENT = '<p>Lorem initius... </p>';
417
-
418
- $.fn.gridEditor.texts.ckeditor = function(ge) {
419
-
420
- /**
421
- * The instance editing this content area. Kept in jQuery data when it
422
- * is made, and looked for among CKEditor's own as a fallback, since
423
- * an instance made by another version of this file has no data.
424
- */
425
- function instanceOf(contentArea) {
426
- var kept = contentArea.data('ge-ckeditor');
427
- if (kept) { return kept; }
428
-
429
- var found = null;
430
- $.each(window.CKEDITOR.instances, function(name, instance) {
431
- if (instance.element && instance.element.$ === contentArea[0]) { found = instance; }
432
- });
433
-
434
- return found;
411
+ readBefore = /* @__PURE__ */ new WeakMap();
412
+ readReady = /* @__PURE__ */ new WeakMap();
413
+ EDITOR_CLASS = /^(mce-|cke|note-)|^(active|ge-rte-active)$/;
414
+ EDITOR_ATTRIBUTE = /^(data-mce-|contenteditable$|spellcheck$)/;
415
+ textFeature.always = true;
416
+ GridEditor.features.text = textFeature;
417
+ }
418
+ var readBefore;
419
+ var readReady;
420
+ var EDITOR_CLASS;
421
+ var EDITOR_ATTRIBUTE;
422
+
423
+ // src/js/plugins/grideditor.ckeditor.js
424
+ Object.assign(GridEditor.locales.en, {
425
+ "text.ckeditor": "CKEditor"
426
+ });
427
+ var INITIAL_CONTENT = "<p>Lorem initius... </p>";
428
+ var instances = /* @__PURE__ */ new WeakMap();
429
+ GridEditor.texts.ckeditor = function(ge) {
430
+ function instanceOf(contentArea) {
431
+ var kept = instances.get(contentArea);
432
+ if (kept) {
433
+ return kept;
434
+ }
435
+ var found = null;
436
+ Object.keys(window.CKEDITOR.instances).forEach(function(name) {
437
+ var instance = window.CKEDITOR.instances[name];
438
+ if (instance.element && instance.element.$ === contentArea) {
439
+ found = instance;
435
440
  }
436
-
437
- return {
438
- labelKey: 'text.ckeditor',
439
- initialContent: INITIAL_CONTENT,
440
- missingKey: 'error.ckeditor_missing',
441
-
442
- available: function() { return !!window.CKEDITOR; },
443
-
444
- start: function(contentAreas) {
445
- var settings = ge.settings;
446
-
447
- contentAreas.each(function() {
448
- var contentArea = $(this);
449
- if (contentArea.hasClass('active')) { return; }
450
-
451
- if (contentArea.html() == INITIAL_CONTENT) {
452
- // CKEditor kills this '&nbsp' creating a non usable box :/
453
- contentArea.html('&nbsp;');
454
- }
455
-
456
- // Add the .attr('contenteditable',''true') or CKEditor loads readonly
457
- contentArea.addClass('active').attr('contenteditable', 'true');
458
-
459
- var configuration = $.extend(
460
- {},
461
- (settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
462
- {
463
- // Focus editor on creation
464
- on: {
465
- instanceReady: function( evt ) {
466
- // Call original instanceReady function, if one was passed in the config
467
- var callback;
468
- try {
469
- callback = settings.ckeditor.config.on.instanceReady;
470
- } catch (err) {
471
- // No callback passed
472
- }
473
- if (callback) {
474
- callback.call(this, evt);
475
- }
476
-
477
- // The editor owns what is inside the
478
- // content area now, so the grid editor is
479
- // told to put its own furniture back
480
- ge.textReady(contentArea);
481
-
482
- instance.focus();
483
- }
484
- }
485
- }
486
- );
487
- var instance = window.CKEDITOR.inline(contentArea.get(0), configuration);
488
- contentArea.data('ge-ckeditor', instance);
489
- });
490
- },
491
-
492
- stop: function(contentAreas) {
493
- contentAreas.filter('.active').each(function() {
494
- var contentArea = $(this);
495
-
496
- // This content area's instance, and no other: up to 5.x
497
- // closing one content area destroyed every CKEditor on
498
- // the page, other editors' and the host's own included
499
- var instance = window.CKEDITOR ? instanceOf(contentArea) : null;
500
- if (instance) { instance.destroy(); }
501
- contentArea.removeData('ge-ckeditor');
502
-
503
- // Cleanup
504
- contentArea
505
- .removeClass('active cke_focus')
506
- .removeAttr('id')
507
- .removeAttr('style')
508
- .removeAttr('spellcheck')
509
- .removeAttr('contenteditable')
510
- ;
511
- });
512
- },
513
- };
441
+ });
442
+ return found;
443
+ }
444
+ return {
445
+ labelKey: "text.ckeditor",
446
+ initialContent: INITIAL_CONTENT,
447
+ missingKey: "error.ckeditor_missing",
448
+ available: function() {
449
+ return !!window.CKEDITOR;
450
+ },
451
+ start: function(contentAreas) {
452
+ var settings = ge.settings;
453
+ contentAreas.forEach(function(contentArea) {
454
+ if (hasClass(contentArea, "active")) {
455
+ return;
456
+ }
457
+ if (contentArea.innerHTML == INITIAL_CONTENT) {
458
+ contentArea.innerHTML = "&nbsp;";
459
+ }
460
+ addClass(contentArea, "active");
461
+ contentArea.setAttribute("contenteditable", "true");
462
+ var configuration = Object.assign(
463
+ {},
464
+ settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {},
465
+ {
466
+ // Focus editor on creation
467
+ on: {
468
+ instanceReady: function(evt) {
469
+ var callback;
470
+ try {
471
+ callback = settings.ckeditor.config.on.instanceReady;
472
+ } catch (err) {
473
+ }
474
+ if (callback) {
475
+ callback.call(this, evt);
476
+ }
477
+ ge.textReady(contentArea);
478
+ instance.focus();
479
+ }
480
+ }
481
+ }
482
+ );
483
+ var instance = window.CKEDITOR.inline(contentArea, configuration);
484
+ instances.set(contentArea, instance);
485
+ });
486
+ },
487
+ stop: function(contentAreas) {
488
+ contentAreas.filter(function(contentArea) {
489
+ return hasClass(contentArea, "active");
490
+ }).forEach(function(contentArea) {
491
+ var instance = window.CKEDITOR ? instanceOf(contentArea) : null;
492
+ if (instance) {
493
+ instance.destroy();
494
+ }
495
+ instances.delete(contentArea);
496
+ removeClass(contentArea, "active cke_focus");
497
+ ["id", "style", "spellcheck", "contenteditable"].forEach(function(name) {
498
+ contentArea.removeAttribute(name);
499
+ });
500
+ });
501
+ }
514
502
  };
515
- })(jQuery);
503
+ };
504
+ })();