@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
@@ -8,7 +8,7 @@
8
8
  * What it can ask the editor for is the handle its factory is called with,
9
9
  * described in docs/plugins.md.
10
10
  *
11
- * <script src="dist/jquery.grideditor.min.js"></script>
11
+ * <script src="dist/grideditor.min.js"></script>
12
12
  * <script src="dist/plugins/grideditor.clipboard.min.js"></script>
13
13
  *
14
14
  * What is copied is kept in localStorage, so it survives a reload and can be
@@ -18,9 +18,10 @@
18
18
  * A paste is an add like any other - before-add-* and after-add-*, with
19
19
  * `source: 'paste'` - so a host can turn one away.
20
20
  */
21
- (function($) {
21
+ import { GridEditor } from '../grideditor.js';
22
+ import * as dom from '../dom.js';
22
23
 
23
- $.extend($.fn.gridEditor.locales.en, {
24
+ Object.assign(GridEditor.locales.en, {
24
25
  'tool.copy': 'Copy',
25
26
  'tool.paste': 'Paste',
26
27
  'clipboard.paste_row': 'Paste row',
@@ -33,7 +34,6 @@ var VERSION = 1;
33
34
 
34
35
  /** Where nothing can be stored, what was copied lives here, for this page. */
35
36
  var memory = null;
36
- var editors = 0;
37
37
 
38
38
  /**
39
39
  * What each drawer takes when something is pasted into it, by the kind of the
@@ -83,18 +83,23 @@ function write(clip) {
83
83
  memory = clip;
84
84
  }
85
85
 
86
- $(document).trigger(CHANGE);
86
+ announce();
87
+ }
88
+
89
+ /** Every editor on the page looks at the clipboard again. */
90
+ function announce() {
91
+ document.dispatchEvent(new CustomEvent(CHANGE));
87
92
  }
88
93
 
89
94
  // Another tab copied something: every editor here looks again
90
- $(window).on('storage', function(e) {
91
- if (e.originalEvent && e.originalEvent.key === STORAGE_ITEM) { $(document).trigger(CHANGE); }
95
+ window.addEventListener('storage', function(e) {
96
+ if (e.key === STORAGE_ITEM) { announce(); }
92
97
  });
93
98
 
94
- $.fn.gridEditor.features.clipboard = function(ge) {
99
+ GridEditor.features.clipboard = function(ge) {
95
100
 
96
- var namespace = '.ge-clipboard-' + (++editors);
97
101
  var shown = null; // What the toolbar's paste buttons stand for
102
+ var listening = false; // Whether refresh is on the document's change event
98
103
 
99
104
  function used(name) {
100
105
  return !ge.settings.plugins || ge.settings.plugins.indexOf(name) !== -1;
@@ -103,10 +108,10 @@ $.fn.gridEditor.features.clipboard = function(ge) {
103
108
  /** A category this editor can take: the plugin that makes it is here. */
104
109
  function available(clip) {
105
110
  if (clip.category === 'container') {
106
- return !!$.fn.gridEditor.containers[clip.kind] && used(clip.kind);
111
+ return !!GridEditor.containers[clip.kind] && used(clip.kind);
107
112
  }
108
- if (clip.category === 'section') { return !!$.fn.gridEditor.features.sections && used('sections'); }
109
- if (clip.category === 'element') { return !!$.fn.gridEditor.features.elements && used('elements'); }
113
+ if (clip.category === 'section') { return !!GridEditor.features.sections && used('sections'); }
114
+ if (clip.category === 'element') { return !!GridEditor.features.elements && used('elements'); }
110
115
 
111
116
  return true;
112
117
  }
@@ -116,7 +121,7 @@ $.fn.gridEditor.features.clipboard = function(ge) {
116
121
  }
117
122
 
118
123
  function categoryOf(kind) {
119
- if ($.fn.gridEditor.containers[kind]) { return 'container'; }
124
+ if (GridEditor.containers[kind]) { return 'container'; }
120
125
 
121
126
  return ['row', 'column', 'section', 'text', 'element'].indexOf(kind) !== -1 ? kind : null;
122
127
  }
@@ -129,10 +134,15 @@ $.fn.gridEditor.features.clipboard = function(ge) {
129
134
 
130
135
  // The canvas came back with new drawers: the one to flash is the
131
136
  // node's new copy tool
132
- var tool = ge.drawerOf(node).find('> .ge-copy');
133
- tool.addClass('ge-copied').find('i').attr('class', 'bi bi-check2');
137
+ var tool = dom.child(ge.drawerOf(node), '.ge-copy');
138
+ if (!tool) { return; }
139
+
140
+ var icon = dom.one(tool, 'i');
141
+ dom.addClass(tool, 'ge-copied');
142
+ if (icon) { icon.setAttribute('class', 'bi bi-check2'); }
134
143
  setTimeout(function() {
135
- tool.removeClass('ge-copied').find('i').attr('class', 'bi bi-copy');
144
+ dom.removeClass(tool, 'ge-copied');
145
+ if (icon) { icon.setAttribute('class', 'bi bi-copy'); }
136
146
  }, 1200);
137
147
  }
138
148
 
@@ -148,9 +158,12 @@ $.fn.gridEditor.features.clipboard = function(ge) {
148
158
  * them: two copies of a tab strip pointing at one set of panes is a tab
149
159
  * strip that opens the other copy's tabs. An id the page does not have
150
160
  * is kept, so pasting into another page changes nothing.
161
+ *
162
+ * Parsed the way innerHTML parses, so a <script> in what was copied is
163
+ * markup, pasted like the rest, and does not run in the editor.
151
164
  */
152
165
  function fresh(html) {
153
- var node = $($.parseHTML(html.trim(), document, true)).first();
166
+ var node = dom.create(html);
154
167
  var renamed = {};
155
168
  var taken = function(id) {
156
169
  return !!document.getElementById(id) || Object.keys(renamed).some(function(old) {
@@ -158,8 +171,8 @@ $.fn.gridEditor.features.clipboard = function(ge) {
158
171
  });
159
172
  };
160
173
 
161
- node.find('[id]').addBack('[id]').each(function() {
162
- var id = this.id;
174
+ dom.selfAndAll(node, '[id]').forEach(function(element) {
175
+ var id = element.id;
163
176
  if (!document.getElementById(id)) { return; }
164
177
 
165
178
  var generated = GENERATED_ID.exec(id);
@@ -174,14 +187,12 @@ $.fn.gridEditor.features.clipboard = function(ge) {
174
187
  }
175
188
 
176
189
  renamed[id] = next;
177
- this.id = next;
190
+ element.id = next;
178
191
  });
179
192
 
180
193
  if (!Object.keys(renamed).length) { return node; }
181
194
 
182
- node.find('*').addBack().each(function() {
183
- var element = this;
184
-
195
+ dom.selfAndAll(node, '*').forEach(function(element) {
185
196
  REFERENCES.forEach(function(name) {
186
197
  var value = element.getAttribute(name);
187
198
  if (value === null) { return; }
@@ -205,13 +216,13 @@ $.fn.gridEditor.features.clipboard = function(ge) {
205
216
  function refresh() {
206
217
  var clip = read();
207
218
 
208
- ge.canvas.find('.ge-paste').each(function() {
209
- $(this).toggle(fits(clip, $(this).attr('data-ge-paste').split(' ')));
219
+ dom.all(ge.canvas, '.ge-paste').forEach(function(tool) {
220
+ dom.toggle(tool, fits(clip, tool.getAttribute('data-ge-paste').split(' ')));
210
221
  });
211
222
 
212
- ge.toolbarItems('clipboard').each(function() {
213
- var item = TOOLBAR[parseInt($(this).attr('data-ge-item'), 10)];
214
- $(this).toggle(fits(clip, [item.kind]));
223
+ ge.toolbarItems('clipboard').forEach(function(button) {
224
+ var item = TOOLBAR[parseInt(button.getAttribute('data-ge-item'), 10)];
225
+ dom.toggle(button, fits(clip, [item.kind]));
215
226
  });
216
227
 
217
228
  shown = clip;
@@ -221,7 +232,7 @@ $.fn.gridEditor.features.clipboard = function(ge) {
221
232
  { kind: 'row', labelKey: 'clipboard.paste_row' },
222
233
  { kind: 'section', labelKey: 'clipboard.paste_section' },
223
234
  ].map(function(item) {
224
- return $.extend(item, {
235
+ return Object.assign(item, {
225
236
  iconClass: 'bi bi-clipboard-plus',
226
237
  // On the right, as an icon: pasting is not one of the things
227
238
  // the add buttons make
@@ -244,25 +255,26 @@ $.fn.gridEditor.features.clipboard = function(ge) {
244
255
  var categories = TARGETS[kind];
245
256
  if (!categories) { return; }
246
257
 
247
- ge.createTool(drawer, ge.t('tool.paste'), 'ge-paste', 'bi bi-clipboard-plus', function() {
258
+ var tool = ge.createTool(drawer, ge.t('tool.paste'), 'ge-paste', 'bi bi-clipboard-plus', function() {
248
259
  paste(node, categories);
249
260
  });
250
- drawer.children('.ge-paste').last()
251
- .attr('data-ge-paste', categories.join(' '))
252
- .toggle(fits(read(), categories));
261
+ tool.setAttribute('data-ge-paste', categories.join(' '));
262
+ dom.toggle(tool, fits(read(), categories));
253
263
  },
254
264
 
255
265
  toolbar: TOOLBAR,
256
266
 
257
267
  onInit: function() {
258
268
  refresh();
259
- $(document).off(CHANGE + namespace).on(CHANGE + namespace, refresh);
269
+ if (!listening) {
270
+ document.addEventListener(CHANGE, refresh);
271
+ listening = true;
272
+ }
260
273
  },
261
274
 
262
275
  onDeinit: function() {
263
- $(document).off(CHANGE + namespace);
276
+ document.removeEventListener(CHANGE, refresh);
277
+ listening = false;
264
278
  },
265
279
  };
266
280
  };
267
-
268
- })(jQuery);
@@ -16,15 +16,16 @@
16
16
  * <script src="codemirror/mode/javascript/javascript.js"></script>
17
17
  * <script src="codemirror/mode/css/css.js"></script>
18
18
  * <script src="codemirror/mode/htmlmixed/htmlmixed.js"></script>
19
- * <script src="dist/jquery.grideditor.min.js"></script>
19
+ * <script src="dist/grideditor.min.js"></script>
20
20
  * <script src="dist/plugins/grideditor.codemirror-inline.min.js"></script>
21
21
  *
22
22
  * Without CodeMirror on the page the html is edited in a plain textarea.
23
23
  * CodeMirror's options are the codemirror plugin's, codemirror.config.
24
24
  */
25
- (function($) {
25
+ import { GridEditor } from '../grideditor.js';
26
+ import * as dom from '../dom.js';
26
27
 
27
- $.extend($.fn.gridEditor.locales.en, {
28
+ Object.assign(GridEditor.locales.en, {
28
29
  'tool.edit_html': 'Edit html',
29
30
  'codemirror.apply': 'Apply',
30
31
  'codemirror.cancel': 'Cancel',
@@ -33,14 +34,14 @@ $.extend($.fn.gridEditor.locales.en, {
33
34
  /** What has html of its own to edit: a pane's is split between its button and its body. */
34
35
  var KINDS = ['row', 'column', 'text', 'plain', 'element', 'section'];
35
36
 
36
- $.fn.gridEditor.features['codemirror-inline'] = function(ge) {
37
+ GridEditor.features['codemirror-inline'] = function(ge) {
37
38
 
38
39
  var open = []; // The blocks being edited: { node, kind, from, wrapper, textarea, editor }
39
40
 
40
41
  function options() {
41
42
  var own = (ge.settings.codemirror && ge.settings.codemirror.config) || {};
42
43
 
43
- return $.extend({
44
+ return Object.assign({
44
45
  mode: 'htmlmixed',
45
46
  lineNumbers: true,
46
47
  lineWrapping: true,
@@ -53,29 +54,29 @@ $.fn.gridEditor.features['codemirror-inline'] = function(ge) {
53
54
 
54
55
  /** What stands for the node in its column: a text's text block, or the node. */
55
56
  function anchorOf(node) {
56
- var textBlock = node.parent('.ge-text-block');
57
- return textBlock.length ? textBlock : node;
57
+ var textBlock = node.parentElement;
58
+ return dom.hasClass(textBlock, 'ge-text-block') ? textBlock : node;
58
59
  }
59
60
 
60
61
  function entryOf(node) {
61
- return open.filter(function(entry) { return entry.node[0] === node[0]; })[0] || null;
62
+ return open.filter(function(entry) { return entry.node === node; })[0] || null;
62
63
  }
63
64
 
64
65
  function editable(node, kind) {
65
- return KINDS.indexOf(kind) !== -1 || node.is('[data-ge-container]');
66
+ return KINDS.indexOf(kind) !== -1 || dom.is(node, '[data-ge-container]');
66
67
  }
67
68
 
68
69
  /** The editor where the block was, the block hidden behind it. */
69
70
  function show(entry) {
70
- var anchor = anchorOf(entry.node).addClass('ge-code-hidden');
71
- entry.wrapper.insertAfter(anchor);
71
+ var anchor = dom.addClass(anchorOf(entry.node), 'ge-code-hidden');
72
+ dom.insertAfter(entry.wrapper, anchor);
72
73
  if (entry.editor) { entry.editor.refresh(); }
73
74
  }
74
75
 
75
76
  function hide(entry) {
76
- entry.wrapper.detach();
77
- anchorOf(entry.node).removeClass('ge-code-hidden');
78
- entry.node.removeClass('ge-code-hidden');
77
+ entry.wrapper.remove();
78
+ dom.removeClass(anchorOf(entry.node), 'ge-code-hidden');
79
+ dom.removeClass(entry.node, 'ge-code-hidden');
79
80
  }
80
81
 
81
82
  function close(entry) {
@@ -94,30 +95,33 @@ $.fn.gridEditor.features['codemirror-inline'] = function(ge) {
94
95
  // As getHtml gives it: no drawers, no editor open in it
95
96
  from: ge.nodeHtml(node),
96
97
  // A drawer, to the editor: never content, never a block to move
97
- wrapper: $('<div class="ge-tools-drawer ge-code-inline" />'),
98
+ wrapper: dom.element('div', { 'class': 'ge-tools-drawer ge-code-inline' }),
98
99
  editor: null,
99
100
  };
100
- entry.textarea = $('<textarea class="ge-code-inline-source" />').val(entry.from).appendTo(entry.wrapper);
101
-
102
- var bar = $('<div class="ge-code-inline-bar" />').appendTo(entry.wrapper);
103
- $('<button type="button" class="btn btn-sm btn-primary ge-code-apply" />')
104
- .text(ge.t('codemirror.apply'))
105
- .on('click', function() { apply(entry); })
106
- .appendTo(bar);
107
- $('<button type="button" class="btn btn-sm btn-outline-secondary ge-code-cancel" />')
108
- .text(ge.t('codemirror.cancel'))
109
- .on('click', function() { close(entry); })
110
- .appendTo(bar);
101
+ entry.textarea = entry.wrapper.appendChild(dom.element('textarea', { 'class': 'ge-code-inline-source' }));
102
+ entry.textarea.value = entry.from;
103
+
104
+ var bar = entry.wrapper.appendChild(dom.element('div', { 'class': 'ge-code-inline-bar' }));
105
+ var applyButton = bar.appendChild(dom.element('button', {
106
+ type: 'button',
107
+ 'class': 'btn btn-sm btn-primary ge-code-apply',
108
+ }, ge.t('codemirror.apply')));
109
+ applyButton.addEventListener('click', function() { apply(entry); });
110
+ var cancelButton = bar.appendChild(dom.element('button', {
111
+ type: 'button',
112
+ 'class': 'btn btn-sm btn-outline-secondary ge-code-cancel',
113
+ }, ge.t('codemirror.cancel')));
114
+ cancelButton.addEventListener('click', function() { close(entry); });
111
115
 
112
116
  open.push(entry);
113
117
  show(entry);
114
118
 
115
119
  if (window.CodeMirror) {
116
- entry.editor = window.CodeMirror.fromTextArea(entry.textarea[0], options());
117
- $(entry.editor.getWrapperElement()).addClass('ge-code-editor');
120
+ entry.editor = window.CodeMirror.fromTextArea(entry.textarea, options());
121
+ dom.addClass(entry.editor.getWrapperElement(), 'ge-code-editor');
118
122
  entry.editor.focus();
119
123
  } else {
120
- entry.textarea.trigger('focus');
124
+ entry.textarea.focus();
121
125
  }
122
126
  }
123
127
 
@@ -127,7 +131,7 @@ $.fn.gridEditor.features['codemirror-inline'] = function(ge) {
127
131
  * getHtml, so what was written is read as the editor reads any markup.
128
132
  */
129
133
  function apply(entry) {
130
- var to = entry.editor ? entry.editor.getValue() : entry.textarea.val();
134
+ var to = entry.editor ? entry.editor.getValue() : entry.textarea.value;
131
135
  var payload = ge.payloadFor(entry.kind, entry.node, { source: 'tool', from: entry.from, to: to });
132
136
 
133
137
  // Canceled, the editor stays open with what was written in it
@@ -135,15 +139,26 @@ $.fn.gridEditor.features['codemirror-inline'] = function(ge) {
135
139
 
136
140
  close(entry);
137
141
 
138
- var instance = ge.canvas.data('grideditor');
142
+ var instance = GridEditor.get(ge.canvas);
139
143
  instance.deinit();
140
144
 
141
- var made = $('<div />').html(to).contents();
142
- entry.node.replaceWith(made);
145
+ // Parsed as innerHTML parses: a <script> written here is markup,
146
+ // and does not run in the editor
147
+ var made = dom.parse(to);
148
+ var parent = entry.node.parentElement;
149
+ entry.node.replaceWith.apply(entry.node, made);
143
150
 
144
151
  instance.init();
145
152
 
146
- ge.emit('after-edit-html', ge.payloadFor(entry.kind, made.filter('*'), {
153
+ // The node is the first element written, or none when only text was;
154
+ // `nodes` is every element written, which may be several
155
+ var written = made.filter(function(node) { return node.nodeType === 1; });
156
+ var first = written[0] || null;
157
+
158
+ ge.emit('after-edit-html', ge.payloadFor(entry.kind, first || entry.node, {
159
+ node: first,
160
+ nodes: written,
161
+ parent: first ? first.parentElement : parent,
147
162
  source: 'tool',
148
163
  from: entry.from,
149
164
  to: to,
@@ -174,7 +189,7 @@ $.fn.gridEditor.features['codemirror-inline'] = function(ge) {
174
189
 
175
190
  onInit: function() {
176
191
  open.slice().forEach(function(entry) {
177
- if (!$.contains(document.documentElement, entry.node[0])) {
192
+ if (!dom.attached(entry.node)) {
178
193
  if (entry.editor) { entry.editor.toTextArea(); }
179
194
  entry.wrapper.remove();
180
195
  open.splice(open.indexOf(entry), 1);
@@ -186,5 +201,3 @@ $.fn.gridEditor.features['codemirror-inline'] = function(ge) {
186
201
  },
187
202
  };
188
203
  };
189
-
190
- })(jQuery);
@@ -13,7 +13,7 @@
13
13
  * <script src="codemirror/mode/javascript/javascript.js"></script>
14
14
  * <script src="codemirror/mode/css/css.js"></script>
15
15
  * <script src="codemirror/mode/htmlmixed/htmlmixed.js"></script>
16
- * <script src="dist/jquery.grideditor.min.js"></script>
16
+ * <script src="dist/grideditor.min.js"></script>
17
17
  * <script src="dist/plugins/grideditor.codemirror.min.js"></script>
18
18
  *
19
19
  * CodeMirror 5 rather than 6: 6 comes as ES modules only, for a bundler,
@@ -21,13 +21,14 @@
21
21
  * CodeMirror on the page the source view is the textarea, as before, and
22
22
  * the console says why.
23
23
  */
24
- (function($) {
24
+ import { GridEditor } from '../grideditor.js';
25
+ import * as dom from '../dom.js';
25
26
 
26
- $.extend($.fn.gridEditor.locales.en, {
27
+ Object.assign(GridEditor.locales.en, {
27
28
  'error.codemirror_missing': 'CodeMirror not available! Make sure you loaded the CodeMirror js file; the source is edited in a plain textarea without it.',
28
29
  });
29
30
 
30
- $.fn.gridEditor.features.codemirror = function(ge) {
31
+ GridEditor.features.codemirror = function(ge) {
31
32
 
32
33
  var editor = null;
33
34
  var warned = false;
@@ -35,7 +36,7 @@ $.fn.gridEditor.features.codemirror = function(ge) {
35
36
  function options() {
36
37
  var own = (ge.settings.codemirror && ge.settings.codemirror.config) || {};
37
38
 
38
- return $.extend({
39
+ return Object.assign({
39
40
  mode: 'htmlmixed',
40
41
  lineNumbers: true,
41
42
  lineWrapping: true,
@@ -56,10 +57,10 @@ $.fn.gridEditor.features.codemirror = function(ge) {
56
57
  return;
57
58
  }
58
59
 
59
- var height = textarea.height();
60
+ var height = dom.outerHeight(textarea);
60
61
 
61
- editor = window.CodeMirror.fromTextArea(textarea[0], options());
62
- $(editor.getWrapperElement()).addClass('ge-code-editor');
62
+ editor = window.CodeMirror.fromTextArea(textarea, options());
63
+ dom.addClass(editor.getWrapperElement(), 'ge-code-editor');
63
64
  editor.setSize(null, height);
64
65
  editor.focus();
65
66
  },
@@ -75,5 +76,3 @@ $.fn.gridEditor.features.codemirror = function(ge) {
75
76
  },
76
77
  };
77
78
  };
78
-
79
- })(jQuery);
@@ -6,16 +6,17 @@
6
6
  * beside the texts, instead of rich text. What it can ask the editor for is
7
7
  * the handle its factory is called with, described in docs/plugins.md.
8
8
  *
9
- * <script src="dist/jquery.grideditor.min.js"></script>
9
+ * <script src="dist/grideditor.min.js"></script>
10
10
  * <script src="dist/plugins/grideditor.elements.min.js"></script>
11
11
  *
12
12
  * Up to 5.x an element lived inside a content area, among the text. Markup
13
13
  * saved that way still loads: the editor takes each element out of the text
14
14
  * it sits in, which is what `cuts` is for.
15
15
  */
16
- (function($) {
16
+ import { GridEditor } from '../grideditor.js';
17
+ import * as dom from '../dom.js';
17
18
 
18
- $.extend($.fn.gridEditor.locales.en, {
19
+ Object.assign(GridEditor.locales.en, {
19
20
  'tool.delete_element': 'Remove element',
20
21
  'tool.element_info': 'Element: {name}',
21
22
  'confirm.delete_element': 'Delete element?',
@@ -24,47 +25,49 @@ $.extend($.fn.gridEditor.locales.en, {
24
25
  /** A column's children that are something else than an element, whatever elements.auto says. */
25
26
  var NOT_ELEMENTS = '.row, .ge-content, .ge-text-block, [data-ge-container], .ge-tools-drawer, .ge-resize-handle';
26
27
 
27
- $.fn.gridEditor.features.elements = function(ge) {
28
+ GridEditor.features.elements = function(ge) {
28
29
 
29
30
  var warnedIntoText = false;
30
31
 
31
32
  function elementsEnabled() {
32
33
  if (ge.settings.elements.enabled !== 'auto') { return !!ge.settings.elements.enabled; }
33
34
 
34
- return ge.settings.elements.auto || ge.canvas.find(ge.settings.elements.selector).length > 0;
35
+ return ge.settings.elements.auto || !!ge.canvas.querySelector(ge.settings.elements.selector);
35
36
  }
36
37
 
37
38
  /** Whether a child of a column is an element. */
38
39
  function isElement(node) {
39
40
  return ge.settings.elements.auto
40
- ? !node.is(NOT_ELEMENTS)
41
- : node.is(ge.settings.elements.selector);
41
+ ? !node.matches(NOT_ELEMENTS)
42
+ : node.matches(ge.settings.elements.selector);
42
43
  }
43
44
 
44
45
  function markElements() {
45
46
  if (!elementsEnabled()) { return; }
46
47
 
47
- ge.canvas.find('.column').children().each(function() {
48
- var element = $(this);
49
- if (!element.hasClass('ge-element') && !isElement(element)) { return; }
48
+ dom.all(ge.canvas, '.column').forEach(function(column) {
49
+ dom.children(column).forEach(function(element) {
50
+ if (!dom.hasClass(element, 'ge-element') && !isElement(element)) { return; }
50
51
 
51
- element.addClass('ge-element');
52
- if (!element.find('> .ge-tools-drawer').length) { createElementControls(element); }
52
+ dom.addClass(element, 'ge-element');
53
+ if (!dom.child(element, '.ge-tools-drawer')) { createElementControls(element); }
54
+ });
53
55
  });
54
56
  }
55
57
 
56
58
  function unmarkElements() {
57
- ge.canvas.find('.ge-element').each(function() {
58
- var element = $(this).removeClass('ge-element');
59
+ dom.all(ge.canvas, '.ge-element').forEach(function(element) {
60
+ dom.removeClass(element, 'ge-element');
59
61
 
60
62
  // A host element that had no class of its own should not come
61
63
  // back from getHtml carrying an empty one
62
- if (!element.attr('class')) { element.removeAttr('class'); }
64
+ dom.dropEmptyClass(element);
63
65
  });
64
66
  }
65
67
 
66
68
  function createElementControls(element) {
67
- var drawer = $('<div class="ge-tools-drawer ge-element-drawer" />').prependTo(element);
69
+ var drawer = dom.element('div', { 'class': 'ge-tools-drawer ge-element-drawer' });
70
+ element.insertBefore(drawer, element.firstChild);
68
71
 
69
72
  ge.createMoveTool(drawer);
70
73
  ge.createTool(drawer, ge.t('tool.element_info', { name: elementName(element) }),
@@ -78,18 +81,18 @@ $.fn.gridEditor.features.elements = function(ge) {
78
81
 
79
82
  ge.createTool(drawer, ge.t('tool.delete_element'), 'ge-delete-element', 'bi bi-trash', function() {
80
83
  ge.deleteNode('element', element, ge.t('confirm.delete_element'), function(removed) {
81
- element.animate({ opacity: 'hide', height: 'hide' }, 300, removed);
84
+ dom.shrinkAway(element, 300, removed);
82
85
  });
83
86
  });
84
87
  }
85
88
 
86
89
  function elementName(element) {
87
- var type = element.attr('data-ge-element');
88
- var label = element.attr('data-ge-label');
90
+ var type = element.getAttribute('data-ge-element');
91
+ var label = element.getAttribute('data-ge-label');
89
92
 
90
93
  if (label && type) { return label + ' (' + type + ')'; }
91
94
 
92
- return label || type || element[0].tagName.toLowerCase();
95
+ return label || type || element.tagName.toLowerCase();
93
96
  }
94
97
 
95
98
  /**
@@ -99,11 +102,11 @@ $.fn.gridEditor.features.elements = function(ge) {
99
102
  * prependTo - with a word to the host.
100
103
  */
101
104
  function placementBesideText(options) {
102
- var placed = $.extend({}, options);
105
+ var placed = Object.assign({}, options);
103
106
 
104
107
  [['appendTo', 'insertAfter'], ['prependTo', 'insertBefore']].forEach(function(pair) {
105
- var target = options[pair[0]] !== undefined ? $(options[pair[0]]) : null;
106
- if (!target || !target.is('.ge-content')) { return; }
108
+ var target = options[pair[0]] !== undefined ? nodeFrom(options[pair[0]]) : null;
109
+ if (!target || !target.matches('.ge-content')) { return; }
107
110
 
108
111
  if (!warnedIntoText) {
109
112
  warnedIntoText = true;
@@ -112,21 +115,44 @@ $.fn.gridEditor.features.elements = function(ge) {
112
115
  }
113
116
 
114
117
  delete placed[pair[0]];
115
- placed[pair[1]] = target.parent('.ge-text-block').length ? target.parent() : target;
118
+ placed[pair[1]] = dom.hasClass(target.parentElement, 'ge-text-block') ? target.parentElement : target;
116
119
  });
117
120
 
118
121
  return placed;
119
122
  }
120
123
 
124
+ /** A place a caller named: an element, or the first one a selector matches. */
125
+ function nodeFrom(node) {
126
+ if (typeof node === 'string') { return document.querySelector(node); }
127
+ return node && node.nodeType === 1 ? node : null;
128
+ }
129
+
130
+ /**
131
+ * What the element holds: html, which is parsed as innerHTML parses so
132
+ * no <script> in it runs, or a node, or a list of nodes.
133
+ */
134
+ function fill(element, content) {
135
+ if (content === undefined || content === null) { return; }
136
+
137
+ if (typeof content === 'string') {
138
+ dom.parse(content).forEach(function(node) { element.appendChild(node); });
139
+ } else if (content.nodeType) {
140
+ element.appendChild(content);
141
+ } else if (typeof content.length === 'number') {
142
+ Array.prototype.slice.call(content).forEach(function(node) { element.appendChild(node); });
143
+ }
144
+ }
145
+
121
146
  function apiCreateElement(content, options) {
122
147
  options = options || {};
123
148
 
124
- var element = $('<div class="ge-element" />')
125
- .attr('data-ge-element', options.type || 'element')
126
- .append(content)
127
- ;
149
+ var element = dom.element('div', {
150
+ 'class': 'ge-element',
151
+ 'data-ge-element': options.type || 'element',
152
+ });
153
+ fill(element, content);
128
154
  if (options.label !== undefined) {
129
- element.attr('data-ge-label', options.label);
155
+ element.setAttribute('data-ge-label', options.label);
130
156
  }
131
157
 
132
158
  return ge.place(element, 'element', placementBesideText(options));
@@ -139,7 +165,7 @@ $.fn.gridEditor.features.elements = function(ge) {
139
165
 
140
166
  /** A node this plugin marked is an element, whatever else it is. */
141
167
  kindOf: function(node) {
142
- return node.hasClass('ge-element') ? 'element' : null;
168
+ return dom.hasClass(node, 'ge-element') ? 'element' : null;
143
169
  },
144
170
 
145
171
  /**
@@ -156,7 +182,7 @@ $.fn.gridEditor.features.elements = function(ge) {
156
182
  // containers - and only the columns
157
183
  blocks: '.ge-element',
158
184
  accepts: function(region, node) {
159
- if (node.hasClass('ge-element')) { return region.is('.column'); }
185
+ if (dom.hasClass(node, 'ge-element')) { return dom.is(region, '.column'); }
160
186
 
161
187
  return true;
162
188
  },
@@ -165,5 +191,3 @@ $.fn.gridEditor.features.elements = function(ge) {
165
191
  onDeinit: unmarkElements,
166
192
  };
167
193
  };
168
-
169
- })(jQuery);