@themarioga/grid-editor 3.2.1 → 4.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 (65) hide show
  1. package/BUILDING.md +12 -3
  2. package/CHANGELOG.md +87 -0
  3. package/README.md +79 -7
  4. package/UPGRADING.md +79 -0
  5. package/dist/grideditor.css +188 -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 +924 -174
  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 +34 -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.alignment.js +81 -0
  19. package/dist/plugins/grideditor.alignment.min.js +2 -0
  20. package/dist/plugins/grideditor.alignment.min.js.map +1 -0
  21. package/dist/plugins/grideditor.elements.js +5 -5
  22. package/dist/plugins/grideditor.elements.min.js +1 -1
  23. package/dist/plugins/grideditor.elements.min.js.map +1 -1
  24. package/dist/plugins/grideditor.gutters.js +145 -0
  25. package/dist/plugins/grideditor.gutters.min.js +2 -0
  26. package/dist/plugins/grideditor.gutters.min.js.map +1 -0
  27. package/dist/plugins/grideditor.order.js +206 -0
  28. package/dist/plugins/grideditor.order.min.js +2 -0
  29. package/dist/plugins/grideditor.order.min.js.map +1 -0
  30. package/dist/plugins/grideditor.spacing.js +299 -0
  31. package/dist/plugins/grideditor.spacing.min.js +2 -0
  32. package/dist/plugins/grideditor.spacing.min.js.map +1 -0
  33. package/dist/plugins/grideditor.tabs.js +8 -0
  34. package/dist/plugins/grideditor.tabs.min.js +1 -1
  35. package/dist/plugins/grideditor.tabs.min.js.map +1 -1
  36. package/dist/plugins/grideditor.visibility.js +172 -0
  37. package/dist/plugins/grideditor.visibility.min.js +2 -0
  38. package/dist/plugins/grideditor.visibility.min.js.map +1 -0
  39. package/docs/events.md +26 -8
  40. package/docs/locale-keys.md +54 -0
  41. package/docs/plugins.md +129 -10
  42. package/example/autosave.html +6 -1
  43. package/example/basic.html +8 -2
  44. package/example/breakpoints.html +6 -1
  45. package/example/ckeditor.html +6 -1
  46. package/example/containers.html +5 -1
  47. package/example/elements.html +6 -1
  48. package/example/index.html +24 -1
  49. package/example/locale.html +6 -1
  50. package/example/plugins.html +6 -1
  51. package/example/summernote.html +6 -1
  52. package/example/utilities.html +145 -0
  53. package/example/wrap_content.html +6 -1
  54. package/package.json +3 -2
  55. package/src/js/jquery.grideditor.js +924 -174
  56. package/src/js/locales/grideditor.es.js +34 -0
  57. package/src/js/plugins/grideditor.accordion.js +8 -0
  58. package/src/js/plugins/grideditor.alignment.js +81 -0
  59. package/src/js/plugins/grideditor.elements.js +5 -5
  60. package/src/js/plugins/grideditor.gutters.js +145 -0
  61. package/src/js/plugins/grideditor.order.js +206 -0
  62. package/src/js/plugins/grideditor.spacing.js +299 -0
  63. package/src/js/plugins/grideditor.tabs.js +8 -0
  64. package/src/js/plugins/grideditor.visibility.js +172 -0
  65. package/src/less/grideditor.less +210 -18
@@ -69,6 +69,40 @@
69
69
  'view.lg': 'Escritorio',
70
70
  'view.xl': 'Escritorio grande',
71
71
  'view.xxl': 'Pantalla panorámica',
72
+ 'utility.section': 'Responsive: {view}',
73
+ 'utility.default': 'Por defecto',
74
+ 'utility.inherit': 'Hereda: {value} (de {breakpoint})',
75
+ 'utility.varies': 'Cambia en {breakpoints}; elegir aquí lo sustituye',
76
+ 'utility.visibility': 'Visibilidad',
77
+ 'utility.visibility_hidden': 'Oculto',
78
+ 'utility.visibility_shown': 'Visible',
79
+ 'tool.hide_in_view': 'Ocultar en esta vista',
80
+ 'tool.show_in_view': 'Mostrar en esta vista',
81
+ 'badge.hidden_in': 'Oculto en {breakpoints}',
82
+ 'utility.order': 'Orden',
83
+ 'utility.order_first': 'Primero',
84
+ 'utility.order_last': 'Último',
85
+ 'tool.order_earlier': 'Antes en esta vista',
86
+ 'tool.order_later': 'Después en esta vista',
87
+ 'badge.order': 'Orden: {value}',
88
+ 'utility.justify_content': 'Justificar columnas',
89
+ 'utility.align_items': 'Alinear columnas',
90
+ 'utility.align_self': 'Alinearse',
91
+ 'utility.gutters': 'Espaciado entre columnas',
92
+ 'utility.gutters_x': 'Espaciado horizontal',
93
+ 'utility.gutters_y': 'Espaciado vertical',
94
+ 'utility.padding': 'Relleno',
95
+ 'utility.margin': 'Margen',
96
+ 'utility.side_all': 'Todos los lados',
97
+ 'utility.side_x': 'Izquierda y derecha',
98
+ 'utility.side_y': 'Arriba y abajo',
99
+ 'utility.side_t': 'Arriba',
100
+ 'utility.side_b': 'Abajo',
101
+ 'utility.side_s': 'Inicio',
102
+ 'utility.side_e': 'Fin',
103
+ 'utility.spacing_gutter': 'El relleno lateral de una columna es su espaciado: cambiarlo cambia el espacio entre columnas',
104
+ 'error.sortable_missing': '¡SortableJS no está disponible! Asegúrate de haber cargado el archivo js de Sortable; sin él no se puede arrastrar.',
105
+ 'warning.setting_removed': 'El ajuste {setting} se eliminó en la 4.0. Usa {replacement} en su lugar.',
72
106
  'error.tinymce_missing': '¡tinyMCE no está disponible! Asegúrate de haber cargado el archivo js de tinyMCE.',
73
107
  'error.ckeditor_missing': '¡CKEditor no está disponible! Asegúrate de haber cargado los archivos js de ckeditor y del adaptador de jQuery.',
74
108
  'error.summernote_missing': '¡Summernote no está disponible! Asegúrate de haber cargado el archivo js de Summernote.',
@@ -99,6 +99,14 @@ $.fn.gridEditor.containers.accordion = function(ge) {
99
99
 
100
100
  return {
101
101
  labelKey: 'container.add_accordion',
102
+
103
+ // Items sort within their accordion and into any other one
104
+ onSortable: function(sortable) {
105
+ sortable(ge.canvas.find('.ge-container-accordion > .accordion'), {
106
+ draggable: '.ge-accordion-item',
107
+ group: 'accordion',
108
+ });
109
+ },
102
110
  addPaneKey: 'container.add_accordion_item',
103
111
  paneKind: 'accordion-item',
104
112
 
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Alignment for grid-editor.
3
+ *
4
+ * A utility plugin: load this file after the editor and a row's columns can be
5
+ * justified and aligned per breakpoint, and a column can align itself, with
6
+ * Bootstrap's justify-content-{breakpoint}-*, align-items-{breakpoint}-* and
7
+ * align-self-{breakpoint}-* classes. What it can ask the editor for is the
8
+ * handle its factory is called with, described in docs/plugins.md.
9
+ *
10
+ * <script src="dist/jquery.grideditor.min.js"></script>
11
+ * <script src="dist/plugins/grideditor.alignment.min.js"></script>
12
+ *
13
+ * Fields only, in the settings panels: alignment is set now and then, not
14
+ * clicked through, and a drawer is short of room.
15
+ */
16
+ (function($) {
17
+
18
+ $.extend($.fn.gridEditor.locales.en, {
19
+ 'utility.justify_content': 'Justify columns',
20
+ 'utility.align_items': 'Align columns',
21
+ 'utility.align_self': 'Align self',
22
+ });
23
+
24
+ /** What Bootstrap's value names come to in css. */
25
+ var FLEX = {
26
+ start: 'flex-start',
27
+ end: 'flex-end',
28
+ center: 'center',
29
+ between: 'space-between',
30
+ around: 'space-around',
31
+ evenly: 'space-evenly',
32
+ baseline: 'baseline',
33
+ stretch: 'stretch',
34
+ auto: 'auto',
35
+ };
36
+
37
+ /**
38
+ * A family whose preview is its one css property. `none` is what the
39
+ * property is when no class says anything, which a view has to show over a
40
+ * wider breakpoint's class that is live in a wide window.
41
+ */
42
+ function family(definition) {
43
+ return $.extend({
44
+ prefix: definition.name,
45
+ preview: function(value) {
46
+ var styles = {};
47
+ styles[definition.name] = value === null ? definition.none : FLEX[value];
48
+ return styles;
49
+ },
50
+ }, definition);
51
+ }
52
+
53
+ $.fn.gridEditor.utilities.alignment = function() {
54
+ return {
55
+ families: [
56
+ family({
57
+ name: 'justify-content',
58
+ labelKey: 'utility.justify_content',
59
+ values: ['start', 'center', 'end', 'between', 'around', 'evenly'],
60
+ appliesTo: ['row'],
61
+ none: 'normal',
62
+ }),
63
+ family({
64
+ name: 'align-items',
65
+ labelKey: 'utility.align_items',
66
+ values: ['start', 'center', 'end', 'baseline', 'stretch'],
67
+ appliesTo: ['row'],
68
+ none: 'normal',
69
+ }),
70
+ family({
71
+ name: 'align-self',
72
+ labelKey: 'utility.align_self',
73
+ values: ['auto', 'start', 'center', 'end', 'baseline', 'stretch'],
74
+ appliesTo: ['column'],
75
+ none: 'auto',
76
+ }),
77
+ ],
78
+ };
79
+ };
80
+
81
+ })(jQuery);
@@ -127,13 +127,13 @@ $.fn.gridEditor.features.elements = function(ge) {
127
127
  onContentReady: markElements,
128
128
 
129
129
  /** Elements move within a content area and between them. */
130
- onSortable: function(shared) {
130
+ onSortable: function(sortable) {
131
131
  if (!elementsEnabled()) { return; }
132
132
 
133
- ge.canvas.find('.ge-content').sortable($.extend({
134
- items: '> .ge-element',
135
- connectWith: '.ge-canvas .ge-content',
136
- }, shared, ge.settings.sortable_options));
133
+ sortable(ge.canvas.find('.ge-content'), {
134
+ draggable: '.ge-element',
135
+ group: 'element',
136
+ });
137
137
  },
138
138
  };
139
139
  };
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Gutters for grid-editor.
3
+ *
4
+ * A utility plugin: load this file after the editor and a row's gutters can
5
+ * differ per breakpoint, with Bootstrap's g-{breakpoint}-*, gx-{breakpoint}-*
6
+ * and gy-{breakpoint}-* classes. What it can ask the editor for is the handle
7
+ * its factory is called with, described in docs/plugins.md.
8
+ *
9
+ * <script src="dist/jquery.grideditor.min.js"></script>
10
+ * <script src="dist/plugins/grideditor.gutters.min.js"></script>
11
+ *
12
+ * The editor draws its own frame round every column, narrower than any
13
+ * gutter, so a row with gutter classes is drawn with its real gutters instead.
14
+ *
15
+ * utilities.gutters.scale is what 0 to 5 come to, for a page that changed
16
+ * Bootstrap's $spacers.
17
+ */
18
+ (function($) {
19
+
20
+ $.extend($.fn.gridEditor.locales.en, {
21
+ 'utility.gutters': 'Gutters',
22
+ 'utility.gutters_x': 'Horizontal gutters',
23
+ 'utility.gutters_y': 'Vertical gutters',
24
+ });
25
+
26
+ var VALUES = ['0', '1', '2', '3', '4', '5'];
27
+
28
+ /** Bootstrap's own: $spacers, and what a row's gutters are with no class. */
29
+ var SCALE = ['0', '.25rem', '.5rem', '1rem', '1.5rem', '3rem'];
30
+ var DEFAULT_X = '1.5rem';
31
+ var DEFAULT_Y = '0';
32
+
33
+ var INFIXES = ['', 'sm', 'md', 'lg', 'xl', 'xxl'];
34
+ var CLASS_PATTERN = /(?:^|\s)g[xy]?-(?:(?:sm|md|lg|xl|xxl)-)?[0-5](?:\s|$)/;
35
+
36
+ $.fn.gridEditor.utilities.gutters = function(ge) {
37
+
38
+ var options = $.extend({ scale: SCALE }, ge.settings.utilities.gutters);
39
+
40
+ /**
41
+ * The class of a family that decides a row's gutters at a breakpoint:
42
+ * the widest breakpoint up to it that has one, as { tier, value }.
43
+ */
44
+ function source(row, prefix, tier) {
45
+ var classes = (row.attr('class') || '').split(/\s+/);
46
+
47
+ for (var i = tier; i >= 0; i--) {
48
+ for (var value = VALUES.length - 1; value >= 0; value--) {
49
+ var name = prefix + (INFIXES[i] ? '-' + INFIXES[i] : '') + '-' + value;
50
+ if (classes.indexOf(name) !== -1) { return { tier: i, value: value }; }
51
+ }
52
+ }
53
+
54
+ return null;
55
+ }
56
+
57
+ /**
58
+ * One axis the way Bootstrap's css settles it. g and gx (or gy) set the
59
+ * same variable, every breakpoint's rules come after the smaller ones',
60
+ * and within a breakpoint the bigger values come later. So the class
61
+ * that wins is the one from the wider breakpoint, then the bigger one -
62
+ * not the more specific family, whatever that would suggest.
63
+ */
64
+ function axis(row, prefix, fallback) {
65
+ var tier = ge.breakpoints.indexOf(ge.view());
66
+ var winner = [source(row, 'g', tier), source(row, prefix, tier)]
67
+ .filter(Boolean)
68
+ .sort(function(a, b) { return b.tier - a.tier || b.value - a.value; })[0];
69
+
70
+ return winner ? options.scale[winner.value] : fallback;
71
+ }
72
+
73
+ function preview(axes) {
74
+ return function(value, row) {
75
+ var styles = {};
76
+
77
+ if (axes.indexOf('x') !== -1) { styles['--bs-gutter-x'] = axis(row, 'gx', DEFAULT_X); }
78
+ if (axes.indexOf('y') !== -1) { styles['--bs-gutter-y'] = axis(row, 'gy', DEFAULT_Y); }
79
+
80
+ return styles;
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Choosing g sets both axes, so a gx or gy the same breakpoint had is
86
+ * taken off: left on, the bigger of the two would win, and the field the
87
+ * user just chose would not be what the row shows.
88
+ */
89
+ function afterUtility(e, payload) {
90
+ if (payload.family !== 'g') { return; }
91
+
92
+ ['gx', 'gy'].forEach(function(family) {
93
+ ge.setUtility(payload.node, family, null, { view: payload.breakpoint, source: payload.source });
94
+ });
95
+ }
96
+
97
+ 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
+ });
102
+ }
103
+
104
+ return {
105
+ families: [
106
+ {
107
+ name: 'g',
108
+ prefix: 'g',
109
+ values: VALUES,
110
+ appliesTo: ['row'],
111
+ labelKey: 'utility.gutters',
112
+ preview: preview(['x', 'y']),
113
+ },
114
+ {
115
+ name: 'gx',
116
+ prefix: 'gx',
117
+ values: VALUES,
118
+ appliesTo: ['row'],
119
+ labelKey: 'utility.gutters_x',
120
+ preview: preview(['x']),
121
+ },
122
+ {
123
+ name: 'gy',
124
+ prefix: 'gy',
125
+ values: VALUES,
126
+ appliesTo: ['row'],
127
+ labelKey: 'utility.gutters_y',
128
+ preview: preview(['y']),
129
+ },
130
+ ],
131
+
132
+ onInit: function() {
133
+ ge.canvas.off('grideditor:after-utility.ge-gutters').on('grideditor:after-utility.ge-gutters', afterUtility);
134
+ },
135
+
136
+ onRefresh: mark,
137
+
138
+ onDeinit: function() {
139
+ ge.canvas.off('grideditor:after-utility.ge-gutters');
140
+ ge.canvas.find('.ge-gutters').removeClass('ge-gutters');
141
+ },
142
+ };
143
+ };
144
+
145
+ })(jQuery);
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Column order for grid-editor.
3
+ *
4
+ * A utility plugin: load this file after the editor and a column's place in
5
+ * its row can differ per breakpoint, with Bootstrap's order-{breakpoint}-*
6
+ * classes. What it can ask the editor for is the handle its factory is called
7
+ * with, described in docs/plugins.md.
8
+ *
9
+ * <script src="dist/jquery.grideditor.min.js"></script>
10
+ * <script src="dist/plugins/grideditor.order.min.js"></script>
11
+ *
12
+ * Two arrows in each column's drawer move it one place earlier or later in
13
+ * the view being edited, by numbering the row's columns; the markup does not
14
+ * move. Dragging still moves the markup, as it always has.
15
+ *
16
+ * utilities.order.drawer: false leaves the arrows out, and the panel field is
17
+ * the only control.
18
+ */
19
+ (function($) {
20
+
21
+ $.extend($.fn.gridEditor.locales.en, {
22
+ 'utility.order': 'Order',
23
+ 'utility.order_first': 'First',
24
+ 'utility.order_last': 'Last',
25
+ 'tool.order_earlier': 'Earlier in this view',
26
+ 'tool.order_later': 'Later in this view',
27
+ 'badge.order': 'Order: {value}',
28
+ });
29
+
30
+ var VALUES = ['first', '0', '1', '2', '3', '4', '5', 'last'];
31
+
32
+ /** Where each value puts a column, as Bootstrap's css has it. */
33
+ var RANK = { first: -1, last: 6 };
34
+
35
+ /** A column that carries any class of the family, at any breakpoint. */
36
+ var CLASS_PATTERN = /(?:^|\s)order-(?:(?:sm|md|lg|xl|xxl)-)?(?:first|last|[0-5])(?:\s|$)/;
37
+
38
+ $.fn.gridEditor.utilities.order = function(ge) {
39
+
40
+ var options = $.extend({ drawer: true }, ge.settings.utilities.order);
41
+ var warnedAboutDrag = false;
42
+
43
+ function rank(value) {
44
+ if (value === null) { return 0; }
45
+
46
+ return RANK[value] !== undefined ? RANK[value] : parseInt(value, 10);
47
+ }
48
+
49
+ function label(value) {
50
+ if (value === 'first') { return ge.t('utility.order_first'); }
51
+ if (value === 'last') { return ge.t('utility.order_last'); }
52
+
53
+ return value;
54
+ }
55
+
56
+ /** The columns of a row in the order a view shows them, given what each one's order is. */
57
+ function visualOrder(columns, read) {
58
+ return columns.get()
59
+ .map(function(element, index) {
60
+ return { element: element, index: index, rank: rank(read($(element))) };
61
+ })
62
+ .sort(function(a, b) { return a.rank - b.rank || a.index - b.index; })
63
+ .map(function(entry) { return entry.element; });
64
+ }
65
+
66
+ function sameOrder(a, b) {
67
+ return a.every(function(element, index) { return element === b[index]; });
68
+ }
69
+
70
+ /**
71
+ * The values that put n columns in n places, or null past eight: that
72
+ * is how many places Bootstrap's order classes have.
73
+ */
74
+ function slots(count) {
75
+ if (count <= 6) { return VALUES.slice(1, 1 + count); }
76
+ if (count === 7) { return VALUES.slice(1); }
77
+ if (count === 8) { return VALUES.slice(); }
78
+
79
+ return null;
80
+ }
81
+
82
+ /**
83
+ * Move a column one place earlier or later in the view being edited.
84
+ *
85
+ * The row's columns are numbered in their new order. When that order is
86
+ * the markup's own, the numbers are taken off instead - unless what is
87
+ * left underneath, the breakpoint below, would then order them some other
88
+ * way, and the numbers are what keep them in the markup's order.
89
+ */
90
+ function move(col, direction) {
91
+ var view = ge.view();
92
+ var columns = col.parent().children('.column');
93
+ var shown = visualOrder(columns, function(column) { return ge.getUtility(column, 'order', view); });
94
+ var from = shown.indexOf(col[0]);
95
+ var to = from + direction;
96
+
97
+ if (to < 0 || to >= shown.length) { return; }
98
+
99
+ shown.splice(to, 0, shown.splice(from, 1)[0]);
100
+
101
+ var values = null;
102
+ if (!sameOrder(shown, columns.get()) || !inheritsMarkupOrder(columns, view)) {
103
+ values = slots(shown.length);
104
+
105
+ if (!values) {
106
+ ge.warn('a row of ' + shown.length + ' columns cannot be reordered with Bootstrap\'s ' +
107
+ 'order classes, which have eight places');
108
+ return;
109
+ }
110
+ }
111
+
112
+ ge.operate(function() {
113
+ shown.forEach(function(element, index) {
114
+ ge.setUtility($(element), 'order', values ? values[index] : null, { source: 'tool' });
115
+ });
116
+ });
117
+ }
118
+
119
+ /** Whether taking this view's classes off leaves the columns in the markup's order. */
120
+ function inheritsMarkupOrder(columns, view) {
121
+ var index = ge.breakpoints.indexOf(view);
122
+ if (index <= 0) { return true; }
123
+
124
+ var below = ge.breakpoints[index - 1];
125
+
126
+ return sameOrder(visualOrder(columns, function(column) {
127
+ return ge.getUtility(column, 'order', below);
128
+ }), columns.get());
129
+ }
130
+
131
+ /** Whether a row's columns are ordered by class, rather than by the markup, in this view. */
132
+ function ordered(row) {
133
+ return row.children('.column').get().some(function(element) {
134
+ return ge.getUtility($(element), 'order', ge.view()) !== null;
135
+ });
136
+ }
137
+
138
+ /** The badge: a column ordered by class in this view says where. */
139
+ function mark(scope) {
140
+ scope.find('.column').addBack('.column').each(function() {
141
+ var col = $(this);
142
+ var value = CLASS_PATTERN.test(col.attr('class') || '')
143
+ ? ge.getUtility(col, 'order', ge.view())
144
+ : null;
145
+
146
+ if (value === null) {
147
+ col.removeAttr('data-ge-order');
148
+ } else {
149
+ col.attr('data-ge-order', ge.t('badge.order', { value: label(value) }));
150
+ }
151
+ });
152
+ }
153
+
154
+ /**
155
+ * A column dropped in a row ordered by class lands where the markup puts
156
+ * it, and shows up where its order does, which is worth saying once.
157
+ */
158
+ function afterMove(e, payload) {
159
+ if (warnedAboutDrag || payload.kind !== 'column' || !payload.to) { return; }
160
+ if (!ordered(payload.to.parent)) { return; }
161
+
162
+ warnedAboutDrag = true;
163
+ ge.warn('a column was dropped in a row whose columns carry order classes in this view: ' +
164
+ 'where it shows is set by those classes, not by where it sits in the markup');
165
+ }
166
+
167
+ return {
168
+ families: [{
169
+ name: 'order',
170
+ prefix: 'order',
171
+ values: VALUES,
172
+ appliesTo: ['column'],
173
+ labelKey: 'utility.order',
174
+ label: label,
175
+ preview: function(value) {
176
+ return { order: rank(value) };
177
+ },
178
+ }],
179
+
180
+ drawerTools: function(drawer, node, kind) {
181
+ if (!options.drawer || kind !== 'column') { return; }
182
+
183
+ ge.createTool(drawer, ge.t('tool.order_earlier'), 'ge-order-earlier', 'bi bi-chevron-left', function() {
184
+ move(node, -1);
185
+ });
186
+ ge.createTool(drawer, ge.t('tool.order_later'), 'ge-order-later', 'bi bi-chevron-right', function() {
187
+ move(node, 1);
188
+ });
189
+ },
190
+
191
+ // init runs again whenever a node is added, without a deinit
192
+ // between, so the listener is replaced rather than stacked
193
+ onInit: function() {
194
+ ge.canvas.off('grideditor:after-move.ge-order').on('grideditor:after-move.ge-order', afterMove);
195
+ },
196
+
197
+ onRefresh: mark,
198
+
199
+ onDeinit: function() {
200
+ ge.canvas.off('grideditor:after-move.ge-order');
201
+ ge.canvas.find('[data-ge-order]').removeAttr('data-ge-order');
202
+ },
203
+ };
204
+ };
205
+
206
+ })(jQuery);