@themarioga/grid-editor 6.0.0 → 7.1.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 +59 -0
  4. package/README.md +163 -87
  5. package/UPGRADING.md +119 -0
  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 -168
  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 +484 -449
  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 +493 -427
  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 +502 -490
  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 +6 -0
  97. package/docs/plugins.md +47 -25
  98. package/example/adapter.html +112 -0
  99. package/example/attributes.html +89 -62
  100. package/example/autocols.html +9 -9
  101. package/example/autosave.html +18 -16
  102. package/example/basic.html +8 -6
  103. package/example/breakpoints.html +5 -6
  104. package/example/ckeditor.html +4 -5
  105. package/example/clipboard.html +15 -11
  106. package/example/codemirror.html +13 -8
  107. package/example/containers.html +11 -9
  108. package/example/custom_editor.html +53 -34
  109. package/example/elements.html +14 -12
  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 +13 -10
  116. package/package.json +44 -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 -156
  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 +148 -140
  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 +77 -56
  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
@@ -13,23 +13,31 @@
13
13
  * back, and making the host's plain content a text through the core's
14
14
  * `textTypes` hook.
15
15
  *
16
- * Each editor registers under $.fn.gridEditor.texts, which is this file's own
16
+ * Each editor registers under GridEditor.texts, which is this file's own
17
17
  * registry and not a contract: an editor of a host's own is a feature plugin
18
18
  * of its own, as example/custom_editor.html shows.
19
19
  */
20
- (function($) {
20
+ import { GridEditor } from '../grideditor.js';
21
+ import * as dom from '../dom.js';
21
22
 
22
- if ($.fn.gridEditor.features.text) { return; }
23
+ // However many editors a page loads, each with a copy of this file in its
24
+ // classic script: the first one installs it
25
+ if (!GridEditor.features.text) {
23
26
 
24
- $.extend($.fn.gridEditor.locales.en, {
27
+ Object.assign(GridEditor.locales.en, {
25
28
  'text.add': 'Text',
26
29
  'text.add_type': 'Text ({editor})',
27
30
  'panel.editor': 'Editor',
28
31
  'panel.kind_text': 'Text',
29
32
  });
30
33
 
31
- /** The text editors, by the content type each edits. */
32
- $.fn.gridEditor.texts = $.fn.gridEditor.texts || {};
34
+ /**
35
+ * What a content area's attributes were before its editor opened, and
36
+ * once it had: the two readings closeText plays the host's changes
37
+ * back from. Shared by every editor on the page, like the nodes.
38
+ */
39
+ var readBefore = new WeakMap();
40
+ var readReady = new WeakMap();
33
41
 
34
42
  /** What a text editor puts on a content area while it is open, whenever it likes. */
35
43
  var EDITOR_CLASS = /^(mce-|cke|note-)|^(active|ge-rte-active)$/;
@@ -37,7 +45,7 @@
37
45
 
38
46
  function attributesOf(element) {
39
47
  var found = {};
40
- $.each($.makeArray(element.attributes), function(i, attribute) {
48
+ Array.prototype.slice.call(element.attributes).forEach(function(attribute) {
41
49
  found[attribute.name] = attribute.value;
42
50
  });
43
51
  return found;
@@ -51,9 +59,9 @@
51
59
 
52
60
  /** The host's markup, with what changed from `ready` to `open` played back onto it. */
53
61
  function restoreAttributes(block, before, ready, open) {
54
- var result = $.extend({}, before);
62
+ var result = Object.assign({}, before);
55
63
 
56
- $.each($.extend({}, ready, open), function(name) {
64
+ Object.keys(Object.assign({}, ready, open)).forEach(function(name) {
57
65
  if (name === 'class' || EDITOR_ATTRIBUTE.test(name) || ready[name] === open[name]) { return; }
58
66
 
59
67
  if (open[name] === undefined) {
@@ -76,8 +84,8 @@
76
84
  // shuffle a node's attributes because it was edited
77
85
  if (classes.length) { result['class'] = classes.join(' '); } else { delete result['class']; }
78
86
 
79
- $.each(attributesOf(block[0]), function(name) { block.removeAttr(name); });
80
- $.each(result, function(name, value) { block.attr(name, value); });
87
+ Object.keys(attributesOf(block)).forEach(function(name) { block.removeAttribute(name); });
88
+ Object.keys(result).forEach(function(name) { block.setAttribute(name, result[name]); });
81
89
  }
82
90
 
83
91
  function textFeature(ge) {
@@ -86,8 +94,8 @@
86
94
  var TEXTS = {};
87
95
  var warned = {};
88
96
 
89
- $.each($.fn.gridEditor.texts, function(type, factory) {
90
- TEXTS[type] = factory(ge);
97
+ Object.keys(GridEditor.texts).forEach(function(type) {
98
+ TEXTS[type] = GridEditor.texts[type](ge);
91
99
  });
92
100
 
93
101
  // Every editor loaded, in the order the page loaded them, unless the
@@ -110,11 +118,17 @@
110
118
  /** A detached content area of `type`, holding `content` or the editor's initial content. */
111
119
  function makeText(type, content) {
112
120
  var text = TEXTS[type];
121
+ var block = dom.element('div', {
122
+ 'class': 'ge-content ge-content-type-' + type,
123
+ 'data-ge-content-type': type,
124
+ });
113
125
 
114
- return $('<div class="ge-content" />')
115
- .addClass('ge-content-type-' + type)
116
- .attr('data-ge-content-type', type)
117
- .html(content !== undefined ? content : (text && text.initialContent) || '');
126
+ if (content && content.nodeType) {
127
+ block.appendChild(content);
128
+ } else {
129
+ dom.setHtml(block, content !== undefined ? content : (text && text.initialContent) || '');
130
+ }
131
+ return block;
118
132
  }
119
133
 
120
134
  /**
@@ -144,21 +158,20 @@
144
158
 
145
159
  /** Whether a content area is a text of one of the editors loaded here. */
146
160
  function isOurs(block) {
147
- return !!TEXTS[block.attr('data-ge-content-type')];
161
+ return !!TEXTS[block.getAttribute('data-ge-content-type')];
148
162
  }
149
163
 
150
164
  /** Open the editor on a text, once: until it is closed again. */
151
165
  function startText(block) {
152
- if (block.hasClass('ge-rte-active')) { return; }
166
+ if (dom.hasClass(block, 'ge-rte-active')) { return; }
153
167
 
154
168
  // A content area nobody can see - a tab that is not the open one,
155
169
  // a closed accordion item - has no geometry for an editor to lay
156
170
  // its toolbar out against, and nothing anyone can type into
157
- if (!block.is(':visible')) { return; }
171
+ if (!dom.visible(block)) { return; }
158
172
 
159
- // The attribute, not jQuery's cached copy of it: it is markup, and
160
- // the drawer reads it the same way
161
- var text = TEXTS[block.attr('data-ge-content-type')];
173
+ // The attribute: it is markup, and the drawer reads it the same way
174
+ var text = TEXTS[block.getAttribute('data-ge-content-type')];
162
175
  if (!text) { return; }
163
176
 
164
177
  // Not marked active, so the next click tries again: the library
@@ -168,13 +181,14 @@
168
181
  return;
169
182
  }
170
183
 
171
- block.data('ge-text-before', attributesOf(block[0])).removeData('ge-text-ready');
172
- block.addClass('ge-rte-active');
173
- text.start(block);
184
+ readBefore.set(block, attributesOf(block));
185
+ readReady.delete(block);
186
+ dom.addClass(block, 'ge-rte-active');
187
+ text.start([block]);
174
188
  }
175
189
 
176
190
  function onClick() {
177
- startText($(this));
191
+ startText(this);
178
192
  }
179
193
 
180
194
  /**
@@ -192,28 +206,30 @@
192
206
  * is left out either way.
193
207
  */
194
208
  function closeText(block) {
195
- var text = TEXTS[block.attr('data-ge-content-type')];
196
- var before = block.data('ge-text-before');
197
- var open = before ? attributesOf(block[0]) : null;
209
+ var text = TEXTS[block.getAttribute('data-ge-content-type')];
210
+ var before = readBefore.get(block);
211
+ var open = before ? attributesOf(block) : null;
198
212
 
199
213
  // Every content area is told, as in 5.x: one whose editor never
200
214
  // started is the plugin's to ignore
201
- if (text) { text.stop(block); }
215
+ if (text) { text.stop([block]); }
202
216
 
203
217
  // After stop, not before: an editor that restores the class
204
218
  // attribute it snapshotted would put ge-rte-active back
205
- block.removeClass('ge-rte-active');
219
+ dom.removeClass(block, 'ge-rte-active');
206
220
 
207
221
  if (before) {
208
- restoreAttributes(block, before, block.data('ge-text-ready') || before, open);
209
- block.removeData('ge-text-before').removeData('ge-text-ready');
222
+ restoreAttributes(block, before, readReady.get(block) || before, open);
223
+ readBefore.delete(block);
224
+ readReady.delete(block);
210
225
  }
211
226
  }
212
227
 
213
228
  function createTextControls(textBlock) {
214
- var block = textBlock.children('.ge-content');
215
- var type = block.attr('data-ge-content-type');
216
- var drawer = $('<div class="ge-tools-drawer ge-text-drawer" />').prependTo(textBlock);
229
+ var block = dom.child(textBlock, '.ge-content');
230
+ var type = block.getAttribute('data-ge-content-type');
231
+ var drawer = dom.element('div', { 'class': 'ge-tools-drawer ge-text-drawer' });
232
+ textBlock.insertBefore(drawer, textBlock.firstChild);
217
233
 
218
234
  ge.createMoveTool(drawer);
219
235
 
@@ -221,10 +237,11 @@
221
237
 
222
238
  // Which editor edits it, first in its settings: something to
223
239
  // know about it, not something to do with it
224
- $('<div class="ge-field ge-text-editor" />')
225
- .append($('<span class="ge-field-label" />').text(ge.t('panel.editor')))
226
- .append($('<span class="ge-field-value" />').text(textLabel(type)))
227
- .prependTo(details.children('.ge-details-general'));
240
+ var general = dom.child(details, '.ge-details-general');
241
+ var editor = dom.element('div', { 'class': 'ge-field ge-text-editor' });
242
+ editor.appendChild(dom.element('span', { 'class': 'ge-field-label' }, ge.t('panel.editor')));
243
+ editor.appendChild(dom.element('span', { 'class': 'ge-field-value' }, textLabel(type)));
244
+ general.insertBefore(editor, general.firstChild);
228
245
 
229
246
  settings.text_tools.forEach(function(hostTool) {
230
247
  ge.createTool(drawer, hostTool.title || '', hostTool.className || '',
@@ -236,7 +253,7 @@
236
253
  // Its editor lets go first: removed while open, it would
237
254
  // be left behind, attached to nothing
238
255
  closeText(block);
239
- textBlock.slideUp(function() {
256
+ dom.slideUp(textBlock, function() {
240
257
  textBlock.remove();
241
258
  removed();
242
259
  });
@@ -246,16 +263,18 @@
246
263
 
247
264
  /** A drawer for each text of ours in a text block that has none yet. */
248
265
  function markTexts() {
249
- ge.canvas.find('.ge-text-block').each(function() {
250
- var textBlock = $(this);
251
- if (textBlock.children('.ge-tools-drawer').length) { return; }
252
- if (!isOurs(textBlock.children('.ge-content'))) { return; }
266
+ dom.all(ge.canvas, '.ge-text-block').forEach(function(textBlock) {
267
+ if (dom.child(textBlock, '.ge-tools-drawer')) { return; }
268
+
269
+ var block = dom.child(textBlock, '.ge-content');
270
+ if (!block || !isOurs(block)) { return; }
253
271
 
254
272
  createTextControls(textBlock);
255
273
  });
256
274
  }
257
275
 
258
276
  var texts = offeredTexts();
277
+ var clicks = null; // The delegated click listener, while editing
259
278
 
260
279
  return {
261
280
  methods: {
@@ -281,8 +300,8 @@
281
300
  available: text.available ? function() { return text.available(); } : null,
282
301
  missingKey: text.missingKey,
283
302
  edit: function(block) {
284
- var textBlock = block.parent('.ge-text-block');
285
- if (textBlock.length && !textBlock.children('.ge-tools-drawer').length) {
303
+ var textBlock = block.parentElement;
304
+ if (dom.hasClass(textBlock, 'ge-text-block') && !dom.child(textBlock, '.ge-tools-drawer')) {
286
305
  createTextControls(textBlock);
287
306
  }
288
307
 
@@ -310,26 +329,28 @@
310
329
  onInit: function() {
311
330
  markTexts();
312
331
 
313
- ge.canvas.off('click.ge-text').on('click.ge-text', '.ge-content', onClick);
332
+ if (clicks) { ge.canvas.removeEventListener('click', clicks); }
333
+ clicks = dom.delegate(ge.canvas, 'click', '.ge-content', onClick);
314
334
  },
315
335
 
316
336
  // While the drawers and the text blocks are still there, as the
317
337
  // editors left them
318
338
  onBeforeDeinit: function() {
319
- ge.canvas.find('.ge-content').each(function() {
320
- if (isOurs($(this))) { closeText($(this)); }
339
+ dom.all(ge.canvas, '.ge-content').forEach(function(block) {
340
+ if (isOurs(block)) { closeText(block); }
321
341
  });
322
342
  },
323
343
 
324
344
  onDeinit: function() {
325
- ge.canvas.off('click.ge-text');
345
+ if (clicks) { ge.canvas.removeEventListener('click', clicks); }
346
+ clicks = null;
326
347
  },
327
348
 
328
349
  // The first time only: an undo says ready again, and by then the
329
350
  // host may have changed the content area itself
330
351
  onContentReady: function(area) {
331
- if (area.data('ge-text-before') && !area.data('ge-text-ready')) {
332
- area.data('ge-text-ready', attributesOf(area[0]));
352
+ if (readBefore.has(area) && !readReady.has(area)) {
353
+ readReady.set(area, attributesOf(area));
333
354
  }
334
355
  },
335
356
  };
@@ -338,6 +359,6 @@
338
359
  // Whatever the plugins setting says: content_types chooses the editors
339
360
  textFeature.always = true;
340
361
 
341
- $.fn.gridEditor.features.text = textFeature;
362
+ GridEditor.features.text = textFeature;
342
363
 
343
- })(jQuery);
364
+ }
@@ -0,0 +1,335 @@
1
+ /**
2
+ * Types for grid-editor's public API: the GridEditor class, its methods, its
3
+ * settings, and its events and their payloads.
4
+ *
5
+ * The plugin contract - the handle a plugin's factory gets - is not typed
6
+ * here; docs/plugins.md describes it. A plugin's factory is typed loosely as
7
+ * a function of that handle.
8
+ */
9
+
10
+ /** A breakpoint key. */
11
+ export type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
12
+
13
+ /** A view: a breakpoint, or every one at once. */
14
+ export type View = Breakpoint | 'all';
15
+
16
+ /** A column's size: units, Bootstrap's `col` (`'equal'`) or `col-auto` (`'auto'`). */
17
+ export type ColumnSize = number | 'equal' | 'auto';
18
+
19
+ /** A row's columns-per-row layout: row-cols per breakpoint, and how many columns. */
20
+ export interface RowColsLayout {
21
+ row_cols: Partial<Record<Breakpoint, number | 'auto'>>;
22
+ columns?: number;
23
+ }
24
+
25
+ /** What a row is made of: sizes, or a columns-per-row layout. */
26
+ export type RowLayout = ColumnSize[] | RowColsLayout;
27
+
28
+ /** An element, or a selector for the first element it matches. */
29
+ export type Target = Element | string;
30
+
31
+ /** Where a created node goes. The first one given wins; none leaves it detached. */
32
+ export interface Placement {
33
+ appendTo?: Target;
34
+ prependTo?: Target;
35
+ insertAfter?: Target;
36
+ insertBefore?: Target;
37
+ }
38
+
39
+ /** A host tool in a drawer: row_tools, col_tools and the rest. */
40
+ export interface HostTool {
41
+ title?: string;
42
+ className?: string;
43
+ iconClass?: string;
44
+ /** A click handler, or handlers by event name. `this` is the tool. */
45
+ on?: ((this: HTMLElement, event: Event) => void) | Record<string, (this: HTMLElement, event: Event) => void>;
46
+ }
47
+
48
+ /** A preset class toggle on a settings panel. */
49
+ export interface PresetClass {
50
+ label: string;
51
+ cssClass: string;
52
+ title?: string;
53
+ }
54
+
55
+ /** A content filter: run on init and deinit with the canvas. A string names a function on window. */
56
+ export type CustomFilter = ((canvas: HTMLElement, isInit: boolean) => void) | string;
57
+
58
+ /** The settings. Every one is optional. */
59
+ export interface GridEditorOptions {
60
+ new_row_layouts?: RowLayout[];
61
+ row_classes?: PresetClass[];
62
+ col_classes?: PresetClass[];
63
+ element_classes?: PresetClass[];
64
+ container_classes?: PresetClass[];
65
+ pane_classes?: PresetClass[];
66
+ text_classes?: PresetClass[];
67
+ row_tools?: HostTool[];
68
+ col_tools?: HostTool[];
69
+ element_tools?: HostTool[];
70
+ container_tools?: HostTool[];
71
+ tab_tools?: HostTool[];
72
+ accordion_tools?: HostTool[];
73
+ text_tools?: HostTool[];
74
+ drag_handle?: 'tool' | 'drawer';
75
+ toolbar_drag?: 'auto' | boolean;
76
+ /** The plugins to use, of any kind; null is every one loaded. */
77
+ plugins?: string[] | null;
78
+ /** The text editors offered, in order. */
79
+ content_types?: string[];
80
+ row_cols?: boolean;
81
+ utilities?: Record<string, unknown>;
82
+ elements?: { enabled?: boolean | 'auto'; selector?: string; auto?: boolean };
83
+ custom_filter?: CustomFilter | CustomFilter[] | '';
84
+ valid_col_sizes?: ColumnSize[];
85
+ valid_col_offsets?: number[];
86
+ add_column?: { size?: ColumnSize | null; picker?: boolean; delay?: number };
87
+ layout_modes?: View[];
88
+ default_view?: View;
89
+ resize?: { enabled?: boolean; handles?: string; balance?: 'next' | false };
90
+ /** A textarea whose html the canvas starts with. */
91
+ source_textarea?: Target | '';
92
+ edit_source?: boolean;
93
+ locale?: string;
94
+ locale_strings?: Record<string, string>;
95
+ callbacks?: Partial<GridEditorCallbacks>;
96
+ confirm_delete?: boolean;
97
+ settings_panel?: 'offcanvas' | 'popover' | 'modal' | 'inline';
98
+ drag?: { delay?: number; touch_delay?: number; threshold?: number; animation?: number; scroll?: boolean };
99
+ tinymce?: { config?: Record<string, unknown> };
100
+ ckeditor?: { config?: Record<string, unknown> };
101
+ summernote?: { config?: Record<string, unknown> };
102
+ [plugin: string]: unknown;
103
+ }
104
+
105
+ /** Where a node was, or went: its parent and its index among the blocks there. */
106
+ export interface Position {
107
+ parent: HTMLElement;
108
+ index: number;
109
+ }
110
+
111
+ /** What a breakpoint said before the all view's write took it off. */
112
+ export interface Cleared {
113
+ breakpoint: Breakpoint;
114
+ value: string | number;
115
+ }
116
+
117
+ /** What every notification carries. */
118
+ export interface Payload {
119
+ /** What the node is: row, column, text, plain, element, tab, accordion-item, a container's type… */
120
+ kind: string;
121
+ node: HTMLElement;
122
+ /** Where the node is going, or coming from on a delete; null while it is detached. */
123
+ parent: HTMLElement | null;
124
+ canvas: HTMLElement;
125
+ breakpoint: View;
126
+ source: 'api' | 'tool' | 'dragdrop' | 'paste' | 'panel' | string;
127
+ /** A pane inside a container. */
128
+ container?: HTMLElement;
129
+ }
130
+
131
+ export interface MovePayload extends Payload {
132
+ from: Position;
133
+ to?: Position;
134
+ }
135
+
136
+ export interface ResizePayload extends Payload {
137
+ from: ColumnSize | null;
138
+ to: ColumnSize | null;
139
+ cleared?: Cleared[];
140
+ }
141
+
142
+ export interface IndentPayload extends Payload {
143
+ from: number;
144
+ to: number;
145
+ cleared?: Cleared[];
146
+ }
147
+
148
+ export interface UtilityPayload extends Payload {
149
+ family: string;
150
+ from: string | null;
151
+ to: string | null;
152
+ tiers: Breakpoint[];
153
+ cleared: Cleared[];
154
+ }
155
+
156
+ export interface ConvertPayload extends Payload {
157
+ from: 'plain';
158
+ to: string;
159
+ }
160
+
161
+ export interface EditHtmlPayload extends Omit<Payload, 'node'> {
162
+ node: HTMLElement | null;
163
+ /** Every element written, which may be several. */
164
+ nodes?: HTMLElement[];
165
+ from: string;
166
+ to: string;
167
+ }
168
+
169
+ export interface PopupOrphanPayload extends Payload {
170
+ missing: string;
171
+ }
172
+
173
+ export interface ViewChangePayload {
174
+ canvas: HTMLElement;
175
+ breakpoint: View;
176
+ from: View;
177
+ to: View;
178
+ }
179
+
180
+ /** The events, by name, with their payloads. Adding fires a specific name and the generic one. */
181
+ export interface GridEditorEventMap {
182
+ 'grideditor:before-add': Payload;
183
+ 'grideditor:after-add': Payload;
184
+ 'grideditor:before-add-row': Payload;
185
+ 'grideditor:after-add-row': Payload;
186
+ 'grideditor:before-add-column': Payload;
187
+ 'grideditor:after-add-column': Payload;
188
+ 'grideditor:before-add-text': Payload;
189
+ 'grideditor:after-add-text': Payload;
190
+ 'grideditor:before-add-element': Payload;
191
+ 'grideditor:after-add-element': Payload;
192
+ 'grideditor:before-add-container': Payload;
193
+ 'grideditor:after-add-container': Payload;
194
+ 'grideditor:before-add-tab': Payload;
195
+ 'grideditor:after-add-tab': Payload;
196
+ 'grideditor:before-add-accordion-item': Payload;
197
+ 'grideditor:after-add-accordion-item': Payload;
198
+ 'grideditor:before-add-section': Payload;
199
+ 'grideditor:after-add-section': Payload;
200
+ 'grideditor:before-delete': Payload;
201
+ 'grideditor:after-delete': Payload;
202
+ 'grideditor:before-move': MovePayload;
203
+ 'grideditor:after-move': MovePayload;
204
+ 'grideditor:before-resize': ResizePayload;
205
+ 'grideditor:after-resize': ResizePayload;
206
+ 'grideditor:before-indent': IndentPayload;
207
+ 'grideditor:after-indent': IndentPayload;
208
+ 'grideditor:before-utility': UtilityPayload;
209
+ 'grideditor:after-utility': UtilityPayload;
210
+ 'grideditor:before-convert': ConvertPayload;
211
+ 'grideditor:after-convert': ConvertPayload;
212
+ 'grideditor:before-edit-html': EditHtmlPayload;
213
+ 'grideditor:after-edit-html': EditHtmlPayload;
214
+ 'grideditor:after-copy': Payload;
215
+ 'grideditor:popup-orphan': PopupOrphanPayload;
216
+ 'grideditor:view-change': ViewChangePayload;
217
+ }
218
+
219
+ /** An event the editor dispatches on its canvas: a CustomEvent whose detail is the payload. */
220
+ export type GridEditorEvent<K extends keyof GridEditorEventMap> = CustomEvent<GridEditorEventMap[K]>;
221
+
222
+ /** 'grideditor:before-add-row' is the callback before_add_row. */
223
+ type CallbackName<K> = K extends `grideditor:${infer Name}` ? Snake<Name> : never;
224
+ type Snake<S extends string> = S extends `${infer Head}-${infer Tail}` ? `${Head}_${Snake<Tail>}` : S;
225
+
226
+ /** The callbacks setting: the events by another route. Returning false cancels a before-*. */
227
+ export type GridEditorCallbacks = {
228
+ [K in keyof GridEditorEventMap as CallbackName<K>]: (payload: GridEditorEventMap[K]) => boolean | void;
229
+ };
230
+
231
+ /** A plugin's factory: called once per editor with the handle in docs/plugins.md. */
232
+ export type PluginFactory = ((ge: any) => Record<string, unknown>) & { always?: boolean };
233
+
234
+ export interface CreateColumnOptions extends Placement {
235
+ offset?: number;
236
+ /** Html, or a node: a text of the first editor offered, or plain content with none. */
237
+ content?: string | Node;
238
+ }
239
+
240
+ export interface CreateTextOptions extends Placement {
241
+ content?: string | Node;
242
+ }
243
+
244
+ export interface CreateElementOptions extends Placement {
245
+ type?: string;
246
+ label?: string;
247
+ }
248
+
249
+ export interface CreateSectionOptions extends Placement {
250
+ width?: 'fixed' | 'fluid' | Breakpoint;
251
+ rows?: RowLayout[];
252
+ }
253
+
254
+ export interface PaneOptions {
255
+ label?: string;
256
+ [option: string]: unknown;
257
+ }
258
+
259
+ /** An editor on a canvas element. */
260
+ export declare class GridEditor {
261
+ /**
262
+ * An editor on `target`. An element carries one at most: asked for a
263
+ * second, this gives back the first, with its options, and warns once.
264
+ * Throws a TypeError when `target` is neither an element nor a selector
265
+ * that matches one.
266
+ */
267
+ constructor(target: Target, options?: GridEditorOptions);
268
+
269
+ /** The same as `new GridEditor(target, options)`. */
270
+ static create(target: Target, options?: GridEditorOptions): GridEditor;
271
+ /** The editor on `target`, or null. */
272
+ static get(target: Target | null | undefined): GridEditor | null;
273
+
274
+ static containers: Record<string, PluginFactory>;
275
+ static features: Record<string, PluginFactory>;
276
+ static utilities: Record<string, PluginFactory>;
277
+ static texts: Record<string, PluginFactory>;
278
+ static locales: Record<string, Record<string, string>>;
279
+ /** A string from the locale `settings.locale` names, English when it has none. */
280
+ static t(settings: { locale?: string; locale_strings?: Record<string, string> }, key: string, params?: Record<string, string | number>): string;
281
+ /** SortableJS, for a page that imports it rather than loading it as window.Sortable. */
282
+ static Sortable: unknown;
283
+ /** Bootstrap's javascript (only its Modal is used), for a page with no window.bootstrap. */
284
+ static bootstrap: { Modal?: unknown } | null;
285
+ static version: string;
286
+
287
+ /** The canvas element. */
288
+ readonly canvas: HTMLElement;
289
+ /** A read-only copy of the settings the editor runs with. */
290
+ readonly settings: Readonly<GridEditorOptions>;
291
+
292
+ /** The html to save: no drawers, no editor classes, no inline styles. */
293
+ getHtml(): string;
294
+ /** getHtml without grid-editor's marking, for publishing. It cannot be edited again as it was. */
295
+ getPlainHtml(): string;
296
+ /** Run the editing pass over the canvas again, after markup was put in. */
297
+ init(): this;
298
+ /** Take the editing furniture off, leaving the markup. */
299
+ deinit(): this;
300
+ /** deinit(), then init(). */
301
+ reset(): this;
302
+ /** Take the editor off: the markup stays, everything else goes. */
303
+ destroy(): this;
304
+ changeView(view: View): this;
305
+ getView(): View;
306
+ setLocale(code: string): this;
307
+ createRow(layout?: RowLayout, options?: Placement): HTMLElement | null;
308
+ createColumn(size?: ColumnSize | null, options?: CreateColumnOptions): HTMLElement | null;
309
+ createText(type?: string, options?: CreateTextOptions): HTMLElement | null;
310
+ createText(options: CreateTextOptions): HTMLElement | null;
311
+ createElement(content: string | Node | ArrayLike<Node>, options?: CreateElementOptions): HTMLElement | null;
312
+ createSection(options?: CreateSectionOptions): HTMLElement | null;
313
+ createContainer(type: string, options?: Placement & Record<string, unknown>): HTMLElement | null;
314
+ addTab(container: Target, options?: PaneOptions): HTMLElement | null;
315
+ addAccordionItem(container: Target, options?: PaneOptions): HTMLElement | null;
316
+ /** A utility's value on a node in a view (the current one by default), or null. */
317
+ getUtility(node: Target, family: string, view?: View): string | null;
318
+ /** Write one through the events; null is inherit. False when canceled or nothing changed. */
319
+ setUtility(node: Target, family: string, value: string | number | null, view?: View): boolean;
320
+ }
321
+
322
+ export default GridEditor;
323
+
324
+ declare global {
325
+ interface Window {
326
+ GridEditor: typeof GridEditor;
327
+ }
328
+
329
+ interface HTMLElementEventMap extends GridEditorEventMap_ {}
330
+ }
331
+
332
+ /** The events on any element, so canvas.addEventListener('grideditor:...') is typed. */
333
+ type GridEditorEventMap_ = {
334
+ [K in keyof GridEditorEventMap]: CustomEvent<GridEditorEventMap[K]>;
335
+ };