@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
@@ -7,15 +7,15 @@
7
7
  * align-self-{breakpoint}-* classes. What it can ask the editor for is the
8
8
  * handle its factory is called with, described in docs/plugins.md.
9
9
  *
10
- * <script src="dist/jquery.grideditor.min.js"></script>
10
+ * <script src="dist/grideditor.min.js"></script>
11
11
  * <script src="dist/plugins/grideditor.alignment.min.js"></script>
12
12
  *
13
13
  * Fields only, in the settings panels: alignment is set now and then, not
14
14
  * clicked through, and a drawer is short of room.
15
15
  */
16
- (function($) {
16
+ import { GridEditor } from '../grideditor.js';
17
17
 
18
- $.extend($.fn.gridEditor.locales.en, {
18
+ Object.assign(GridEditor.locales.en, {
19
19
  'utility.justify_content': 'Justify columns',
20
20
  'utility.align_items': 'Align columns',
21
21
  'utility.align_self': 'Align self',
@@ -40,7 +40,7 @@ var FLEX = {
40
40
  * wider breakpoint's class that is live in a wide window.
41
41
  */
42
42
  function family(definition) {
43
- return $.extend({
43
+ return Object.assign({
44
44
  prefix: definition.name,
45
45
  preview: function(value) {
46
46
  var styles = {};
@@ -50,7 +50,7 @@ function family(definition) {
50
50
  }, definition);
51
51
  }
52
52
 
53
- $.fn.gridEditor.utilities.alignment = function() {
53
+ GridEditor.utilities.alignment = function() {
54
54
  return {
55
55
  families: [
56
56
  family({
@@ -77,5 +77,3 @@ $.fn.gridEditor.utilities.alignment = function() {
77
77
  ],
78
78
  };
79
79
  };
80
-
81
- })(jQuery);
@@ -6,18 +6,24 @@
6
6
  * the editor for is the handle its factory is called with, described in
7
7
  * 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.card.min.js"></script>
11
11
  */
12
- (function($) {
12
+ import { GridEditor } from '../grideditor.js';
13
+ import * as dom from '../dom.js';
13
14
 
14
- $.extend($.fn.gridEditor.locales.en, {
15
+ Object.assign(GridEditor.locales.en, {
15
16
  'container.add_card': 'Card',
16
17
  'container.card_title': 'Card title',
17
18
  'container.card_footer': 'Card footer',
18
19
  });
19
20
 
20
- $.fn.gridEditor.containers.card = function(ge) {
21
+ GridEditor.containers.card = function(ge) {
22
+
23
+ /** A header's or a footer's text, editable in place, when the card has one. */
24
+ function editable(part) {
25
+ if (part) { ge.makeLabelEditable(ge.labelIn(part)); }
26
+ }
21
27
 
22
28
  return {
23
29
  labelKey: 'container.add_card',
@@ -29,34 +35,30 @@ $.fn.gridEditor.containers.card = function(ge) {
29
35
  * exactly one region and nests like any other container.
30
36
  */
31
37
  create: function(options) {
32
- var card = $('<div class="card" />');
38
+ var card = dom.element('div', { 'class': 'card' });
33
39
 
34
40
  if (options.header !== false) {
35
- $('<div class="card-header" />')
36
- .append($('<span class="ge-pane-label" />')
37
- .text(options.title || ge.t('container.card_title')))
38
- .appendTo(card)
39
- ;
41
+ var header = card.appendChild(dom.element('div', { 'class': 'card-header' }));
42
+ header.appendChild(dom.element('span', { 'class': 'ge-pane-label' },
43
+ options.title || ge.t('container.card_title')));
40
44
  }
41
45
 
42
- $('<div class="card-body" />').append(ge.defaultRegion()).appendTo(card);
46
+ card.appendChild(dom.element('div', { 'class': 'card-body' })).appendChild(ge.defaultRegion());
43
47
 
44
48
  if (options.footer) {
45
- $('<div class="card-footer text-body-secondary" />')
46
- .append($('<span class="ge-pane-label" />')
47
- .text(typeof options.footer === 'string'
48
- ? options.footer
49
- : ge.t('container.card_footer')))
50
- .appendTo(card)
51
- ;
49
+ var footer = card.appendChild(dom.element('div', { 'class': 'card-footer text-body-secondary' }));
50
+ footer.appendChild(dom.element('span', { 'class': 'ge-pane-label' },
51
+ typeof options.footer === 'string' ? options.footer : ge.t('container.card_footer')));
52
52
  }
53
53
 
54
- return $('<div />').attr('data-ge-container', 'card').append(card);
54
+ var container = dom.element('div', { 'data-ge-container': 'card' });
55
+ container.appendChild(card);
56
+ return container;
55
57
  },
56
58
 
57
59
  mark: function(container) {
58
- ge.makeLabelEditable(ge.labelIn(container.find('> .card > .card-header')));
59
- ge.makeLabelEditable(ge.labelIn(container.find('> .card > .card-footer')));
60
+ editable(dom.one(container, ':scope > .card > .card-header'));
61
+ editable(dom.one(container, ':scope > .card > .card-footer'));
60
62
  },
61
63
 
62
64
  unmark: function(container) {
@@ -64,5 +66,3 @@ $.fn.gridEditor.containers.card = function(ge) {
64
66
  },
65
67
  };
66
68
  };
67
-
68
- })(jQuery);
@@ -7,119 +7,120 @@
7
7
  * factory is called with, described in docs/plugins.md.
8
8
  *
9
9
  * <script src="ckeditor/ckeditor.js"></script>
10
- * <script src="dist/jquery.grideditor.min.js"></script>
10
+ * <script src="dist/grideditor.min.js"></script>
11
11
  * <script src="dist/plugins/grideditor.ckeditor.min.js"></script>
12
12
  *
13
13
  * Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
14
- * loaded on its own, like every plugin. The built file starts with what
15
- * every text editor shares - text blocks, the Text button, createText,
16
- * making the host's plain content a text - from
17
- * src/js/text/grideditor.text.js, installed once however many editors a
18
- * page loads.
14
+ * loaded on its own, like every plugin. It imports what every text editor
15
+ * shares - text blocks, the Text button, createText, making the host's plain
16
+ * content a text - from src/js/text/grideditor.text.js, which the build puts
17
+ * in its classic script, installed once however many editors a page loads.
19
18
  */
20
- (function($) {
21
-
22
- $.extend($.fn.gridEditor.locales.en, {
23
- 'text.ckeditor': 'CKEditor',
24
- });
25
-
26
- var INITIAL_CONTENT = '<p>Lorem initius... </p>';
27
-
28
- $.fn.gridEditor.texts.ckeditor = function(ge) {
29
-
30
- /**
31
- * The instance editing this content area. Kept in jQuery data when it
32
- * is made, and looked for among CKEditor's own as a fallback, since
33
- * an instance made by another version of this file has no data.
34
- */
35
- function instanceOf(contentArea) {
36
- var kept = contentArea.data('ge-ckeditor');
37
- if (kept) { return kept; }
38
-
39
- var found = null;
40
- $.each(window.CKEDITOR.instances, function(name, instance) {
41
- if (instance.element && instance.element.$ === contentArea[0]) { found = instance; }
42
- });
43
-
44
- return found;
45
- }
46
-
47
- return {
48
- labelKey: 'text.ckeditor',
49
- initialContent: INITIAL_CONTENT,
50
- missingKey: 'error.ckeditor_missing',
51
-
52
- available: function() { return !!window.CKEDITOR; },
53
-
54
- start: function(contentAreas) {
55
- var settings = ge.settings;
19
+ import { GridEditor } from '../grideditor.js';
20
+ import * as dom from '../dom.js';
21
+ import '../text/grideditor.text.js';
22
+
23
+ Object.assign(GridEditor.locales.en, {
24
+ 'text.ckeditor': 'CKEditor',
25
+ });
26
+
27
+ var INITIAL_CONTENT = '<p>Lorem initius... </p>';
28
+
29
+ // The instance each content area is edited with, as this file made it
30
+ var instances = new WeakMap();
31
+
32
+ GridEditor.texts.ckeditor = function(ge) {
33
+
34
+ /**
35
+ * The instance editing this content area. Kept when it is made, and
36
+ * looked for among CKEditor's own as a fallback, since an instance made
37
+ * by another copy of this file is not in this one's record.
38
+ */
39
+ function instanceOf(contentArea) {
40
+ var kept = instances.get(contentArea);
41
+ if (kept) { return kept; }
42
+
43
+ var found = null;
44
+ Object.keys(window.CKEDITOR.instances).forEach(function(name) {
45
+ var instance = window.CKEDITOR.instances[name];
46
+ if (instance.element && instance.element.$ === contentArea) { found = instance; }
47
+ });
48
+
49
+ return found;
50
+ }
51
+
52
+ return {
53
+ labelKey: 'text.ckeditor',
54
+ initialContent: INITIAL_CONTENT,
55
+ missingKey: 'error.ckeditor_missing',
56
+
57
+ available: function() { return !!window.CKEDITOR; },
58
+
59
+ start: function(contentAreas) {
60
+ var settings = ge.settings;
61
+
62
+ contentAreas.forEach(function(contentArea) {
63
+ if (dom.hasClass(contentArea, 'active')) { return; }
64
+
65
+ if (contentArea.innerHTML == INITIAL_CONTENT) {
66
+ // CKEditor kills this '&nbsp' creating a non usable box :/
67
+ contentArea.innerHTML = '&nbsp;';
68
+ }
69
+
70
+ // contenteditable="true", or CKEditor loads readonly
71
+ dom.addClass(contentArea, 'active');
72
+ contentArea.setAttribute('contenteditable', 'true');
73
+
74
+ var configuration = Object.assign(
75
+ {},
76
+ (settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
77
+ {
78
+ // Focus editor on creation
79
+ on: {
80
+ instanceReady: function( evt ) {
81
+ // Call original instanceReady function, if one was passed in the config
82
+ var callback;
83
+ try {
84
+ callback = settings.ckeditor.config.on.instanceReady;
85
+ } catch (err) {
86
+ // No callback passed
87
+ }
88
+ if (callback) {
89
+ callback.call(this, evt);
90
+ }
56
91
 
57
- contentAreas.each(function() {
58
- var contentArea = $(this);
59
- if (contentArea.hasClass('active')) { return; }
92
+ // The editor owns what is inside the
93
+ // content area now, so the grid editor is
94
+ // told to put its own furniture back
95
+ ge.textReady(contentArea);
60
96
 
61
- if (contentArea.html() == INITIAL_CONTENT) {
62
- // CKEditor kills this '&nbsp' creating a non usable box :/
63
- contentArea.html('&nbsp;');
64
- }
65
-
66
- // Add the .attr('contenteditable',''true') or CKEditor loads readonly
67
- contentArea.addClass('active').attr('contenteditable', 'true');
68
-
69
- var configuration = $.extend(
70
- {},
71
- (settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
72
- {
73
- // Focus editor on creation
74
- on: {
75
- instanceReady: function( evt ) {
76
- // Call original instanceReady function, if one was passed in the config
77
- var callback;
78
- try {
79
- callback = settings.ckeditor.config.on.instanceReady;
80
- } catch (err) {
81
- // No callback passed
82
- }
83
- if (callback) {
84
- callback.call(this, evt);
85
- }
86
-
87
- // The editor owns what is inside the
88
- // content area now, so the grid editor is
89
- // told to put its own furniture back
90
- ge.textReady(contentArea);
91
-
92
- instance.focus();
93
- }
97
+ instance.focus();
94
98
  }
95
99
  }
96
- );
97
- var instance = window.CKEDITOR.inline(contentArea.get(0), configuration);
98
- contentArea.data('ge-ckeditor', instance);
99
- });
100
- },
101
-
102
- stop: function(contentAreas) {
103
- contentAreas.filter('.active').each(function() {
104
- var contentArea = $(this);
105
-
106
- // This content area's instance, and no other: up to 5.x
107
- // closing one content area destroyed every CKEditor on
108
- // the page, other editors' and the host's own included
109
- var instance = window.CKEDITOR ? instanceOf(contentArea) : null;
110
- if (instance) { instance.destroy(); }
111
- contentArea.removeData('ge-ckeditor');
112
-
113
- // Cleanup
114
- contentArea
115
- .removeClass('active cke_focus')
116
- .removeAttr('id')
117
- .removeAttr('style')
118
- .removeAttr('spellcheck')
119
- .removeAttr('contenteditable')
120
- ;
100
+ }
101
+ );
102
+ var instance = window.CKEDITOR.inline(contentArea, configuration);
103
+ instances.set(contentArea, instance);
104
+ });
105
+ },
106
+
107
+ stop: function(contentAreas) {
108
+ contentAreas.filter(function(contentArea) {
109
+ return dom.hasClass(contentArea, 'active');
110
+ }).forEach(function(contentArea) {
111
+ // This content area's instance, and no other: up to 5.x
112
+ // closing one content area destroyed every CKEditor on
113
+ // the page, other editors' and the host's own included
114
+ var instance = window.CKEDITOR ? instanceOf(contentArea) : null;
115
+ if (instance) { instance.destroy(); }
116
+ instances.delete(contentArea);
117
+
118
+ // Cleanup
119
+ dom.removeClass(contentArea, 'active cke_focus');
120
+ ['id', 'style', 'spellcheck', 'contenteditable'].forEach(function(name) {
121
+ contentArea.removeAttribute(name);
121
122
  });
122
- },
123
- };
123
+ });
124
+ },
124
125
  };
125
- })(jQuery);
126
+ };
@@ -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);