@themarioga/grid-editor 6.0.0 → 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 +47 -0
  4. package/README.md +137 -85
  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 +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 -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 +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 +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
@@ -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);
@@ -8,16 +8,16 @@
8
8
  * editor for is the handle its factory is called with, described in
9
9
  * 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.elements.min.js"></script>
13
13
  * <script src="dist/plugins/grideditor.float.min.js"></script>
14
14
  *
15
15
  * Elements only. A floated row or column stops being part of the grid, and a
16
16
  * container sits beside the content areas rather than in their text.
17
17
  */
18
- (function($) {
18
+ import { GridEditor } from '../grideditor.js';
19
19
 
20
- $.extend($.fn.gridEditor.locales.en, {
20
+ Object.assign(GridEditor.locales.en, {
21
21
  'utility.float': 'Float',
22
22
  'utility.float_start': 'Start',
23
23
  'utility.float_end': 'End',
@@ -27,7 +27,7 @@ $.extend($.fn.gridEditor.locales.en, {
27
27
  /** Start and end are left and right: Bootstrap's css is left to right. */
28
28
  var CSS = { start: 'left', end: 'right', none: 'none' };
29
29
 
30
- $.fn.gridEditor.utilities.float = function(ge) {
30
+ GridEditor.utilities.float = function(ge) {
31
31
 
32
32
  function label(value) {
33
33
  if (value === 'start') { return ge.t('utility.float_start'); }
@@ -52,5 +52,3 @@ $.fn.gridEditor.utilities.float = function(ge) {
52
52
  }],
53
53
  };
54
54
  };
55
-
56
- })(jQuery);
@@ -6,7 +6,7 @@
6
6
  * and gy-{breakpoint}-* classes. What it can ask the editor for is the handle
7
7
  * 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.gutters.min.js"></script>
11
11
  *
12
12
  * The editor draws its own frame round every column, narrower than any
@@ -15,9 +15,10 @@
15
15
  * utilities.gutters.scale is what 0 to 5 come to, for a page that changed
16
16
  * Bootstrap's $spacers.
17
17
  */
18
- (function($) {
18
+ import { GridEditor } from '../grideditor.js';
19
+ import * as dom from '../dom.js';
19
20
 
20
- $.extend($.fn.gridEditor.locales.en, {
21
+ Object.assign(GridEditor.locales.en, {
21
22
  'utility.gutters': 'Gutters',
22
23
  'utility.gutters_x': 'Horizontal gutters',
23
24
  'utility.gutters_y': 'Vertical gutters',
@@ -33,16 +34,17 @@ var DEFAULT_Y = '0';
33
34
  var INFIXES = ['', 'sm', 'md', 'lg', 'xl', 'xxl'];
34
35
  var CLASS_PATTERN = /(?:^|\s)g[xy]?-(?:(?:sm|md|lg|xl|xxl)-)?[0-5](?:\s|$)/;
35
36
 
36
- $.fn.gridEditor.utilities.gutters = function(ge) {
37
+ GridEditor.utilities.gutters = function(ge) {
37
38
 
38
- var options = $.extend({ scale: SCALE }, ge.settings.utilities.gutters);
39
+ var options = Object.assign({ scale: SCALE }, ge.settings.utilities.gutters);
40
+ var listening = null; // The after-utility listener, while editing
39
41
 
40
42
  /**
41
43
  * The class of a family that decides a row's gutters at a breakpoint:
42
44
  * the widest breakpoint up to it that has one, as { tier, value }.
43
45
  */
44
46
  function source(row, prefix, tier) {
45
- var classes = (row.attr('class') || '').split(/\s+/);
47
+ var classes = (row.getAttribute('class') || '').split(/\s+/);
46
48
 
47
49
  for (var i = tier; i >= 0; i--) {
48
50
  for (var value = VALUES.length - 1; value >= 0; value--) {
@@ -86,7 +88,8 @@ $.fn.gridEditor.utilities.gutters = function(ge) {
86
88
  * taken off: left on, the bigger of the two would win, and the field the
87
89
  * user just chose would not be what the row shows.
88
90
  */
89
- function afterUtility(e, payload) {
91
+ function afterUtility(e) {
92
+ var payload = e.detail;
90
93
  if (payload.family !== 'g') { return; }
91
94
 
92
95
  ['gx', 'gy'].forEach(function(family) {
@@ -95,9 +98,8 @@ $.fn.gridEditor.utilities.gutters = function(ge) {
95
98
  }
96
99
 
97
100
  function mark(scope) {
98
- scope.find('.row').addBack('.row').each(function() {
99
- var row = $(this);
100
- row.toggleClass('ge-gutters', CLASS_PATTERN.test(row.attr('class') || ''));
101
+ dom.selfAndAll(scope, '.row').forEach(function(row) {
102
+ dom.toggleClass(row, 'ge-gutters', CLASS_PATTERN.test(row.getAttribute('class') || ''));
101
103
  });
102
104
  }
103
105
 
@@ -130,16 +132,19 @@ $.fn.gridEditor.utilities.gutters = function(ge) {
130
132
  ],
131
133
 
132
134
  onInit: function() {
133
- ge.canvas.off('grideditor:after-utility.ge-gutters').on('grideditor:after-utility.ge-gutters', afterUtility);
135
+ // init runs again whenever a node is added, without a deinit
136
+ // between, so the listener is replaced rather than stacked
137
+ if (listening) { ge.canvas.removeEventListener('grideditor:after-utility', listening); }
138
+ listening = afterUtility;
139
+ ge.canvas.addEventListener('grideditor:after-utility', listening);
134
140
  },
135
141
 
136
142
  onRefresh: mark,
137
143
 
138
144
  onDeinit: function() {
139
- ge.canvas.off('grideditor:after-utility.ge-gutters');
140
- ge.canvas.find('.ge-gutters').removeClass('ge-gutters');
145
+ if (listening) { ge.canvas.removeEventListener('grideditor:after-utility', listening); }
146
+ listening = null;
147
+ dom.all(ge.canvas, '.ge-gutters').forEach(function(row) { dom.removeClass(row, 'ge-gutters'); });
141
148
  },
142
149
  };
143
150
  };
144
-
145
- })(jQuery);