@themarioga/grid-editor 3.2.1 → 4.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 (43) hide show
  1. package/BUILDING.md +12 -3
  2. package/CHANGELOG.md +45 -0
  3. package/README.md +26 -6
  4. package/UPGRADING.md +79 -0
  5. package/dist/grideditor.css +40 -20
  6. package/dist/grideditor.min.css +1 -1
  7. package/dist/grideditor.min.css.map +1 -1
  8. package/dist/jquery.grideditor.bundle.min.js +10 -0
  9. package/dist/jquery.grideditor.js +369 -165
  10. package/dist/jquery.grideditor.min.js +1 -1
  11. package/dist/jquery.grideditor.min.js.map +1 -1
  12. package/dist/locales/grideditor.es.js +2 -0
  13. package/dist/locales/grideditor.es.min.js +1 -1
  14. package/dist/locales/grideditor.es.min.js.map +1 -1
  15. package/dist/plugins/grideditor.accordion.js +8 -0
  16. package/dist/plugins/grideditor.accordion.min.js +1 -1
  17. package/dist/plugins/grideditor.accordion.min.js.map +1 -1
  18. package/dist/plugins/grideditor.elements.js +5 -5
  19. package/dist/plugins/grideditor.elements.min.js +1 -1
  20. package/dist/plugins/grideditor.elements.min.js.map +1 -1
  21. package/dist/plugins/grideditor.tabs.js +8 -0
  22. package/dist/plugins/grideditor.tabs.min.js +1 -1
  23. package/dist/plugins/grideditor.tabs.min.js.map +1 -1
  24. package/docs/events.md +6 -7
  25. package/docs/locale-keys.md +2 -0
  26. package/docs/plugins.md +21 -7
  27. package/example/autosave.html +1 -1
  28. package/example/basic.html +3 -2
  29. package/example/breakpoints.html +1 -1
  30. package/example/ckeditor.html +1 -1
  31. package/example/containers.html +1 -1
  32. package/example/elements.html +1 -1
  33. package/example/locale.html +1 -1
  34. package/example/plugins.html +1 -1
  35. package/example/summernote.html +1 -1
  36. package/example/wrap_content.html +1 -1
  37. package/package.json +3 -2
  38. package/src/js/jquery.grideditor.js +369 -165
  39. package/src/js/locales/grideditor.es.js +2 -0
  40. package/src/js/plugins/grideditor.accordion.js +8 -0
  41. package/src/js/plugins/grideditor.elements.js +5 -5
  42. package/src/js/plugins/grideditor.tabs.js +8 -0
  43. package/src/less/grideditor.less +43 -18
package/BUILDING.md CHANGED
@@ -19,8 +19,17 @@ and the files in `src/js/locales/` and `src/js/plugins/` one by one under
19
19
  `dist/locales/` and `dist/plugins/`. Neither of those two directories is part
20
20
  of the main bundle: the `src/js/*.js` glob does not descend, so a page loads
21
21
  the languages and the container plugins it actually wants. See
22
- [docs/plugins.md](docs/plugins.md) for what a container plugin is. Locale files are
23
- deliberately not part of the main bundle: a page loads only the languages it
22
+ [docs/plugins.md](docs/plugins.md) for what a container plugin is.
23
+
24
+ One more file comes out of it: `dist/jquery.grideditor.bundle.min.js`, the
25
+ minified editor concatenated with the copy of SortableJS in `node_modules`,
26
+ for pages that would rather load one file than two. It carries both MIT
27
+ notices, it is built after the minified editor because it is made of it, and a
28
+ page loads it *or* the editor and SortableJS separately, never both. The
29
+ version is pinned in `package.json`, so refreshing it is an `npm update
30
+ sortablejs` and a rebuild.
31
+
32
+ Locale files are deliberately not part of the main bundle: a page loads only the languages it
24
33
  offers. English is the exception and lives in the bundle, because it is the
25
34
  fallback every string lookup ends at. See `docs/locale-keys.md` for the keys,
26
35
  and `src/js/locales/grideditor.es.js` for what a locale file looks like.
@@ -44,7 +53,7 @@ suite, pass part of its name:
44
53
 
45
54
  A suite can also be run on its own with `node test/rte.js`.
46
55
 
47
- The fixture pages in `test/fixtures` load jQuery, jQuery UI and Bootstrap from
56
+ The fixture pages in `test/fixtures` load jQuery, SortableJS and Bootstrap from
48
57
  `test/vendor` rather than from a CDN, so most of the suite runs offline. The
49
58
  rich text editor suite is the exception: it loads tinyMCE, CKEditor and
50
59
  Summernote from their CDNs to test against the real editors, and the runner
package/CHANGELOG.md CHANGED
@@ -5,6 +5,51 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
 
8
+ ## [4.0.0] - 2026-09-22
9
+ ### Added
10
+ - Editing from a touchscreen. Sorting, resizing a column and carrying a toolbar
11
+ button onto the canvas all work with a finger; a touch rests for
12
+ `drag.touch_delay` before it moves anything, so the page can still be
13
+ scrolled. `test/touch.js` holds every gesture to it, and none of them worked
14
+ in 3.x.
15
+ - `dist/jquery.grideditor.bundle.min.js`: the editor with SortableJS inside it,
16
+ for pages that would rather load one file than two. A page loads it or the
17
+ pair, never both.
18
+ - A `drag` setting: `delay`, `touch_delay`, `threshold`, `animation` and
19
+ `scroll`, named for the gesture rather than for the library underneath.
20
+ - A whole container can be dragged. Its move tool used to be a handle for a
21
+ list that did not accept containers, so dragging one did nothing.
22
+
23
+ ### Removed
24
+ - jQuery UI is no longer a dependency. A page loads jQuery, SortableJS and the
25
+ editor, which comes to 81.6 kB gzip against 132.8 kB before: 51 kB less, 39%
26
+ of the page.
27
+ - `sortable_options` and `resizable_options`. Both handed out the drag
28
+ library's own options; `drag` and `resize` replace them, and passing either
29
+ warns once naming the replacement.
30
+
31
+ ### Changed
32
+ - Resizing a column and dragging a toolbar button onto the canvas are the
33
+ editor's own pointer code, so jQuery UI is no longer used at all. A refused
34
+ `before-resize` now stops the gesture before it starts instead of refusing
35
+ every step of it, and the pointer is captured, so a fast drag that leaves the
36
+ column behind keeps resizing it. `.ui-resizable-*` become `.ge-resize-*` and
37
+ `.ge-resizing`; a palette button carries `.ge-palette-button`.
38
+ - Sorting is SortableJS instead of jQuery UI: rows, columns, blocks, tabs,
39
+ accordion items and elements all move through it, with touch support that
40
+ jQuery UI sortable never had. `.ui-sortable-helper` and
41
+ `.ui-sortable-placeholder` become `.ge-drag-helper` and
42
+ `.ge-drag-placeholder`.
43
+ - Every sortable list the editor makes, core's and a plugin's, goes through one
44
+ internal seam that names the drag toolkit in one place. Groundwork for 4.0,
45
+ which replaces jQuery UI with SortableJS.
46
+ - A plugin's `onSortable` hook receives that function instead of a jQuery UI
47
+ options object, and describes a list rather than making one. See
48
+ `UPGRADING.md`.
49
+ - Sortable groups are scoped to the editor instance, so two editors on one page
50
+ no longer drag into each other.
51
+
52
+
8
53
  ## [3.2.1] - 2026-09-22
9
54
  ### Changed
10
55
  - `example/containers.html` shows a card too: its own row, with two columns
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Grid Editor
2
2
  ===========
3
3
 
4
- Grid Editor is a visual javascript editor for the [bootstrap 5 grid system](https://getbootstrap.com/docs/5.3/layout/grid/), written as a [jQuery](http://jquery.com/) plugin. You can create, drag, resize and delete rows and columns, indent them, and give each of bootstrap's six breakpoints its own layout — or edit them all at once. It also edits tabs, accordions, popups and cards, and any markup you mark as an element, and it tells your application about every change it makes.
4
+ Grid Editor is a visual javascript editor for the [bootstrap 5 grid system](https://getbootstrap.com/docs/5.3/layout/grid/), written as a [jQuery](http://jquery.com/) plugin. You can create, drag, resize and delete rows and columns, indent them, and give each of bootstrap's six breakpoints its own layout — or edit them all at once, with a mouse or with a finger. It also edits tabs, accordions, popups and cards, and any markup you mark as an element, and it tells your application about every change it makes.
5
5
 
6
6
  This is a fork of [Friendly-Pixel/grid-editor](https://github.com/Friendly-Pixel/grid-editor)
7
7
  by Simon Epskamp, carrying it on from 2.x. It is published as
@@ -39,7 +39,7 @@ from any web server, or from GitHub Pages, with no build step.
39
39
  Installation
40
40
  ------------
41
41
 
42
- * __Dependencies:__ Grid Editor depends on jQuery, jQuery UI, Bootstrap Icons, and Bootstrap 5, so make sure you have included those in the page.
42
+ * __Dependencies:__ Grid Editor depends on jQuery, [SortableJS](https://sortablejs.github.io/Sortable/), Bootstrap Icons, and Bootstrap 5, so make sure you have included those in the page.
43
43
  * If you want to use the tinyMCE integration, include tinyMCE 6 as well. The tinyMCE jQuery plugin is no longer needed, and no longer exists as of tinyMCE 6.
44
44
  * If you want to use the summernote integration, include summernote as well.
45
45
  * If you want to use the CKEditor integration... you get the point.
@@ -52,11 +52,20 @@ npm install @themarioga/grid-editor
52
52
  * Or [download the latest version of Grid Editor](https://github.com/themarioga/grid-editor/archive/master.zip) and include it in your page:
53
53
 
54
54
  ```html
55
- <!-- Make sure jQuery, jQuery UI, bootstrap icons, and bootstrap 5 are included. TinyMCE is optional. -->
55
+ <!-- Make sure jQuery, SortableJS, bootstrap icons, and bootstrap 5 are included. TinyMCE is optional. -->
56
56
  <link rel="stylesheet" type="text/css" href="grid-editor/dist/grideditor.min.css" />
57
+ <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
57
58
  <script src="grid-editor/dist/jquery.grideditor.min.js"></script>
58
59
  ```
59
60
 
61
+ Or, for a page that would rather load one file, the editor with SortableJS
62
+ inside it &mdash; one or the other, never both:
63
+
64
+ ```html
65
+ <link rel="stylesheet" type="text/css" href="grid-editor/dist/grideditor.min.css" />
66
+ <script src="grid-editor/dist/jquery.grideditor.bundle.min.js"></script>
67
+ ```
68
+
60
69
  Usage
61
70
  -----
62
71
  ```javascript
@@ -295,7 +304,19 @@ $('#myGrid').gridEditor({
295
304
 
296
305
  __`confirm_delete`:__ Whether to ask before deleting a row, column, element or container. Default `true`. The question is asked in a Bootstrap modal the editor builds outside your canvas, in the interface language; a page that loaded Bootstrap's css but not its javascript gets the browser's own confirm instead. Set it to `false` if you cancel `before-delete` and ask in your own way.
297
306
 
298
- __`sortable_options`:__ Merged into every jQuery UI sortable, for hosts that need `cancel`, `tolerance` or a custom `connectWith`.
307
+ __`drag`:__ How a drag behaves, wherever the editor drags something. Named for the gesture rather than for the library underneath, so it survives a change of library. Every gesture works from a touchscreen, which is what `touch_delay` is for: a touch drag that started instantly would take the page's scrolling with it, so a finger has to rest for a moment before it moves anything. Setting `delay` makes both gestures wait that long.
308
+
309
+ ```javascript
310
+ $('#myGrid').gridEditor({
311
+ drag: {
312
+ delay: 0, // ms to hold before a drag starts
313
+ touch_delay: 100, // the same for touch, where 0 eats the page's scrolling
314
+ threshold: 3, // px of movement before a gesture counts as a drag
315
+ animation: 150, // ms of reordering animation, 0 for none
316
+ scroll: true, // scroll the page when a drag reaches its edge
317
+ },
318
+ });
319
+ ```
299
320
 
300
321
  ### Breakpoints and sizing
301
322
 
@@ -315,13 +336,12 @@ __`resize`:__ Resizing a column by dragging its edge. Defaults:
315
336
  $('#myGrid').gridEditor({
316
337
  resize: {
317
338
  enabled: true,
318
- handles: 'e', // as jQuery UI names them; 'w' for a right to left page
339
+ handles: 'e', // 'w' for a right to left page, 'e, w' for both
319
340
  balance: 'next', // the following column absorbs the change; false lets the row wrap
320
341
  },
321
342
  });
322
343
  ```
323
344
 
324
- __`resizable_options`:__ Merged into every jQuery UI resizable.
325
345
 
326
346
  ### Elements
327
347
 
package/UPGRADING.md CHANGED
@@ -1,3 +1,82 @@
1
+ Upgrading from grid-editor `3.*` to `4.*`
2
+ =========================================
3
+
4
+ One change, and it is worth the major: jQuery UI is gone. The editor is 51 kB
5
+ lighter on the page and works from a touchscreen, which it never did. Four
6
+ things to do:
7
+
8
+ * __A plugin's `onSortable` takes a function, not an options object.__ It used
9
+ to receive the editor's shared jQuery UI options and call `.sortable()`
10
+ itself; it now receives `sortable(lists, { draggable, group })` and describes
11
+ the list instead. See [docs/plugins.md](docs/plugins.md). Nothing else in the
12
+ plugin handle changed.
13
+
14
+ ```javascript
15
+ // 3.x
16
+ onSortable: function(shared) {
17
+ ge.canvas.find('.ge-content').sortable($.extend({
18
+ items: '> .ge-element',
19
+ connectWith: '.ge-canvas .ge-content',
20
+ }, shared, ge.settings.sortable_options));
21
+ }
22
+
23
+ // 4.x
24
+ onSortable: function(sortable) {
25
+ sortable(ge.canvas.find('.ge-content'), {
26
+ draggable: '> .ge-element',
27
+ group: 'element',
28
+ });
29
+ }
30
+ ```
31
+
32
+ * __`sortable_options` and `resizable_options` are gone.__ They existed to hand
33
+ you the drag library's own options, and 4.0 stops promising there is one: the
34
+ group names, the handle, the filter and the callbacks are the editor's, and
35
+ overwriting them breaks the canvas rather than tuning it. What they were used
36
+ for is now `drag` — `delay`, `touch_delay`, `threshold`, `animation`,
37
+ `scroll` — and the `resize` block you already have. Passing either warns once
38
+ and names the replacement.
39
+
40
+ * __jQuery UI is not a dependency.__ Drop its `<script>` and add SortableJS;
41
+ resizing a column and carrying a toolbar button onto the canvas are the
42
+ editor's own pointer code now. A page that would rather load one file can
43
+ load `dist/jquery.grideditor.bundle.min.js`, the editor with SortableJS
44
+ inside it, instead of the two.
45
+
46
+ ```html
47
+ <!-- 3.x -->
48
+ <script src="jquery-ui.min.js"></script>
49
+ <script src="dist/jquery.grideditor.min.js"></script>
50
+
51
+ <!-- 4.x -->
52
+ <script src="Sortable.min.js"></script>
53
+ <script src="dist/jquery.grideditor.min.js"></script>
54
+ ```
55
+
56
+ Classes you may have styled:
57
+
58
+ | 3.x | 4.0 |
59
+ | --- | --- |
60
+ | `.ui-sortable-helper` | `.ge-drag-helper` |
61
+ | `.ui-sortable-placeholder` | `.ge-drag-placeholder` |
62
+ | `.ui-resizable-handle` | `.ge-resize-handle` |
63
+ | `.ui-resizable-e`, `.ui-resizable-w` | `.ge-resize-e`, `.ge-resize-w` |
64
+ | `.ui-resizable-resizing` | `.ge-resizing` |
65
+ | `.ui-draggable` on a toolbar button | `.ge-palette-button` |
66
+
67
+ * __A whole container can be dragged now.__ Its move tool was a handle for a
68
+ list that did not accept containers, so in 3.x dragging one did nothing. It
69
+ moves like a row does, and fires the same `before-move`/`after-move` with the
70
+ container's kind.
71
+
72
+ * __Two editors on one page no longer drag into each other.__ Lists were
73
+ connected by selector — `.ge-canvas .row` matches every canvas on the page —
74
+ so a column could be dragged from one editor into another, carrying the first
75
+ editor's furniture and firing its events in the wrong place. Lists are now
76
+ connected per instance. If you were relying on that, you were relying on a
77
+ bug.
78
+
79
+
1
80
  Upgrading from grid-editor `2.*` to `3.*`
2
81
  =========================================
3
82
 
@@ -76,7 +76,21 @@
76
76
  background: #2FA4E7;
77
77
  }
78
78
  /* The button following the pointer must not be what the pointer is over */
79
+ .ge-drag-helper {
80
+ opacity: 0.85;
81
+ pointer-events: none;
82
+ }
83
+ .ge-drag-helper .ge-tools-drawer {
84
+ pointer-events: none;
85
+ }
86
+ /* A toolbar button that can be carried onto the canvas */
87
+ .ge-palette-button {
88
+ cursor: move;
89
+ touch-action: none;
90
+ }
79
91
  .ge-toolbar-helper {
92
+ position: absolute;
93
+ z-index: 1000;
80
94
  pointer-events: none;
81
95
  opacity: 0.85;
82
96
  }
@@ -114,21 +128,21 @@
114
128
  /* A trigger pointing at a popup that is not there any more */
115
129
  /* Elements: the level below a column, inside a content area. Dashed
116
130
  rather than solid, so a page full of them still reads as content */
117
- /* Sorting */
131
+ /* Sorting. The dragged node stays in the list and shows where it would
132
+ land - that is the placeholder - while a copy of it follows the
133
+ pointer. */
118
134
  /* A size change should read as a movement rather than a jump, but not
119
135
  while the pointer is dragging the edge: there the column follows the
120
136
  pointer and a transition only lags behind it */
121
- /* Resizing. jQuery UI's own stylesheet is not a dependency, so the handle
122
- is styled here: a grip on the column's edge, clear of the drawer, which
123
- is what keeps the resize gesture and the sort gesture apart */
137
+ /* Resizing: a grip on the column's edge, clear of the drawer, which is
138
+ what keeps the resize gesture and the sort gesture apart */
124
139
  /* The units the column would land on, shown in its drawer while dragging */
125
140
  }
126
141
  .ge-canvas.ge-editing .ge-tools-drawer {
127
142
  /* Positioned, so a tool can hang a picker off itself. Deliberately
128
- not stacked above anything the rest of the time: jQuery UI's resize
129
- handle carries an inline z-index of 90 and runs down the column's
130
- edge, and a drawer sitting over it would take the clicks meant for
131
- the handle. */
143
+ not stacked above anything the rest of the time: the resize handle
144
+ runs down the column's edge, and a drawer sitting over it would take
145
+ the clicks meant for the handle. */
132
146
  position: relative;
133
147
  -webkit-touch-callout: none;
134
148
  /* While one of its tools is offering a choice, this drawer is the one
@@ -364,42 +378,48 @@
364
378
  .ge-canvas.ge-editing .ge-element > .ge-element-drawer > a.ge-element-info {
365
379
  cursor: default;
366
380
  }
367
- .ge-canvas.ge-editing .ui-sortable-placeholder {
381
+ .ge-canvas.ge-editing .ge-drag-placeholder {
368
382
  background: rgba(255, 255, 0, 0.2);
369
- visibility: visible !important;
383
+ opacity: 1;
370
384
  min-height: 50px;
371
385
  max-height: 100px;
372
386
  }
387
+ .ge-canvas.ge-editing .ge-drag-placeholder > * {
388
+ visibility: hidden;
389
+ }
373
390
  .ge-canvas.ge-editing .column {
374
391
  transition: width 120ms ease, margin-left 120ms ease;
375
392
  }
376
- .ge-canvas.ge-editing .column.ui-resizable-resizing {
393
+ .ge-canvas.ge-editing .column.ge-resizing {
377
394
  transition: none;
378
395
  /* Follow the pointer in pixels: the layout mode's max-width is what
379
396
  the column will snap back into once the drag lands */
380
397
  max-width: none;
381
398
  }
382
- .ge-canvas.ge-editing .column > .ui-resizable-handle {
399
+ .ge-canvas.ge-editing .column > .ge-resize-handle {
383
400
  position: absolute;
384
401
  display: block;
385
402
  z-index: 10;
403
+ /* The gesture is the editor's, not the page's: without this a touch
404
+ drag on the handle scrolls instead of resizing */
405
+ touch-action: none;
386
406
  }
387
- .ge-canvas.ge-editing .column > .ui-resizable-e,
388
- .ge-canvas.ge-editing .column > .ui-resizable-w {
407
+ .ge-canvas.ge-editing .column > .ge-resize-e,
408
+ .ge-canvas.ge-editing .column > .ge-resize-w {
389
409
  top: 0;
390
410
  bottom: 0;
391
411
  width: 8px;
392
412
  cursor: ew-resize;
393
413
  background: rgba(47, 164, 231, 0.3);
394
414
  }
395
- .ge-canvas.ge-editing .column > .ui-resizable-e:hover,
396
- .ge-canvas.ge-editing .column > .ui-resizable-w:hover {
415
+ .ge-canvas.ge-editing .column > .ge-resize-e:hover,
416
+ .ge-canvas.ge-editing .column > .ge-resize-w:hover {
397
417
  background: #2FA4E7;
398
418
  }
399
- .ge-canvas.ge-editing .column > .ui-resizable-e {
419
+ .ge-canvas.ge-editing .column > .ge-resize-e {
400
420
  right: -1px;
401
421
  }
402
- .ge-canvas.ge-editing .column > .ui-resizable-w {
422
+ .ge-canvas.ge-editing .column > .ge-resize-w {
403
423
  left: -1px;
404
424
  }
405
425
  .ge-canvas.ge-editing .ge-tools-drawer > .ge-resize-size {
@@ -409,11 +429,11 @@
409
429
  font-size: 11px;
410
430
  color: #178acc;
411
431
  }
412
- .ge-canvas.ge-editing .column.ui-resizable-resizing > .ge-tools-drawer > .ge-resize-size {
432
+ .ge-canvas.ge-editing .column.ge-resizing > .ge-tools-drawer > .ge-resize-size {
413
433
  display: block;
414
434
  }
415
435
  /* The handle belongs to editing, and never to the output */
416
- .ge-canvas:not(.ge-editing) .ui-resizable-handle {
436
+ .ge-canvas:not(.ge-editing) .ge-resize-handle {
417
437
  display: none;
418
438
  }
419
439
  /* Layout modes */