@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
package/docs/plugins.md CHANGED
@@ -7,7 +7,7 @@ what turns the feature on. `grideditor.card.js` is the shortest of them, and
7
7
  the one to read first if you are about to write your own.
8
8
 
9
9
  ```html
10
- <script src="dist/jquery.grideditor.min.js"></script>
10
+ <script src="dist/grideditor.min.js"></script>
11
11
  <script src="dist/plugins/grideditor.tabs.min.js"></script>
12
12
  <script src="dist/plugins/grideditor.popup.min.js"></script>
13
13
  <script src="dist/plugins/grideditor.card.min.js"></script>
@@ -15,11 +15,11 @@ the one to read first if you are about to write your own.
15
15
  ```
16
16
 
17
17
  There are three kinds. A **container plugin** builds a type of container — it
18
- registers under `$.fn.gridEditor.containers`, and the toolbar offers a button
18
+ registers under `GridEditor.containers`, and the toolbar offers a button
19
19
  for it. A **utility plugin** declares families of Bootstrap's responsive
20
- utility classes — `$.fn.gridEditor.utilities` — and the editor edits them per
20
+ utility classes — `GridEditor.utilities` — and the editor edits them per
21
21
  breakpoint. A **feature plugin** is anything else the editor can do —
22
- `$.fn.gridEditor.features`, hooks into the canvas, and may contribute methods.
22
+ `GridEditor.features`, hooks into the canvas, and may contribute methods.
23
23
  All three are factories called once per editor with the same handle.
24
24
 
25
25
  Text is a feature plugin too. The core knows the grid and the host's *plain
@@ -50,14 +50,12 @@ A plugin registers a **factory** under the type it builds. The factory is
50
50
  called once per editor, with the handle below, and returns the definition:
51
51
 
52
52
  ```javascript
53
- (function($) {
54
-
55
- $.extend($.fn.gridEditor.locales.en, {
53
+ Object.assign(GridEditor.locales.en, {
56
54
  'container.add_carousel': 'Carousel',
57
55
  'container.carousel_label': 'Slide {number}',
58
56
  });
59
57
 
60
- $.fn.gridEditor.containers.carousel = function(ge) {
58
+ GridEditor.containers.carousel = function(ge) {
61
59
 
62
60
  function addSlideTo(container, options) { … }
63
61
 
@@ -77,10 +75,28 @@ $.fn.gridEditor.containers.carousel = function(ge) {
77
75
  onDeinit: function() { … }, // optional, per canvas deinit
78
76
  };
79
77
  };
78
+ ```
79
+
80
+ That is a classic script, loaded after `grideditor.js`, with `GridEditor` on
81
+ window. The same plugin as an ES module imports the editor and registers as
82
+ it is imported, which is how the shipped plugins' modules work:
83
+
84
+ ```javascript
85
+ import { GridEditor } from '@themarioga/grid-editor';
80
86
 
81
- })(jQuery);
87
+ GridEditor.containers.carousel = function(ge) { … };
82
88
  ```
83
89
 
90
+ A page or an app imports it for that side effect, after the editor:
91
+ `import './carousel.js'`. Either way there is one registry per page, and the
92
+ editors made after a plugin registered have it.
93
+
94
+ Everything the editor hands a plugin, and everything a plugin hands back, is
95
+ DOM: elements, and arrays of them where there may be several. Up to 6.x it was
96
+ jQuery objects; a plugin written for 6.x is ported by taking that out, and
97
+ [UPGRADING.md](../UPGRADING.md) says how. The shipped plugins are written in
98
+ plain DOM, and a plugin of your own is free to use whatever it likes.
99
+
84
100
  - **`iconClass`**, when given, is the toolbar button's face: the icon alone,
85
101
  with the label as its title. Without one the button shows a plus and the
86
102
  label.
@@ -102,7 +118,9 @@ The handle
102
118
 
103
119
  Everything a plugin needs from the editor comes through the handle its factory
104
120
  is called with. It is the plugin contract: these names, and what they do, do
105
- not change without a major version.
121
+ not change without a major version. 7.0 was one: every node it takes or gives
122
+ is an element, and where 6.x gave a jQuery set that may hold several, an
123
+ array.
106
124
 
107
125
  | | |
108
126
  | --- | --- |
@@ -112,10 +130,10 @@ not change without a major version.
112
130
  | `ge.warn(message)` | A console warning, prefixed like the editor's own |
113
131
  | `ge.containerId(type)` | A generated id, stable across a reset, for Bootstrap's toggles |
114
132
  | `ge.defaultRegion()` | A row with one full width column: what an empty pane starts as |
115
- | `ge.createTool(drawer, title, className, iconClass, handlers)` | A tool in a drawer |
116
- | `ge.createMoveTool(drawer)` | The drag handle, unless `drag_handle` says the whole drawer is one |
133
+ | `ge.createTool(drawer, title, className, iconClass, handlers)` | A tool in a drawer, which it returns. `handlers` is a click handler or `{ eventName: handler }`; each gets the DOM event, with `this` the tool |
134
+ | `ge.createMoveTool(drawer)` | The drag handle, unless `drag_handle` says the whole drawer is one; the tool, or null |
117
135
  | `ge.addSettingsTool(drawer, node, presets)` | The gear, and the id and class panel it opens. Returns the panel, to add fields to |
118
- | `ge.detailsOf(node)` | A node's settings panel, wherever it is: in its drawer, or open in the offcanvas, popover or modal `settings_panel` names, outside the canvas. Find a panel's fields through it, never through the drawer |
136
+ | `ge.detailsOf(node)` | A node's settings panel, wherever it is: in its drawer, or open in the offcanvas, popover or modal `settings_panel` names, outside the canvas. Find a panel's fields through it, never through the drawer. Null for a node with none |
119
137
  | `ge.deleteNode(kind, node, confirmText, animate)` | Remove a node: ask, animate, announce |
120
138
  | `ge.place(node, kind, options)` | Put a created node where `appendTo` and friends say, through the add events. `options.source` is the payload's `source`, `api` by default |
121
139
  | `ge.createPaneControls(pane, kind, hostTools, confirmText, remove)` | The drawer a pane gets: move, the host's tools, delete |
@@ -132,15 +150,15 @@ not change without a major version.
132
150
  | `ge.breakpoints` | Every breakpoint key, smallest first |
133
151
  | `ge.getUtility(node, family, view?)` | A utility's value, as in the public method |
134
152
  | `ge.setUtility(node, family, value, options?)` | Write one through the events. `options` is a view key or `{ view, source }` |
135
- | `ge.utilityField(node, family)` | A panel field for one family, for a plugin that builds its own panel |
153
+ | `ge.utilityField(node, family)` | A panel field for one family, for a plugin that builds its own panel; null for a family no plugin declares |
136
154
  | `ge.rowFromLayout(layout)` | A detached row from a layout: `[8, 4]`, `['auto', 'equal']` or `{ row_cols, columns }` |
137
- | `ge.drawerOf(node)` | A node's drawer: its first child, or for a content area the one beside it in its text block |
155
+ | `ge.drawerOf(node)` | A node's drawer: its first child, or for a content area the one beside it in its text block; null when it has none |
138
156
  | `ge.textReady(block)` | A text editor has rewritten a content area: whatever the editor and its plugins put in there goes back in |
139
157
  | `ge.attachPicker(tool, open)` | Hold a tool, or rest the pointer on it, and `open` is called: how a tool offers a choice |
140
158
  | `ge.openPicker(anchor, choices, className?)` | The choice itself, as a strip under `anchor`: one button per `{ label, title, attributes, choose }` |
141
159
  | `ge.closePicker()` | Close it; true when one was open, which is also a click's answer |
142
160
  | `ge.nodeHtml(node)` | One node's markup as `getHtml` would give it. The canvas leaves editing to read it and comes back, as it does for `getHtml` |
143
- | `ge.toolbarItems(name)` | The toolbar buttons the feature plugin `name` declared, for showing and hiding them |
161
+ | `ge.toolbarItems(name)` | An array of the toolbar buttons the feature plugin `name` declared, for showing and hiding them |
144
162
  | `ge.bareStyle(node, family, property)` | A css property's value on the node with none of the family's classes: what a preview shows when no class applies and that is not a constant |
145
163
 
146
164
  The add, delete and move events for a container and its panes are fired by the
@@ -154,7 +172,7 @@ Feature plugins
154
172
  A feature plugin returns hooks rather than a container definition:
155
173
 
156
174
  ```javascript
157
- $.fn.gridEditor.features.elements = function(ge) {
175
+ GridEditor.features.elements = function(ge) {
158
176
  return {
159
177
  methods: { createElement: … }, // added to the editor's own methods
160
178
  kindOf: function(node) { … }, // what an event calls this node
@@ -246,7 +264,7 @@ rather than remembering anything about it.
246
264
 
247
265
  ```javascript
248
266
  onSortable: function(sortable) {
249
- sortable(ge.canvas.find('.ge-content'), {
267
+ sortable(Array.from(ge.canvas.querySelectorAll('.ge-content')), {
250
268
  draggable: '> .ge-element', // which children move
251
269
  group: 'element', // lists sharing a group connect
252
270
  });
@@ -316,7 +334,7 @@ A feature plugin that edits text declares its types, and that is all the
316
334
  core asks of it:
317
335
 
318
336
  ```javascript
319
- $.fn.gridEditor.features.mytext = function(ge) {
337
+ GridEditor.features.mytext = function(ge) {
320
338
  return {
321
339
  textTypes: function() {
322
340
  return [{
@@ -361,8 +379,12 @@ off there.
361
379
  block's drawer, the *Text* buttons in the toolbar, `createText`, opening an
362
380
  editor on a click and closing it with
363
381
  the host's attributes put back, and `textTypes` - from
364
- `src/js/text/grideditor.text.js`, which the build puts at the top of each.
365
- However many a page loads, that is installed once.
382
+ `src/js/text/grideditor.text.js`, which each of them imports, so its script
383
+ carries it. However many a page loads, that is installed once.
384
+
385
+ Each registers on `GridEditor.texts`, the text feature's own registry, with a
386
+ factory whose `start(contentAreas)` and `stop(contentAreas)` get an array of
387
+ content areas.
366
388
 
367
389
  The editors offered are `content_types`, every one loaded by default, in the
368
390
  order the page loaded them; the `plugins` setting does not choose them. A
@@ -379,9 +401,9 @@ editors.
379
401
 
380
402
  Up to 5.x an editor of a host's own registered under
381
403
  `$.fn.gridEditor.RTEs`, and in 5.x and the 6.0 betas under
382
- `$.fn.gridEditor.texts`. 6.0 removes the first - what is registered there is
383
- ignored, with a warning - and `texts` is the shipped editors' own registry,
384
- not a contract.
404
+ `$.fn.gridEditor.texts`. 6.0 ignored the first, with a warning, and 7.0 has
405
+ neither: `GridEditor.texts` is the shipped editors' own registry, not a
406
+ contract.
385
407
 
386
408
 
387
409
  Utility plugins
@@ -393,7 +415,7 @@ ones spelled `{property}-{breakpoint}-{value}`, like `order-md-2` or
393
415
  and the editor reads, writes, previews and announces them:
394
416
 
395
417
  ```javascript
396
- $.fn.gridEditor.utilities.order = function(ge) {
418
+ GridEditor.utilities.order = function(ge) {
397
419
  return {
398
420
  families: [{
399
421
  name: 'order', // what events and setUtility call it
@@ -0,0 +1,112 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+
6
+ <!-- CSS dependencies -->
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.css">
9
+
10
+ <!-- Javascript dependencies: jQuery 4, which this page's own code is
11
+ written in, as a page for grid-editor 6 was -->
12
+ <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
13
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
14
+
15
+ <!-- Grid editor CSS -->
16
+ <link rel="stylesheet" type="text/css" href="../dist/grideditor.css" />
17
+ <!-- Grid editor javascript: the editor, then the jQuery API on top of
18
+ it, then the plugins - which are 7.0's, like the editor -->
19
+ <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
20
+ <script src="../dist/grideditor.min.js"></script>
21
+ <script src="../dist/grideditor.jquery.min.js"></script>
22
+ <script src="../dist/plugins/grideditor.tabs.min.js"></script>
23
+ <script src="../dist/plugins/grideditor.card.min.js"></script>
24
+
25
+ <script>
26
+ // Everything below is grid-editor 6 code, unchanged
27
+ $(function() {
28
+ $('#myGrid').gridEditor({
29
+ new_row_layouts: [[12], [6, 6], [4, 4, 4]],
30
+ content_types: [],
31
+
32
+ // A callback gets the payload with jQuery objects in it
33
+ callbacks: {
34
+ after_add_row: function(payload) {
35
+ $('#last').text('A row was added, with ' +
36
+ payload.node.children('.column').length + ' columns');
37
+ },
38
+ },
39
+ });
40
+
41
+ // And so does a jQuery event listener, as its second argument
42
+ $('#myGrid').on('grideditor:before-delete', function(e, payload) {
43
+ if (payload.node.hasClass('locked')) {
44
+ e.preventDefault();
45
+ $('#last').text('That row is locked: it stays');
46
+ }
47
+ });
48
+
49
+ $('#output').on('click', function() {
50
+ $('#html').text($('#myGrid').gridEditor('getHtml'));
51
+ });
52
+ });
53
+ </script>
54
+
55
+ <title>Grid Editor jQuery API example</title>
56
+ </head>
57
+ <body>
58
+ <!-- Back to the demo index -->
59
+ <div class="container pt-3">
60
+ <a class="link-secondary" href="index.html"><i class="bi bi-arrow-left"></i> All demos</a>
61
+ </div>
62
+
63
+
64
+ <div class="container">
65
+
66
+ <div class="row my-3">
67
+ <div class="col-lg-8">
68
+ <h1 class="h4">The jQuery API</h1>
69
+ <p class="form-text">
70
+ grid-editor needs no jQuery since 7.0. A page written for
71
+ 6.x loads jQuery 4 and <code>grideditor.jquery.js</code>
72
+ after the editor, and its code runs as it did:
73
+ <code>$('#myGrid').gridEditor(...)</code>, the methods by
74
+ name, jQuery event listeners and callbacks with jQuery
75
+ objects in their payloads. The plugins are 7.0's; a plugin
76
+ written for 6.x is the one thing to port, as
77
+ <code>UPGRADING.md</code> explains.
78
+ </p>
79
+ <p class="form-text">
80
+ Add a row and the callback counts its columns. The first
81
+ row carries a <code>locked</code> class, which the event
82
+ listener reads to turn its delete away.
83
+ </p>
84
+ <button class="btn btn-sm btn-secondary" id="output" type="button">Show the html this produces</button>
85
+ <p class="form-text" id="last"></p>
86
+ <pre id="html" class="form-text"></pre>
87
+ </div>
88
+ </div>
89
+
90
+ <div id="myGrid">
91
+
92
+ <div class="row locked">
93
+ <div class="col-lg-12">
94
+ <h2 class="h5">A locked row</h2>
95
+ <p>Its delete is canceled by the page's own jQuery listener.</p>
96
+ </div>
97
+ </div>
98
+
99
+ <div class="row">
100
+ <div class="col-lg-6">
101
+ <p>An ordinary column.</p>
102
+ </div>
103
+ <div class="col-lg-6">
104
+ <p>And another.</p>
105
+ </div>
106
+ </div>
107
+
108
+ </div> <!-- /#myGrid -->
109
+ </div> <!-- /.container -->
110
+
111
+ </body>
112
+ </html>
@@ -8,15 +8,14 @@
8
8
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.css">
9
9
 
10
10
  <!-- Javascript dependencies -->
11
- <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
12
11
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
13
- <script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/6.8.6/tinymce.min.js"></script>
12
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/7.9.3/tinymce.min.js"></script>
14
13
 
15
14
  <!-- Grid editor CSS -->
16
15
  <link rel="stylesheet" type="text/css" href="../dist/grideditor.css" />
17
16
  <!-- Grid editor javascript -->
18
17
  <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
19
- <script src="../dist/jquery.grideditor.min.js"></script>
18
+ <script src="../dist/grideditor.min.js"></script>
20
19
  <!-- The text editor is a plugin of its own, loaded after the editor -->
21
20
  <script src="../dist/plugins/grideditor.tinymce.min.js"></script>
22
21
  <script src="../dist/plugins/grideditor.card.min.js"></script>
@@ -34,9 +33,9 @@
34
33
  <!-- A plugin of this page's own: a drawer tool that opens a modal, and
35
34
  what the user chooses there saved as an attribute on the node. -->
36
35
  <script id="animation-plugin">
37
- (function($) {
36
+ (function() {
38
37
 
39
- $.extend($.fn.gridEditor.locales.en, {
38
+ Object.assign(GridEditor.locales.en, {
40
39
  'animation.tool': 'Animation',
41
40
  'animation.title': 'Animate on scroll',
42
41
  'animation.effect': 'Effect',
@@ -56,49 +55,67 @@
56
55
  var ATTRIBUTE = 'data-animation';
57
56
  var EFFECTS = ['fade', 'slide', 'zoom'];
58
57
 
59
- $.fn.gridEditor.features.animation = function(ge) {
58
+ GridEditor.features.animation = function(ge) {
60
59
 
61
60
  var modal = null;
62
61
 
63
62
  function read(node) {
64
63
  try {
65
- return JSON.parse(node.attr(ATTRIBUTE) || 'null');
64
+ return JSON.parse(node.getAttribute(ATTRIBUTE) || 'null');
66
65
  } catch (error) {
67
66
  return null;
68
67
  }
69
68
  }
70
69
 
71
70
  /**
72
- * A plain attr() on any node: an element is never inside a
73
- * text editor since 6.0, and a text's own attributes, given
71
+ * A plain setAttribute on any node: an element is never inside
72
+ * a text editor since 6.0, and a text's own attributes, given
74
73
  * while its editor is open, are kept by grid-editor when the
75
74
  * editor closes.
76
75
  */
77
76
  function write(node, value) {
78
77
  if (value) {
79
- node.attr(ATTRIBUTE, JSON.stringify(value));
78
+ node.setAttribute(ATTRIBUTE, JSON.stringify(value));
80
79
  } else {
81
- node.removeAttr(ATTRIBUTE);
80
+ node.removeAttribute(ATTRIBUTE);
82
81
  }
83
82
  }
84
83
 
84
+ function make(tag, className, text) {
85
+ var node = document.createElement(tag);
86
+ if (className) { node.className = className; }
87
+ if (text !== undefined) { node.textContent = text; }
88
+ return node;
89
+ }
90
+
85
91
  /** Built once, outside the canvas, so it is never part of getHtml. */
86
92
  function dialog() {
87
93
  if (modal) { return modal; }
88
94
 
89
- var effects = $('<select class="form-select" name="effect" />')
90
- .append($('<option value="" />').text(ge.t('animation.none')));
95
+ var effects = make('select', 'form-select');
96
+ effects.name = 'effect';
97
+ var none = make('option', null, ge.t('animation.none'));
98
+ none.value = '';
99
+ effects.appendChild(none);
91
100
  EFFECTS.forEach(function(effect) {
92
- effects.append($('<option />').val(effect).text(ge.t('animation.' + effect)));
101
+ var option = make('option', null, ge.t('animation.' + effect));
102
+ option.value = effect;
103
+ effects.appendChild(option);
93
104
  });
94
105
 
95
106
  var field = function(label, input) {
96
- return $('<div class="mb-3" />')
97
- .append($('<label class="form-label" />').text(ge.t(label)))
98
- .append(input);
107
+ var wrapper = make('div', 'mb-3');
108
+ wrapper.appendChild(make('label', 'form-label', ge.t(label)));
109
+ if (typeof input === 'string') {
110
+ wrapper.insertAdjacentHTML('beforeend', input);
111
+ } else {
112
+ wrapper.appendChild(input);
113
+ }
114
+ return wrapper;
99
115
  };
100
116
 
101
- modal = $(
117
+ var holder = document.createElement('div');
118
+ holder.innerHTML =
102
119
  '<div class="modal fade my-animation-modal" tabindex="-1" aria-hidden="true">' +
103
120
  '<div class="modal-dialog modal-dialog-centered"><form class="modal-content">' +
104
121
  '<div class="modal-header">' +
@@ -111,46 +128,52 @@
111
128
  '<button type="submit" class="btn btn-primary"></button>' +
112
129
  '</div>' +
113
130
  '</form></div>' +
114
- '</div>'
115
- ).appendTo('body');
116
-
117
- modal.find('.modal-title').text(ge.t('animation.title'));
118
- modal.find('.modal-footer .btn-secondary').text(ge.t('animation.cancel'));
119
- modal.find('.modal-footer .btn-primary').text(ge.t('animation.save'));
120
- modal.find('.modal-body')
121
- .append(field('animation.effect', effects))
122
- .append(field('animation.duration', '<input class="form-control" type="number" name="duration" min="0" step="100">'))
123
- .append(field('animation.delay', '<input class="form-control" type="number" name="delay" min="0" step="100">'))
124
- .append($('<div class="form-check" />')
125
- .append('<input class="form-check-input" type="checkbox" name="once" id="my-animation-once">')
126
- .append($('<label class="form-check-label" for="my-animation-once" />').text(ge.t('animation.once'))));
131
+ '</div>';
132
+ modal = document.body.appendChild(holder.firstChild);
133
+
134
+ modal.querySelector('.modal-title').textContent = ge.t('animation.title');
135
+ modal.querySelector('.modal-footer .btn-secondary').textContent = ge.t('animation.cancel');
136
+ modal.querySelector('.modal-footer .btn-primary').textContent = ge.t('animation.save');
137
+
138
+ var once = make('div', 'form-check');
139
+ once.innerHTML = '<input class="form-check-input" type="checkbox" name="once" id="my-animation-once">';
140
+ var onceLabel = make('label', 'form-check-label', ge.t('animation.once'));
141
+ onceLabel.setAttribute('for', 'my-animation-once');
142
+ once.appendChild(onceLabel);
143
+
144
+ var body = modal.querySelector('.modal-body');
145
+ body.appendChild(field('animation.effect', effects));
146
+ body.appendChild(field('animation.duration', '<input class="form-control" type="number" name="duration" min="0" step="100">'));
147
+ body.appendChild(field('animation.delay', '<input class="form-control" type="number" name="delay" min="0" step="100">'));
148
+ body.appendChild(once);
127
149
 
128
150
  return modal;
129
151
  }
130
152
 
131
153
  function open(node, kind, tool) {
132
- var form = dialog().find('form');
154
+ var form = dialog().querySelector('form');
133
155
  var current = read(node) || {};
134
156
 
135
- form.find('[name=effect]').val(current.effect || '');
136
- form.find('[name=duration]').val(current.duration || 600);
137
- form.find('[name=delay]').val(current.delay || 0);
138
- form.find('[name=once]').prop('checked', current.once !== false);
157
+ form.elements.effect.value = current.effect || '';
158
+ form.elements.duration.value = current.duration || 600;
159
+ form.elements.delay.value = current.delay || 0;
160
+ form.elements.once.checked = current.once !== false;
139
161
 
140
- form.off('submit').on('submit', function(e) {
162
+ // One handler at a time: this node's, until the next open
163
+ form.onsubmit = function(e) {
141
164
  e.preventDefault();
142
165
 
143
- var effect = form.find('[name=effect]').val();
166
+ var effect = form.elements.effect.value;
144
167
  var value = effect ? {
145
168
  effect: effect,
146
- duration: parseInt(form.find('[name=duration]').val(), 10) || 0,
147
- delay: parseInt(form.find('[name=delay]').val(), 10) || 0,
148
- once: form.find('[name=once]').prop('checked'),
169
+ duration: parseInt(form.elements.duration.value, 10) || 0,
170
+ delay: parseInt(form.elements.delay.value, 10) || 0,
171
+ once: form.elements.once.checked,
149
172
  } : null;
150
173
 
151
174
  var from = read(node);
152
175
  write(node, value);
153
- tool.toggleClass('my-animation-set', !!value);
176
+ tool.classList.toggle('my-animation-set', !!value);
154
177
 
155
178
  // Announced like the editor's own changes, for a host
156
179
  // that listens: grideditor:animation-change
@@ -158,10 +181,10 @@
158
181
  source: 'tool', from: from, to: value,
159
182
  }));
160
183
 
161
- window.bootstrap.Modal.getInstance(modal[0]).hide();
162
- });
184
+ window.bootstrap.Modal.getInstance(modal).hide();
185
+ };
163
186
 
164
- window.bootstrap.Modal.getOrCreateInstance(modal[0]).show();
187
+ window.bootstrap.Modal.getOrCreateInstance(modal).show();
165
188
  }
166
189
 
167
190
  return {
@@ -169,46 +192,50 @@
169
192
  // a row, a column, an element, a container's type, a pane
170
193
  drawerTools: function(drawer, node, kind) {
171
194
  var animated = ['row', 'column', 'section', 'text', 'element'].indexOf(kind) !== -1 ||
172
- !!$.fn.gridEditor.containers[kind];
195
+ !!GridEditor.containers[kind];
173
196
  if (!animated) { return; }
174
197
 
175
- ge.createTool(drawer, ge.t('animation.tool'), 'my-animation-tool', 'bi bi-magic', function() {
198
+ var tool = ge.createTool(drawer, ge.t('animation.tool'), 'my-animation-tool', 'bi bi-magic', function() {
176
199
  open(node, kind, tool);
177
200
  });
178
201
 
179
202
  // Drawers are built again on every init, so the tool
180
203
  // reads the node rather than remembering anything
181
- var tool = drawer.children('.my-animation-tool').last()
182
- .toggleClass('my-animation-set', !!read(node));
204
+ tool.classList.toggle('my-animation-set', !!read(node));
183
205
  },
184
206
  };
185
207
  };
186
208
 
187
- })(jQuery);
209
+ })();
188
210
  </script>
189
211
 
190
212
  <script>
191
- $(function() {
192
- $('#animation-source').text($('#animation-plugin').text().trim().replace(/^ {8}/gm, ''));
213
+ document.addEventListener('DOMContentLoaded', function() {
214
+ document.getElementById('animation-source').textContent =
215
+ document.getElementById('animation-plugin').textContent.trim().replace(/^ {8}/gm, '');
193
216
 
194
- $('#myGrid').gridEditor({
217
+ var editor = new GridEditor('#myGrid', {
195
218
  new_row_layouts: [[12], [6, 6], [4, 4, 4]],
196
219
  content_types: ['tinymce'],
220
+ // tinyMCE 7 is GPL-2.0-or-later: 'gpl' accepts that licence.
221
+ // A commercial licence passes its own key here instead.
222
+ tinymce: { config: { license_key: 'gpl' } },
197
223
  });
198
224
 
199
- $('#myGrid').on('grideditor:animation-change', function(e, payload) {
200
- $('#log').text('The ' + payload.kind + ' now animates: ' +
201
- (payload.to ? payload.to.effect : 'no'));
225
+ document.getElementById('myGrid').addEventListener('grideditor:animation-change', function(e) {
226
+ var payload = e.detail;
227
+ document.getElementById('log').textContent = 'The ' + payload.kind + ' now animates: ' +
228
+ (payload.to ? payload.to.effect : 'no');
202
229
  });
203
230
 
204
- $('#output').on('click', function() {
205
- $('#html').text($('#myGrid').gridEditor('getPlainHtml'));
231
+ document.getElementById('output').addEventListener('click', function() {
232
+ document.getElementById('html').textContent = editor.getPlainHtml();
206
233
  });
207
234
 
208
235
  // The published page: the plain html, and a few lines of the
209
236
  // host's own that read data-animation. Nothing of grid-editor.
210
- $('#published').on('click', function() {
211
- var html = $('#myGrid').gridEditor('getPlainHtml');
237
+ document.getElementById('published').addEventListener('click', function() {
238
+ var html = editor.getPlainHtml();
212
239
  var page = window.open('', '_blank');
213
240
 
214
241
  page.document.write(
@@ -227,7 +254,7 @@
227
254
  'Scroll down: each node animates as it comes into view' +
228
255
  '</div>' +
229
256
  '<div class="container">' + html + '</div>' +
230
- '<script>' + $('#runtime').text() + '<\/script>' +
257
+ '<script>' + document.getElementById('runtime').textContent + '<\/script>' +
231
258
  '</body></html>'
232
259
  );
233
260
  page.document.close();
@@ -280,7 +307,7 @@
280
307
  text, from its drawer, while you are typing: the attribute
281
308
  is kept when the editor closes, although tinyMCE puts back
282
309
  the attributes it found when it opened. The plugin does
283
- nothing special for that - a plain <code>attr()</code> -
310
+ nothing special for that - a plain <code>setAttribute()</code> -
284
311
  and nothing special for the quote either, which is an
285
312
  element: a block beside the texts, never inside one.
286
313
  </p>
@@ -8,7 +8,6 @@
8
8
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.css">
9
9
 
10
10
  <!-- Javascript dependencies -->
11
- <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
12
11
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
13
12
 
14
13
  <!-- Grid editor CSS -->
@@ -17,12 +16,12 @@
17
16
  <!-- The editor, and the sections plugin: equal and auto sizes and
18
17
  columns per row are the editor's own, sections are a plugin -->
19
18
  <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
20
- <script src="../dist/jquery.grideditor.min.js"></script>
19
+ <script src="../dist/grideditor.min.js"></script>
21
20
  <script src="../dist/plugins/grideditor.sections.min.js"></script>
22
21
 
23
22
  <script>
24
- $(function() {
25
- $('#myGrid').gridEditor({
23
+ document.addEventListener('DOMContentLoaded', function() {
24
+ var editor = new GridEditor('#myGrid', {
26
25
  content_types: [],
27
26
 
28
27
  // Sizes are numbers, 'equal' (col) or 'auto' (col-auto), and a
@@ -36,17 +35,18 @@
36
35
  });
37
36
 
38
37
  // A width chosen anywhere - tools, edge, panel - is a resize
39
- $('#myGrid').on('grideditor:after-resize', function(e, payload) {
40
- $('#last').text('width at ' + payload.breakpoint + ': ' +
38
+ document.getElementById('myGrid').addEventListener('grideditor:after-resize', function(e) {
39
+ var payload = e.detail;
40
+ document.getElementById('last').textContent = 'width at ' + payload.breakpoint + ': ' +
41
41
  (payload.from === null ? 'from the row' : payload.from) + ' → ' +
42
42
  (payload.to === null ? 'inherit' : payload.to) +
43
43
  (payload.cleared && payload.cleared.length ? ' (took off ' + payload.cleared.map(function(entry) {
44
44
  return entry.breakpoint;
45
- }).join(', ') + ')' : ''));
45
+ }).join(', ') + ')' : '');
46
46
  });
47
47
 
48
- $('#output').on('click', function() {
49
- $('#html').text($('#myGrid').gridEditor('getHtml'));
48
+ document.getElementById('output').addEventListener('click', function() {
49
+ document.getElementById('html').textContent = editor.getHtml();
50
50
  });
51
51
  });
52
52
  </script>