@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.
- package/AUTO_SAVE.md +2 -2
- package/BUILDING.md +45 -29
- package/CHANGELOG.md +59 -0
- package/README.md +163 -87
- package/UPGRADING.md +119 -0
- package/dist/grideditor.bundle.min.js +14 -0
- package/dist/grideditor.d.ts +335 -0
- package/dist/grideditor.esm.js +3977 -0
- package/dist/grideditor.jquery.js +253 -0
- package/dist/grideditor.jquery.min.js +1 -0
- package/dist/grideditor.jquery.min.js.map +7 -0
- package/dist/grideditor.js +3983 -0
- package/dist/grideditor.min.js +6 -0
- package/dist/grideditor.min.js.map +7 -0
- package/dist/locales/grideditor.es.esm.js +158 -0
- package/dist/locales/grideditor.es.js +164 -168
- package/dist/locales/grideditor.es.min.js +6 -2
- package/dist/locales/grideditor.es.min.js.map +7 -1
- package/dist/plugins/grideditor.accordion.esm.js +294 -0
- package/dist/plugins/grideditor.accordion.js +286 -180
- package/dist/plugins/grideditor.accordion.min.js +1 -2
- package/dist/plugins/grideditor.accordion.min.js.map +7 -1
- package/dist/plugins/grideditor.alignment.esm.js +55 -0
- package/dist/plugins/grideditor.alignment.js +58 -77
- package/dist/plugins/grideditor.alignment.min.js +1 -2
- package/dist/plugins/grideditor.alignment.min.js.map +7 -1
- package/dist/plugins/grideditor.card.esm.js +73 -0
- package/dist/plugins/grideditor.card.js +74 -64
- package/dist/plugins/grideditor.card.min.js +1 -2
- package/dist/plugins/grideditor.card.min.js.map +7 -1
- package/dist/plugins/grideditor.ckeditor.esm.js +500 -0
- package/dist/plugins/grideditor.ckeditor.js +484 -449
- package/dist/plugins/grideditor.ckeditor.min.js +1 -2
- package/dist/plugins/grideditor.ckeditor.min.js.map +7 -1
- package/dist/plugins/grideditor.clipboard.esm.js +326 -0
- package/dist/plugins/grideditor.clipboard.js +298 -235
- package/dist/plugins/grideditor.clipboard.min.js +1 -2
- package/dist/plugins/grideditor.clipboard.min.js.map +7 -1
- package/dist/plugins/grideditor.codemirror-inline.esm.js +205 -0
- package/dist/plugins/grideditor.codemirror-inline.js +188 -168
- package/dist/plugins/grideditor.codemirror-inline.min.js +1 -2
- package/dist/plugins/grideditor.codemirror-inline.min.js.map +7 -1
- package/dist/plugins/grideditor.codemirror.esm.js +63 -0
- package/dist/plugins/grideditor.codemirror.js +60 -71
- package/dist/plugins/grideditor.codemirror.min.js +1 -2
- package/dist/plugins/grideditor.codemirror.min.js.map +7 -1
- package/dist/plugins/grideditor.elements.esm.js +271 -0
- package/dist/plugins/grideditor.elements.js +256 -149
- package/dist/plugins/grideditor.elements.min.js +1 -2
- package/dist/plugins/grideditor.elements.min.js.map +7 -1
- package/dist/plugins/grideditor.float.esm.js +34 -0
- package/dist/plugins/grideditor.float.js +37 -52
- package/dist/plugins/grideditor.float.min.js +1 -2
- package/dist/plugins/grideditor.float.min.js.map +7 -1
- package/dist/plugins/grideditor.gutters.esm.js +143 -0
- package/dist/plugins/grideditor.gutters.js +134 -131
- package/dist/plugins/grideditor.gutters.min.js +1 -2
- package/dist/plugins/grideditor.gutters.min.js.map +7 -1
- package/dist/plugins/grideditor.order.esm.js +189 -0
- package/dist/plugins/grideditor.order.js +170 -182
- package/dist/plugins/grideditor.order.min.js +1 -2
- package/dist/plugins/grideditor.order.min.js.map +7 -1
- package/dist/plugins/grideditor.popup.esm.js +187 -0
- package/dist/plugins/grideditor.popup.js +183 -134
- package/dist/plugins/grideditor.popup.min.js +1 -2
- package/dist/plugins/grideditor.popup.min.js.map +7 -1
- package/dist/plugins/grideditor.sections.esm.js +271 -0
- package/dist/plugins/grideditor.sections.js +250 -173
- package/dist/plugins/grideditor.sections.min.js +1 -2
- package/dist/plugins/grideditor.sections.min.js.map +7 -1
- package/dist/plugins/grideditor.spacing.esm.js +318 -0
- package/dist/plugins/grideditor.spacing.js +296 -272
- package/dist/plugins/grideditor.spacing.min.js +1 -2
- package/dist/plugins/grideditor.spacing.min.js.map +7 -1
- package/dist/plugins/grideditor.summernote.esm.js +509 -0
- package/dist/plugins/grideditor.summernote.js +493 -427
- package/dist/plugins/grideditor.summernote.min.js +1 -2
- package/dist/plugins/grideditor.summernote.min.js.map +7 -1
- package/dist/plugins/grideditor.tabs.esm.js +237 -0
- package/dist/plugins/grideditor.tabs.js +233 -139
- package/dist/plugins/grideditor.tabs.min.js +1 -2
- package/dist/plugins/grideditor.tabs.min.js.map +7 -1
- package/dist/plugins/grideditor.textalign.esm.js +40 -0
- package/dist/plugins/grideditor.textalign.js +43 -56
- package/dist/plugins/grideditor.textalign.min.js +1 -2
- package/dist/plugins/grideditor.textalign.min.js.map +7 -1
- package/dist/plugins/grideditor.tinymce.esm.js +519 -0
- package/dist/plugins/grideditor.tinymce.js +502 -490
- package/dist/plugins/grideditor.tinymce.min.js +1 -2
- package/dist/plugins/grideditor.tinymce.min.js.map +7 -1
- package/dist/plugins/grideditor.visibility.esm.js +158 -0
- package/dist/plugins/grideditor.visibility.js +140 -149
- package/dist/plugins/grideditor.visibility.min.js +1 -2
- package/dist/plugins/grideditor.visibility.min.js.map +7 -1
- package/docs/events.md +47 -21
- package/docs/locale-keys.md +6 -0
- package/docs/plugins.md +47 -25
- package/example/adapter.html +112 -0
- package/example/attributes.html +89 -62
- package/example/autocols.html +9 -9
- package/example/autosave.html +18 -16
- package/example/basic.html +8 -6
- package/example/breakpoints.html +5 -6
- package/example/ckeditor.html +4 -5
- package/example/clipboard.html +15 -11
- package/example/codemirror.html +13 -8
- package/example/containers.html +11 -9
- package/example/custom_editor.html +53 -34
- package/example/elements.html +14 -12
- package/example/index.html +16 -2
- package/example/locale.html +6 -7
- package/example/plugins.html +44 -29
- package/example/summernote.html +6 -5
- package/example/utilities.html +17 -13
- package/example/wrap_content.html +13 -10
- package/package.json +44 -12
- package/src/js/dom.js +401 -0
- package/src/js/grideditor.classic.js +16 -0
- package/src/js/grideditor.jquery.js +325 -0
- package/src/js/{jquery.grideditor.js → grideditor.js} +1284 -1124
- package/src/js/locales/grideditor.es.js +163 -156
- package/src/js/plugins/grideditor.accordion.js +97 -77
- package/src/js/plugins/grideditor.alignment.js +5 -7
- package/src/js/plugins/grideditor.card.js +23 -23
- package/src/js/plugins/grideditor.ckeditor.js +107 -106
- package/src/js/plugins/grideditor.clipboard.js +49 -37
- package/src/js/plugins/grideditor.codemirror-inline.js +50 -37
- package/src/js/plugins/grideditor.codemirror.js +9 -10
- package/src/js/plugins/grideditor.elements.js +57 -33
- package/src/js/plugins/grideditor.float.js +4 -6
- package/src/js/plugins/grideditor.gutters.js +20 -15
- package/src/js/plugins/grideditor.order.js +28 -25
- package/src/js/plugins/grideditor.popup.js +63 -51
- package/src/js/plugins/grideditor.sections.js +39 -32
- package/src/js/plugins/grideditor.spacing.js +42 -45
- package/src/js/plugins/grideditor.summernote.js +112 -76
- package/src/js/plugins/grideditor.tabs.js +65 -57
- package/src/js/plugins/grideditor.textalign.js +4 -6
- package/src/js/plugins/grideditor.tinymce.js +148 -140
- package/src/js/plugins/grideditor.visibility.js +24 -25
- package/src/js/register.js +18 -0
- package/src/js/text/grideditor.text.js +77 -56
- package/types/grideditor.d.ts +335 -0
- package/dist/jquery.grideditor.bundle.min.js +0 -10
- package/dist/jquery.grideditor.js +0 -4927
- package/dist/jquery.grideditor.min.js +0 -2
- package/dist/jquery.grideditor.min.js.map +0 -1
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Grid editor
|
|
2
|
+
* Grid editor.
|
|
3
3
|
*
|
|
4
4
|
* A fork of https://github.com/Friendly-Pixel/grid-editor by Simon Epskamp,
|
|
5
5
|
* maintained at https://github.com/themarioga/grid-editor.
|
|
6
|
+
*
|
|
7
|
+
* Plain DOM since 7.0: nothing here needs jQuery. A page written for the 6.x
|
|
8
|
+
* jQuery API loads grideditor.jquery.js beside this file and keeps working;
|
|
9
|
+
* see UPGRADING.md.
|
|
6
10
|
*/
|
|
7
|
-
|
|
11
|
+
import * as dom from './dom.js';
|
|
8
12
|
|
|
9
13
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
14
|
-
* element of the set only and does not chain. `noInstance` is the answer for
|
|
15
|
-
* an element that carries no editor; every other method is a no-op returning
|
|
16
|
-
* the set. `unimplemented` registers a method a later phase fills in, so a
|
|
17
|
-
* host that calls it early gets told rather than ignored.
|
|
14
|
+
* The methods an instance has, and which of them hand back something other
|
|
15
|
+
* than the instance: html, a view key, a created node. After destroy() every
|
|
16
|
+
* one of them is a no-op that says so once, and the value methods answer
|
|
17
|
+
* null - but for getHtml and getPlainHtml, which read the element as it is.
|
|
18
18
|
*/
|
|
19
19
|
var METHODS = {
|
|
20
|
-
getHtml: { value: true
|
|
21
|
-
getPlainHtml: { value: true
|
|
20
|
+
getHtml: { value: true },
|
|
21
|
+
getPlainHtml: { value: true },
|
|
22
22
|
init: {},
|
|
23
23
|
deinit: {},
|
|
24
24
|
reset: {},
|
|
25
25
|
destroy: {},
|
|
26
|
-
remove: {},
|
|
27
26
|
changeView: {},
|
|
28
27
|
getView: { value: true },
|
|
29
28
|
createRow: { value: true },
|
|
@@ -170,6 +169,9 @@ var warned = {};
|
|
|
170
169
|
/** Editors on the page, counted so each one's sortable groups are its own. */
|
|
171
170
|
var editorCounter = 0;
|
|
172
171
|
|
|
172
|
+
/** The editor on each canvas element, so there is never a second one. */
|
|
173
|
+
var instances = new WeakMap();
|
|
174
|
+
|
|
173
175
|
/**
|
|
174
176
|
* Translate one key.
|
|
175
177
|
*
|
|
@@ -177,12 +179,11 @@ var editorCounter = 0;
|
|
|
177
179
|
* then the key itself, so a missing string is a visible key and never an
|
|
178
180
|
* empty tooltip. `params` fills {name} placeholders.
|
|
179
181
|
*
|
|
180
|
-
* Exposed as
|
|
181
|
-
*
|
|
182
|
-
* own.
|
|
182
|
+
* Exposed as GridEditor.t for the plugins that have settings and no
|
|
183
|
+
* instance of their own.
|
|
183
184
|
*/
|
|
184
185
|
function translate(settings, key, params) {
|
|
185
|
-
var locales =
|
|
186
|
+
var locales = GridEditor.locales;
|
|
186
187
|
var locale = locales[settings.locale] || {};
|
|
187
188
|
var overrides = settings.locale_strings || {};
|
|
188
189
|
var string = overrides[key];
|
|
@@ -213,40 +214,46 @@ function warnOnce(key, message) {
|
|
|
213
214
|
warn(message);
|
|
214
215
|
}
|
|
215
216
|
|
|
217
|
+
/** A string in English, for the few things said before an editor has settings. */
|
|
218
|
+
function english(key, params) {
|
|
219
|
+
return translate({ locale: 'en' }, key, params);
|
|
220
|
+
}
|
|
221
|
+
|
|
216
222
|
/**
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
* the set comes back for chaining, so host code does not have to check first.
|
|
221
|
-
* `getHtml` is the exception, because reading an element's html makes sense
|
|
222
|
-
* whether or not it is being edited.
|
|
223
|
+
* The element an editor goes on: an element, or the first one a selector
|
|
224
|
+
* matches. Anything else is a mistake worth throwing for, since there is no
|
|
225
|
+
* editor to hand back.
|
|
223
226
|
*/
|
|
224
|
-
function
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
return set;
|
|
227
|
+
function targetElement(target) {
|
|
228
|
+
if (typeof target === 'string') {
|
|
229
|
+
var found = document.querySelector(target);
|
|
230
|
+
if (!found) { throw new TypeError('grid-editor: no element matches ' + JSON.stringify(target)); }
|
|
231
|
+
return found;
|
|
230
232
|
}
|
|
231
233
|
|
|
232
|
-
if (
|
|
233
|
-
var element = set.first();
|
|
234
|
-
if (!element.length) { return null; }
|
|
234
|
+
if (target && target.nodeType === 1) { return target; }
|
|
235
235
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
236
|
+
throw new TypeError('grid-editor: the target is an element or a selector, not ' +
|
|
237
|
+
(target === null ? 'null' : typeof target));
|
|
238
|
+
}
|
|
240
239
|
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
/** A node a caller handed in, as an element: an element, a selector's first match, or null. */
|
|
241
|
+
function nodeFrom(node) {
|
|
242
|
+
if (typeof node === 'string') { return document.querySelector(node); }
|
|
243
|
+
return node && node.nodeType === 1 ? node : null;
|
|
244
|
+
}
|
|
243
245
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
246
|
+
/**
|
|
247
|
+
* SortableJS, and Bootstrap's Modal, as the host provided them: assigned to
|
|
248
|
+
* GridEditor by a page that imports them as modules, or the page's globals.
|
|
249
|
+
*/
|
|
250
|
+
function sortableLibrary() {
|
|
251
|
+
return GridEditor.Sortable || window.Sortable || null;
|
|
252
|
+
}
|
|
248
253
|
|
|
249
|
-
|
|
254
|
+
function modalLibrary() {
|
|
255
|
+
var bootstrap = GridEditor.bootstrap || window.bootstrap;
|
|
256
|
+
return bootstrap && bootstrap.Modal ? bootstrap.Modal : null;
|
|
250
257
|
}
|
|
251
258
|
|
|
252
259
|
/**
|
|
@@ -261,60 +268,85 @@ function dispatch(set, name, args) {
|
|
|
261
268
|
function plainHtml(html) {
|
|
262
269
|
// Parsed in a document of its own, which is inert: no script in the
|
|
263
270
|
// markup runs and no image starts loading while it is being cleaned
|
|
264
|
-
var root =
|
|
265
|
-
root
|
|
271
|
+
var root = document.implementation.createHTMLDocument('').body;
|
|
272
|
+
root.innerHTML = html;
|
|
266
273
|
var emptied = [];
|
|
267
274
|
|
|
268
|
-
|
|
269
|
-
var node = $(this);
|
|
275
|
+
dom.all(root, '*').forEach(function(node) {
|
|
270
276
|
var marked = false;
|
|
271
277
|
|
|
272
|
-
|
|
278
|
+
Array.prototype.slice.call(node.attributes).forEach(function(attribute) {
|
|
273
279
|
if (attribute.name.indexOf('data-ge-') === 0) {
|
|
274
|
-
node.
|
|
280
|
+
node.removeAttribute(attribute.name);
|
|
275
281
|
marked = true;
|
|
276
282
|
}
|
|
277
283
|
});
|
|
278
284
|
|
|
279
|
-
var classes = (node.
|
|
285
|
+
var classes = (node.getAttribute('class') || '').split(/\s+/).filter(Boolean);
|
|
280
286
|
var kept = classes.filter(function(name) {
|
|
281
287
|
return name !== 'column' && name.indexOf('ge-') !== 0;
|
|
282
288
|
});
|
|
283
289
|
if (kept.length !== classes.length) { marked = true; }
|
|
284
290
|
if (kept.length) {
|
|
285
|
-
node.
|
|
291
|
+
node.setAttribute('class', kept.join(' '));
|
|
286
292
|
} else {
|
|
287
|
-
node.
|
|
293
|
+
node.removeAttribute('class');
|
|
288
294
|
}
|
|
289
295
|
|
|
290
|
-
if (marked &&
|
|
291
|
-
emptied.push(
|
|
296
|
+
if (marked && node.tagName === 'DIV' && !node.attributes.length) {
|
|
297
|
+
emptied.push(node);
|
|
292
298
|
}
|
|
293
299
|
});
|
|
294
300
|
|
|
295
301
|
emptied.forEach(function(div) {
|
|
296
|
-
|
|
302
|
+
dom.unwrap(div);
|
|
297
303
|
});
|
|
298
304
|
|
|
299
|
-
return root
|
|
305
|
+
return root.innerHTML;
|
|
300
306
|
}
|
|
301
307
|
|
|
302
|
-
|
|
308
|
+
/**
|
|
309
|
+
* An editor on `target`: an element, or the first one a selector matches.
|
|
310
|
+
*
|
|
311
|
+
* var ge = new GridEditor('#myGrid', { new_row_layouts: [[12], [6, 6]] });
|
|
312
|
+
* var html = ge.getHtml();
|
|
313
|
+
*
|
|
314
|
+
* An element carries one editor at most: asked for a second, this hands back
|
|
315
|
+
* the one it has, with the options it was made with, and says so once.
|
|
316
|
+
*/
|
|
317
|
+
function GridEditor(target, options) {
|
|
318
|
+
var element = targetElement(target);
|
|
319
|
+
var existing = instances.get(element);
|
|
303
320
|
|
|
304
|
-
|
|
321
|
+
if (existing) {
|
|
322
|
+
if (!doubleWarned.has(element)) {
|
|
323
|
+
doubleWarned.add(element);
|
|
324
|
+
warn(english('warning.already_editing'));
|
|
325
|
+
}
|
|
326
|
+
return existing;
|
|
327
|
+
}
|
|
305
328
|
|
|
306
|
-
|
|
329
|
+
if (!(this instanceof GridEditor)) { return new GridEditor(element, options); }
|
|
307
330
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
331
|
+
build(this, element, options || {});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** The elements a second editor was asked for on, so each is told about once. */
|
|
335
|
+
var doubleWarned = new WeakSet();
|
|
336
|
+
|
|
337
|
+
GridEditor.create = function(target, options) {
|
|
338
|
+
return new GridEditor(target, options);
|
|
339
|
+
};
|
|
311
340
|
|
|
312
|
-
|
|
341
|
+
/** The editor on `target`, or null. */
|
|
342
|
+
GridEditor.get = function(target) {
|
|
343
|
+
var element = nodeFrom(target);
|
|
344
|
+
return element ? instances.get(element) || null : null;
|
|
345
|
+
};
|
|
313
346
|
|
|
314
|
-
|
|
315
|
-
baseElem = $(baseElem);
|
|
347
|
+
function build(instance, baseElem, optionsOrMethod) {
|
|
316
348
|
|
|
317
|
-
var settings =
|
|
349
|
+
var settings = Object.assign({
|
|
318
350
|
'new_row_layouts' : [ // Column layouts for add row buttons
|
|
319
351
|
[12],
|
|
320
352
|
[6, 6],
|
|
@@ -330,8 +362,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
330
362
|
'col_tools' : [], /* Example:
|
|
331
363
|
[ {
|
|
332
364
|
title: 'Set background image',
|
|
333
|
-
iconClass: '
|
|
334
|
-
on: { click: function() {} }
|
|
365
|
+
iconClass: 'bi bi-image',
|
|
366
|
+
on: { click: function(event) {} }
|
|
335
367
|
} ]
|
|
336
368
|
*/
|
|
337
369
|
'row_tools' : [],
|
|
@@ -359,7 +391,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
359
391
|
'resize' : NESTED_SETTINGS.resize, // Resizing a column by dragging its edge
|
|
360
392
|
'source_textarea' : '',
|
|
361
393
|
'edit_source' : true, // The toolbar's button to edit the canvas as html
|
|
362
|
-
'locale' : 'en', // Code of a locale in
|
|
394
|
+
'locale' : 'en', // Code of a locale in GridEditor.locales
|
|
363
395
|
'locale_strings' : {}, // Overrides for individual keys
|
|
364
396
|
'callbacks' : {}, // before_*/after_* functions, the events by another route
|
|
365
397
|
'confirm_delete' : true, // Ask before deleting a row or a column
|
|
@@ -369,18 +401,18 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
369
401
|
|
|
370
402
|
// Merged rather than replaced, so `elements: { auto: true }` keeps the
|
|
371
403
|
// default selector instead of losing it
|
|
372
|
-
|
|
373
|
-
settings[name] =
|
|
404
|
+
Object.keys(NESTED_SETTINGS).forEach(function(name) {
|
|
405
|
+
settings[name] = Object.assign({}, NESTED_SETTINGS[name], settings[name]);
|
|
374
406
|
});
|
|
375
407
|
|
|
376
408
|
// Both handed out the drag toolkit's own options, which 4.0 stops
|
|
377
409
|
// promising: there is no widget underneath a host should be reaching
|
|
378
410
|
// for. What they were used for is a setting of the editor's now.
|
|
379
|
-
|
|
411
|
+
Object.keys(REMOVED_SETTINGS).forEach(function(name) {
|
|
380
412
|
if (optionsOrMethod && optionsOrMethod[name] !== undefined) {
|
|
381
|
-
warn(
|
|
413
|
+
warn(translate(settings, 'warning.setting_removed', {
|
|
382
414
|
setting: name,
|
|
383
|
-
replacement:
|
|
415
|
+
replacement: REMOVED_SETTINGS[name],
|
|
384
416
|
}));
|
|
385
417
|
}
|
|
386
418
|
});
|
|
@@ -403,10 +435,24 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
403
435
|
var warnedHere = {}; // Deprecations are worth saying once per instance, not once per call
|
|
404
436
|
var sortables = []; // Every list made sortable, so deinit destroys exactly those
|
|
405
437
|
var instanceId = ++editorCounter; // Scopes the sortable groups to this editor
|
|
438
|
+
var destroyed = false;
|
|
439
|
+
|
|
440
|
+
// What the editor remembers about the nodes it edits, which used to
|
|
441
|
+
// be jQuery data: a node's settings panel, a drag or a resize in
|
|
442
|
+
// progress. Kept off the markup, and gone with the node.
|
|
443
|
+
var detailsFor = new WeakMap(); // node -> its settings panel
|
|
444
|
+
var moves = new WeakMap(); // dragged node -> { from, canceled }
|
|
445
|
+
var resizes = new WeakMap(); // column -> { from, units }
|
|
446
|
+
var sectionNodes = new WeakMap(); // Responsive section -> the node it edits
|
|
447
|
+
var editableLabels = new WeakSet(); // labels made editable in place
|
|
406
448
|
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
|
|
449
|
+
// Listeners the editor puts on things it does not own - the window,
|
|
450
|
+
// the document, the canvas - taken off together by destroy()
|
|
451
|
+
var lifetime = new AbortController();
|
|
452
|
+
|
|
453
|
+
// Before anything else, because the instance hands the canvas to
|
|
454
|
+
// hosts and the rest of setup() runs at the end of this function
|
|
455
|
+
canvas = dom.addClass(baseElem, 'ge-canvas');
|
|
410
456
|
|
|
411
457
|
function warnOnceHere(key, message) {
|
|
412
458
|
if (warnedHere[key]) { return; }
|
|
@@ -425,7 +471,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
425
471
|
*/
|
|
426
472
|
function setLocale(code) {
|
|
427
473
|
settings.locale = code;
|
|
428
|
-
|
|
474
|
+
instance.settings = settingsCopy();
|
|
429
475
|
|
|
430
476
|
removeConfirmModal();
|
|
431
477
|
removeSettingsPanels();
|
|
@@ -442,14 +488,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
442
488
|
* so no caller assembles one by hand and gets a field wrong.
|
|
443
489
|
*
|
|
444
490
|
* `parent` is where the node is going, or where it is coming from on a
|
|
445
|
-
* delete, which is not the same as node
|
|
491
|
+
* delete, which is not the same as the node's parent while the node is
|
|
446
492
|
* still detached - so an add passes it in.
|
|
447
493
|
*/
|
|
448
494
|
function payloadFor(kind, node, extra) {
|
|
449
|
-
return
|
|
495
|
+
return Object.assign({
|
|
450
496
|
kind: kind,
|
|
451
497
|
node: node,
|
|
452
|
-
parent: node.
|
|
498
|
+
parent: node.parentElement,
|
|
453
499
|
canvas: canvas,
|
|
454
500
|
breakpoint: getView(),
|
|
455
501
|
source: 'api',
|
|
@@ -457,11 +503,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
457
503
|
}
|
|
458
504
|
|
|
459
505
|
/**
|
|
460
|
-
* Deliver one notification twice: as a
|
|
461
|
-
*
|
|
506
|
+
* Deliver one notification twice: as a DOM event on the canvas - the
|
|
507
|
+
* specific name first, then the generic one - and as the matching
|
|
462
508
|
* settings.callbacks entries. Everything is delivered whatever the
|
|
463
509
|
* first listener says, and the answer is whether any of them canceled,
|
|
464
510
|
* which only means something for a before-* notification.
|
|
511
|
+
*
|
|
512
|
+
* A listener that throws is the browser's to report: the other
|
|
513
|
+
* listeners, the callbacks and the operation go on.
|
|
465
514
|
*/
|
|
466
515
|
function emit(name, payload) {
|
|
467
516
|
var names = [name];
|
|
@@ -471,9 +520,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
471
520
|
var canceled = false;
|
|
472
521
|
|
|
473
522
|
names.forEach(function(eventName) {
|
|
474
|
-
var event =
|
|
475
|
-
|
|
476
|
-
|
|
523
|
+
var event = new CustomEvent('grideditor:' + eventName, {
|
|
524
|
+
detail: payload,
|
|
525
|
+
bubbles: true,
|
|
526
|
+
cancelable: true,
|
|
527
|
+
});
|
|
528
|
+
if (!canvas.dispatchEvent(event)) { canceled = true; }
|
|
477
529
|
});
|
|
478
530
|
|
|
479
531
|
names.forEach(function(eventName) {
|
|
@@ -548,7 +600,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
548
600
|
* containers binds one name, not three.
|
|
549
601
|
*/
|
|
550
602
|
function addEventName(kind) {
|
|
551
|
-
return
|
|
603
|
+
return GridEditor.containers[kind] ? 'container' : kind;
|
|
552
604
|
}
|
|
553
605
|
|
|
554
606
|
/**
|
|
@@ -560,7 +612,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
560
612
|
* so it is never part of what getHtml returns.
|
|
561
613
|
*
|
|
562
614
|
* A page that loaded Bootstrap's css but not its javascript still gets
|
|
563
|
-
* asked - by the browser, as before.
|
|
615
|
+
* asked - by the browser, as before. A page that imports Bootstrap as
|
|
616
|
+
* a module hands its Modal over as GridEditor.bootstrap.
|
|
564
617
|
*/
|
|
565
618
|
function askToDelete(message, whenConfirmed) {
|
|
566
619
|
if (!settings.confirm_delete) {
|
|
@@ -568,7 +621,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
568
621
|
return;
|
|
569
622
|
}
|
|
570
623
|
|
|
571
|
-
|
|
624
|
+
var Modal = modalLibrary();
|
|
625
|
+
|
|
626
|
+
if (!Modal) {
|
|
572
627
|
if (window.confirm(message)) { whenConfirmed(); }
|
|
573
628
|
return;
|
|
574
629
|
}
|
|
@@ -576,30 +631,34 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
576
631
|
var modal = confirmModal();
|
|
577
632
|
var confirmed = false;
|
|
578
633
|
|
|
579
|
-
|
|
580
|
-
|
|
634
|
+
dom.one(modal, '.ge-confirm-message').textContent = message;
|
|
635
|
+
dom.one(modal, '.ge-confirm-ok').onclick = function() {
|
|
581
636
|
confirmed = true;
|
|
582
|
-
|
|
583
|
-
}
|
|
637
|
+
Modal.getInstance(modal).hide();
|
|
638
|
+
};
|
|
584
639
|
|
|
585
|
-
|
|
640
|
+
confirmHandlers.hidden = function() {
|
|
586
641
|
// After the modal is out of the way, so the backdrop is not
|
|
587
642
|
// sitting over the animation the delete runs
|
|
588
643
|
if (confirmed) { whenConfirmed(); }
|
|
589
|
-
}
|
|
644
|
+
};
|
|
590
645
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
646
|
+
confirmHandlers.shown = function() {
|
|
647
|
+
dom.one(modal, '.ge-confirm-ok').focus();
|
|
648
|
+
};
|
|
594
649
|
|
|
595
|
-
|
|
650
|
+
Modal.getOrCreateInstance(modal).show();
|
|
596
651
|
}
|
|
597
652
|
|
|
653
|
+
// What the confirm modal does when Bootstrap says it is shown or
|
|
654
|
+
// hidden: this question's answer, replaced by the next question's
|
|
655
|
+
var confirmHandlers = { hidden: null, shown: null };
|
|
656
|
+
|
|
598
657
|
/** Built once per instance, and taken away again by destroy(). */
|
|
599
658
|
function confirmModal() {
|
|
600
659
|
if (confirmDialog) { return confirmDialog; }
|
|
601
660
|
|
|
602
|
-
confirmDialog =
|
|
661
|
+
confirmDialog = dom.create(
|
|
603
662
|
'<div class="modal fade ge-confirm" tabindex="-1" aria-hidden="true">' +
|
|
604
663
|
'<div class="modal-dialog modal-dialog-centered">' +
|
|
605
664
|
'<div class="modal-content">' +
|
|
@@ -615,12 +674,21 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
615
674
|
'</div>' +
|
|
616
675
|
'</div>' +
|
|
617
676
|
'</div>'
|
|
618
|
-
)
|
|
677
|
+
);
|
|
678
|
+
document.body.appendChild(confirmDialog);
|
|
619
679
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
680
|
+
dom.one(confirmDialog, '.modal-title').textContent = t('confirm.title');
|
|
681
|
+
dom.one(confirmDialog, '.btn-close').setAttribute('aria-label', t('confirm.cancel'));
|
|
682
|
+
dom.one(confirmDialog, '.ge-confirm-cancel').textContent = t('confirm.cancel');
|
|
683
|
+
dom.one(confirmDialog, '.ge-confirm-ok').textContent = t('confirm.ok');
|
|
684
|
+
|
|
685
|
+
trackModal(confirmDialog);
|
|
686
|
+
confirmDialog.addEventListener('hidden.bs.modal', function() {
|
|
687
|
+
if (confirmHandlers.hidden) { confirmHandlers.hidden(); }
|
|
688
|
+
});
|
|
689
|
+
confirmDialog.addEventListener('shown.bs.modal', function() {
|
|
690
|
+
if (confirmHandlers.shown) { confirmHandlers.shown(); }
|
|
691
|
+
});
|
|
624
692
|
|
|
625
693
|
return confirmDialog;
|
|
626
694
|
}
|
|
@@ -629,13 +697,48 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
629
697
|
function removeConfirmModal() {
|
|
630
698
|
if (!confirmDialog) { return; }
|
|
631
699
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
700
|
+
// Its answer is not wanted any more: the editor it asked for is going
|
|
701
|
+
confirmHandlers.hidden = null;
|
|
702
|
+
confirmHandlers.shown = null;
|
|
703
|
+
retireModal(confirmDialog);
|
|
704
|
+
confirmDialog = null;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Take a Bootstrap modal away. One out of sight goes at once. One that
|
|
709
|
+
* is showing, or on its way in or out, is asked to hide and goes when
|
|
710
|
+
* Bootstrap says it is hidden: Bootstrap finishes a transition on the
|
|
711
|
+
* node it started it on, and a node taken away under it throws, and
|
|
712
|
+
* leaves the page's body locked, with no scrolling.
|
|
713
|
+
*/
|
|
714
|
+
function retireModal(panel) {
|
|
715
|
+
var Modal = modalLibrary();
|
|
716
|
+
var modal = Modal ? Modal.getInstance(panel) : null;
|
|
717
|
+
var gone = false;
|
|
718
|
+
var finish = function() {
|
|
719
|
+
if (gone) { return; }
|
|
720
|
+
gone = true;
|
|
721
|
+
if (modal) { modal.dispose(); }
|
|
722
|
+
panel.remove();
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
if (!modal || (!modalMoving.get(panel) && !dom.hasClass(panel, 'show'))) {
|
|
726
|
+
finish();
|
|
727
|
+
return;
|
|
635
728
|
}
|
|
636
729
|
|
|
637
|
-
|
|
638
|
-
|
|
730
|
+
panel.addEventListener('hidden.bs.modal', finish, { once: true });
|
|
731
|
+
// Still on its way in, it ignores a hide: once it is in, it takes one
|
|
732
|
+
panel.addEventListener('shown.bs.modal', function() { modal.hide(); }, { once: true });
|
|
733
|
+
modal.hide();
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/** Whether a modal is between Bootstrap's show and shown, or hide and hidden. */
|
|
737
|
+
var modalMoving = new WeakMap();
|
|
738
|
+
|
|
739
|
+
function trackModal(panel) {
|
|
740
|
+
dom.on(panel, 'show.bs.modal hide.bs.modal', function() { modalMoving.set(panel, true); });
|
|
741
|
+
dom.on(panel, 'shown.bs.modal hidden.bs.modal', function() { modalMoving.set(panel, false); });
|
|
639
742
|
}
|
|
640
743
|
|
|
641
744
|
/**
|
|
@@ -815,51 +918,57 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
815
918
|
* counted, so the index is the one a host would recognize.
|
|
816
919
|
*/
|
|
817
920
|
function positionOf(node) {
|
|
818
|
-
var parent = node.
|
|
921
|
+
var parent = node.parentElement;
|
|
819
922
|
|
|
820
923
|
return {
|
|
821
924
|
parent: parent,
|
|
822
|
-
index:
|
|
925
|
+
index: dom.children(parent).filter(function(child) {
|
|
926
|
+
return !dom.hasClass(child, 'ge-tools-drawer');
|
|
927
|
+
}).indexOf(node),
|
|
823
928
|
};
|
|
824
929
|
}
|
|
825
930
|
|
|
826
931
|
function kindOf(node) {
|
|
827
932
|
var fromPlugin = null;
|
|
828
933
|
|
|
829
|
-
|
|
934
|
+
Object.keys(FEATURES).forEach(function(name) {
|
|
935
|
+
var feature = FEATURES[name];
|
|
830
936
|
if (!fromPlugin && feature.kindOf) { fromPlugin = feature.kindOf(node); }
|
|
831
937
|
});
|
|
832
938
|
if (fromPlugin) { return fromPlugin; }
|
|
833
939
|
|
|
834
|
-
if (node.
|
|
835
|
-
if (
|
|
836
|
-
if (
|
|
837
|
-
if (
|
|
838
|
-
if (
|
|
839
|
-
if (
|
|
940
|
+
if (node.getAttribute('data-ge-container')) { return node.getAttribute('data-ge-container'); }
|
|
941
|
+
if (dom.hasClass(node, 'ge-tab')) { return 'tab'; }
|
|
942
|
+
if (dom.hasClass(node, 'ge-accordion-item')) { return 'accordion-item'; }
|
|
943
|
+
if (dom.hasClass(node, 'row')) { return 'row'; }
|
|
944
|
+
if (dom.hasClass(node, 'column')) { return 'column'; }
|
|
945
|
+
if (dom.hasClass(node, 'ge-element')) { return 'element'; }
|
|
840
946
|
// A content area is a text when an editor's type is on it, and the
|
|
841
947
|
// host's plain content when there is none
|
|
842
|
-
if (
|
|
843
|
-
if (
|
|
948
|
+
if (dom.hasClass(node, 'ge-text-block')) { node = dom.child(node, '.ge-content') || node; }
|
|
949
|
+
if (dom.hasClass(node, 'ge-content')) { return node.getAttribute('data-ge-content-type') ? 'text' : 'plain'; }
|
|
844
950
|
return 'node';
|
|
845
951
|
}
|
|
846
|
-
|
|
952
|
+
|
|
847
953
|
// Copy html to sourceElement if a source textarea is given
|
|
848
954
|
if (settings.source_textarea) {
|
|
849
|
-
var sourceHtml =
|
|
955
|
+
var sourceHtml = nodeFrom(settings.source_textarea).value;
|
|
850
956
|
// Html with no grid in it goes into a row and a full width column
|
|
851
957
|
// of its own, where init wraps it as the host's plain content
|
|
852
|
-
|
|
958
|
+
var probe = dom.element('div');
|
|
959
|
+
probe.innerHTML = sourceHtml;
|
|
960
|
+
if (sourceHtml.length > 0 && !probe.querySelector('.row')) {
|
|
853
961
|
sourceHtml = '<div class="row"><div class="col-lg-12">' + sourceHtml + '</div></div>';
|
|
854
962
|
}
|
|
855
|
-
|
|
963
|
+
dom.setHtml(baseElem, sourceHtml);
|
|
856
964
|
}
|
|
857
|
-
|
|
965
|
+
|
|
858
966
|
// Wrap content if it is non-bootstrap
|
|
859
|
-
if (baseElem.children
|
|
860
|
-
var children =
|
|
861
|
-
var newRow =
|
|
862
|
-
|
|
967
|
+
if (baseElem.children.length && !baseElem.querySelector('div.row')) {
|
|
968
|
+
var children = dom.children(baseElem);
|
|
969
|
+
var newRow = dom.create('<div class="row"><div class="col-lg-12"></div></div>');
|
|
970
|
+
baseElem.appendChild(newRow);
|
|
971
|
+
children.forEach(function(child) { newRow.firstChild.appendChild(child); });
|
|
863
972
|
}
|
|
864
973
|
|
|
865
974
|
// setup() and init() run at the end of this function, once every
|
|
@@ -867,29 +976,36 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
867
976
|
// the container registry, and a var declared later is not there yet.
|
|
868
977
|
|
|
869
978
|
function setup() {
|
|
870
|
-
htmlTextArea =
|
|
979
|
+
htmlTextArea = dom.element('textarea', { 'class': 'ge-html-output' });
|
|
980
|
+
canvas.parentNode.insertBefore(htmlTextArea, canvas);
|
|
871
981
|
|
|
872
982
|
createMainControls();
|
|
873
983
|
|
|
984
|
+
var signal = { signal: lifetime.signal };
|
|
985
|
+
|
|
874
986
|
// Make controls fixed on scroll
|
|
875
|
-
|
|
987
|
+
window.addEventListener('scroll', onScroll, signal);
|
|
876
988
|
|
|
877
989
|
/* A click on the host's plain content offers to make it a text */
|
|
878
|
-
|
|
990
|
+
dom.delegate(canvas, 'click', '.ge-content', onContentClick, signal);
|
|
879
991
|
|
|
880
992
|
/* A trigger is often a link, and a link still navigates even
|
|
881
993
|
with its Bootstrap attributes suspended */
|
|
882
|
-
|
|
883
|
-
if (
|
|
884
|
-
});
|
|
994
|
+
dom.delegate(canvas, 'click', '.ge-popup-trigger, [data-ge-popup-target]', function(e) {
|
|
995
|
+
if (dom.hasClass(canvas, 'ge-editing')) { e.preventDefault(); }
|
|
996
|
+
}, signal);
|
|
997
|
+
}
|
|
885
998
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
999
|
+
/**
|
|
1000
|
+
* A rich text editor rewrites the content area as it takes over,
|
|
1001
|
+
* which costs the element drawers inside it. The integrations say
|
|
1002
|
+
* when their editor is ready, and the drawers go back in.
|
|
1003
|
+
*/
|
|
1004
|
+
function textReady(block) {
|
|
1005
|
+
if (!dom.is(block, '.ge-content') || !canvas.contains(block)) { return; }
|
|
1006
|
+
|
|
1007
|
+
plugins('onContentReady', block);
|
|
1008
|
+
refreshPreviews(block);
|
|
893
1009
|
}
|
|
894
1010
|
|
|
895
1011
|
/**
|
|
@@ -897,70 +1013,72 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
897
1013
|
* string in it comes from the locale, so setLocale() rebuilds it.
|
|
898
1014
|
*/
|
|
899
1015
|
function createMainControls() {
|
|
900
|
-
mainControls =
|
|
901
|
-
|
|
1016
|
+
mainControls = dom.element('div', { 'class': 'ge-mainControls' });
|
|
1017
|
+
htmlTextArea.parentNode.insertBefore(mainControls, htmlTextArea);
|
|
1018
|
+
wrapper = mainControls.appendChild(dom.element('div', { 'class': 'ge-wrapper ge-top' }));
|
|
902
1019
|
|
|
903
1020
|
// Add row
|
|
904
|
-
addRowGroup =
|
|
905
|
-
addContainerGroup =
|
|
906
|
-
|
|
1021
|
+
addRowGroup = wrapper.appendChild(dom.element('div', { 'class': 'ge-addRowGroup btn-group' }));
|
|
1022
|
+
addContainerGroup = dom.element('div', { 'class': 'ge-addContainerGroup btn-group ms-1' });
|
|
1023
|
+
settings.new_row_layouts.forEach(function(layout) {
|
|
907
1024
|
var grouped = !Array.isArray(layout);
|
|
908
|
-
var btn =
|
|
909
|
-
|
|
1025
|
+
var btn = dom.element('a', {
|
|
1026
|
+
'class': 'btn btn-sm btn-primary',
|
|
1027
|
+
title: grouped
|
|
910
1028
|
? t('row.add_row_cols', { columns: layout.columns, counts: rowColsText(layout.row_cols) })
|
|
911
|
-
: t('row.add', { layout: layout.join('-') })
|
|
1029
|
+
: t('row.add', { layout: layout.join('-') }),
|
|
912
1030
|
// What this button makes, in the markup rather than in
|
|
913
|
-
//
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
var row = rowFromLayoutValue(layout);
|
|
918
|
-
|
|
919
|
-
var added = addNode('row', row, function() {
|
|
920
|
-
row.appendTo(canvas);
|
|
921
|
-
}, { parent: canvas, source: 'tool' });
|
|
922
|
-
|
|
923
|
-
if (added && row[0].scrollIntoView) {
|
|
924
|
-
row[0].scrollIntoView({behavior: 'smooth'});
|
|
925
|
-
}
|
|
926
|
-
})
|
|
927
|
-
.appendTo(addRowGroup)
|
|
928
|
-
;
|
|
1031
|
+
// memory: a drag works on a clone of it
|
|
1032
|
+
'data-ge-toolbar': 'row',
|
|
1033
|
+
'data-ge-layout': grouped ? JSON.stringify(layout) : layout.join(','),
|
|
1034
|
+
});
|
|
929
1035
|
|
|
930
|
-
btn.
|
|
1036
|
+
btn.addEventListener('click', function() {
|
|
1037
|
+
var row = rowFromLayoutValue(layout);
|
|
1038
|
+
|
|
1039
|
+
var added = addNode('row', row, function() {
|
|
1040
|
+
canvas.appendChild(row);
|
|
1041
|
+
}, { parent: canvas, source: 'tool' });
|
|
1042
|
+
|
|
1043
|
+
if (added && row.scrollIntoView) {
|
|
1044
|
+
row.scrollIntoView({behavior: 'smooth'});
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
addRowGroup.appendChild(btn);
|
|
1048
|
+
|
|
1049
|
+
btn.appendChild(dom.create('<i class="bi bi-plus"></i>'));
|
|
931
1050
|
|
|
932
1051
|
// A row of columns shares out the icon as they share the row;
|
|
933
1052
|
// a row with row-cols draws one line of its widest count
|
|
934
1053
|
var sizes = grouped ? rowColsIcon(layout) : layout;
|
|
935
1054
|
var icon = '<div class="row ge-row-icon">';
|
|
936
1055
|
sizes.forEach(function(size) {
|
|
937
|
-
// Closed explicitly: jQuery 4 no longer expands <div/>, and
|
|
938
|
-
// each column would be parsed inside the one before
|
|
939
1056
|
icon += '<div class="column ' + sizeClass(BREAKPOINTS[0], size) + '"></div>';
|
|
940
1057
|
});
|
|
941
1058
|
icon += '</div>';
|
|
942
|
-
btn.
|
|
1059
|
+
btn.appendChild(dom.create(icon));
|
|
943
1060
|
});
|
|
944
1061
|
|
|
945
|
-
|
|
1062
|
+
wrapper.appendChild(addContainerGroup);
|
|
946
1063
|
|
|
947
1064
|
// A container starts in a row of its own, the way the add row
|
|
948
1065
|
// buttons next to these ones do
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
.
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
;
|
|
1066
|
+
Object.keys(CONTAINERS).forEach(function(type) {
|
|
1067
|
+
var definition = CONTAINERS[type];
|
|
1068
|
+
var button = labelButton(dom.element('a', { 'class': 'btn btn-sm btn-primary ge-add-container' }),
|
|
1069
|
+
t(definition.labelKey), definition.iconClass);
|
|
1070
|
+
|
|
1071
|
+
dom.attr(button, { 'data-ge-toolbar': 'container', 'data-ge-container-type': type });
|
|
1072
|
+
button.addEventListener('click', function() {
|
|
1073
|
+
var row = createRow();
|
|
1074
|
+
var column = row.appendChild(createColumn(MAX_COL_SIZE));
|
|
1075
|
+
var container = column.appendChild(definition.create({}));
|
|
1076
|
+
|
|
1077
|
+
addNode(type, container, function() {
|
|
1078
|
+
canvas.appendChild(row);
|
|
1079
|
+
}, { parent: canvas, source: 'tool' });
|
|
1080
|
+
});
|
|
1081
|
+
addContainerGroup.appendChild(button);
|
|
964
1082
|
});
|
|
965
1083
|
|
|
966
1084
|
// A feature plugin's own buttons, beside the containers': what
|
|
@@ -968,85 +1086,82 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
968
1086
|
// One with align 'end' goes on the right instead, as an icon,
|
|
969
1087
|
// beside the source and preview buttons.
|
|
970
1088
|
var endItems = [];
|
|
971
|
-
|
|
972
|
-
(
|
|
1089
|
+
Object.keys(FEATURES).forEach(function(name) {
|
|
1090
|
+
(FEATURES[name].toolbar || []).forEach(function(item, index) {
|
|
973
1091
|
var button = featureButton(name, item, index);
|
|
974
1092
|
|
|
975
1093
|
if (item.align === 'end') {
|
|
976
1094
|
endItems.push(button);
|
|
977
1095
|
} else {
|
|
978
|
-
|
|
1096
|
+
addContainerGroup.appendChild(button);
|
|
979
1097
|
}
|
|
980
1098
|
});
|
|
981
1099
|
});
|
|
982
1100
|
|
|
983
1101
|
// Buttons on right
|
|
984
|
-
layoutDropdown =
|
|
1102
|
+
layoutDropdown = dom.create('<div class="dropdown pull-right ge-layout-mode">' +
|
|
985
1103
|
'<button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-bs-toggle="dropdown"></button>' +
|
|
986
1104
|
'<div class="dropdown-menu" role="menu"></div>' +
|
|
987
|
-
'</div>')
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1105
|
+
'</div>');
|
|
1106
|
+
dom.delegate(layoutDropdown, 'click', 'a', function() {
|
|
1107
|
+
// Through changeView, so the dropdown and the method are
|
|
1108
|
+
// one path rather than two that have to agree
|
|
1109
|
+
changeView(this.getAttribute('data-ge-view'));
|
|
1110
|
+
});
|
|
1111
|
+
wrapper.appendChild(layoutDropdown);
|
|
1112
|
+
|
|
995
1113
|
settings.layout_modes.forEach(function(view) {
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
;
|
|
1114
|
+
dom.one(layoutDropdown, '.dropdown-menu').appendChild(dom.element('a', {
|
|
1115
|
+
'class': 'dropdown-item',
|
|
1116
|
+
'data-ge-view': view,
|
|
1117
|
+
title: t(labelKeyFor(view)),
|
|
1118
|
+
}, t(labelKeyFor(view))));
|
|
1002
1119
|
});
|
|
1003
|
-
|
|
1120
|
+
dom.one(layoutDropdown, 'button').textContent = t(labelKeyFor(curView));
|
|
1121
|
+
|
|
1122
|
+
var btnGroup = wrapper.appendChild(dom.element('div', { 'class': 'btn-group pull-right' }));
|
|
1004
1123
|
|
|
1005
|
-
var btnGroup = $('<div class="btn-group pull-right"/>')
|
|
1006
|
-
.appendTo(wrapper)
|
|
1007
|
-
;
|
|
1008
1124
|
if (settings.edit_source) {
|
|
1009
1125
|
// Built again by setLocale, maybe with the source open
|
|
1010
|
-
var htmlButton =
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1126
|
+
var htmlButton = dom.create('<button type="button" class="btn btn-sm btn-primary gm-edit-mode"><i class="bi bi-code-slash"></i></button>');
|
|
1127
|
+
htmlButton.setAttribute('title', t('tool.edit_source'));
|
|
1128
|
+
dom.toggleClass(htmlButton, 'active btn-danger', sourceOpen);
|
|
1129
|
+
htmlButton.addEventListener('click', function() {
|
|
1130
|
+
if (sourceOpen) {
|
|
1131
|
+
closeSource();
|
|
1132
|
+
} else {
|
|
1133
|
+
openSource();
|
|
1134
|
+
}
|
|
1019
1135
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
;
|
|
1136
|
+
dom.toggleClass(htmlButton, 'active btn-danger', sourceOpen);
|
|
1137
|
+
});
|
|
1138
|
+
btnGroup.appendChild(htmlButton);
|
|
1024
1139
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
;
|
|
1140
|
+
|
|
1141
|
+
var previewButton = dom.create('<button type="button" class="btn btn-sm btn-primary gm-preview"><i class="bi bi-eye-fill"></i></button>');
|
|
1142
|
+
var endPreview = function() {
|
|
1143
|
+
if (!dom.hasClass(previewButton, 'active')) {
|
|
1144
|
+
dom.addClass(canvas, 'ge-editing');
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
previewButton.setAttribute('title', t('tool.preview'));
|
|
1148
|
+
previewButton.addEventListener('mouseenter', function() {
|
|
1149
|
+
dom.removeClass(canvas, 'ge-editing');
|
|
1150
|
+
});
|
|
1151
|
+
previewButton.addEventListener('click', function() {
|
|
1152
|
+
dom.toggleClass(previewButton, 'active btn-danger');
|
|
1153
|
+
endPreview();
|
|
1154
|
+
});
|
|
1155
|
+
previewButton.addEventListener('mouseleave', endPreview);
|
|
1156
|
+
btnGroup.appendChild(previewButton);
|
|
1040
1157
|
|
|
1041
1158
|
// Floated right after the source and preview buttons, so it
|
|
1042
1159
|
// stands to their left. Not a btn-group: its buttons show one at
|
|
1043
1160
|
// a time, and a hidden one still counts as a neighbour to
|
|
1044
1161
|
// Bootstrap, which squares off the corners they would share.
|
|
1045
1162
|
if (endItems.length) {
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
.appendTo(wrapper)
|
|
1049
|
-
;
|
|
1163
|
+
var end = wrapper.appendChild(dom.element('div', { 'class': 'pull-right ge-toolbar-end' }));
|
|
1164
|
+
endItems.forEach(function(button) { end.appendChild(button); });
|
|
1050
1165
|
}
|
|
1051
1166
|
|
|
1052
1167
|
makeToolbarDraggable();
|
|
@@ -1057,14 +1172,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1057
1172
|
* with its label as the title, or a plus and the label otherwise.
|
|
1058
1173
|
*/
|
|
1059
1174
|
function labelButton(button, label, iconClass) {
|
|
1060
|
-
button.
|
|
1175
|
+
button.setAttribute('title', label);
|
|
1061
1176
|
|
|
1062
|
-
if (iconClass) {
|
|
1177
|
+
if (iconClass) {
|
|
1178
|
+
button.appendChild(dom.element('i', { 'class': iconClass }));
|
|
1179
|
+
return button;
|
|
1180
|
+
}
|
|
1063
1181
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
;
|
|
1182
|
+
button.appendChild(dom.create('<i class="bi bi-plus"></i>'));
|
|
1183
|
+
button.appendChild(dom.element('span', {}, label));
|
|
1184
|
+
return button;
|
|
1068
1185
|
}
|
|
1069
1186
|
|
|
1070
1187
|
/** A feature plugin's toolbar button. At the end it is always an icon, `bi bi-plus` if it has none of its own. */
|
|
@@ -1073,31 +1190,33 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1073
1190
|
// A label of its own, worked out when the toolbar is built - and
|
|
1074
1191
|
// built again by setLocale - or the string its labelKey names
|
|
1075
1192
|
var label = typeof item.label === 'function' ? item.label() : (item.label || t(item.labelKey));
|
|
1076
|
-
var button = labelButton(
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1193
|
+
var button = labelButton(dom.element('a', { 'class': 'btn btn-sm btn-primary ge-add-container ge-add-feature' }), label, iconClass);
|
|
1194
|
+
|
|
1195
|
+
dom.addClass(button, item.className || '');
|
|
1196
|
+
dom.attr(button, {
|
|
1197
|
+
'data-ge-toolbar': 'feature',
|
|
1198
|
+
'data-ge-feature': name,
|
|
1199
|
+
'data-ge-item': index,
|
|
1200
|
+
});
|
|
1201
|
+
button.addEventListener('click', function() {
|
|
1202
|
+
var made = item.create();
|
|
1203
|
+
|
|
1204
|
+
// One that belongs in a column brings a row and a column
|
|
1205
|
+
// of its own, the way a container does
|
|
1206
|
+
var placed = item.inColumn ? inRowOfItsOwn(made) : made;
|
|
1207
|
+
|
|
1208
|
+
var added = addNode(item.kind, made, function() {
|
|
1209
|
+
canvas.appendChild(placed);
|
|
1210
|
+
}, { parent: canvas, source: item.source || 'tool' });
|
|
1211
|
+
|
|
1212
|
+
if (added && item.inColumn && placed.scrollIntoView) {
|
|
1213
|
+
placed.scrollIntoView({behavior: 'smooth'});
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1097
1216
|
|
|
1098
1217
|
return button;
|
|
1099
1218
|
}
|
|
1100
|
-
|
|
1219
|
+
|
|
1101
1220
|
/**
|
|
1102
1221
|
* The toolbar's buttons as a palette: drag one onto the canvas and
|
|
1103
1222
|
* what it makes is created where it lands, rather than at the end.
|
|
@@ -1113,14 +1232,19 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1113
1232
|
}
|
|
1114
1233
|
|
|
1115
1234
|
function makeToolbarDraggable() {
|
|
1116
|
-
var buttons =
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1235
|
+
var buttons = dom.all(mainControls, '[data-ge-toolbar]');
|
|
1236
|
+
|
|
1237
|
+
buttons.forEach(function(button) {
|
|
1238
|
+
dom.removeClass(button, 'ge-palette-button');
|
|
1239
|
+
button.removeEventListener('pointerdown', startToolbarDrag);
|
|
1240
|
+
});
|
|
1120
1241
|
|
|
1121
1242
|
if (!toolbarDrags()) { return; }
|
|
1122
1243
|
|
|
1123
|
-
buttons.
|
|
1244
|
+
buttons.forEach(function(button) {
|
|
1245
|
+
dom.addClass(button, 'ge-palette-button');
|
|
1246
|
+
button.addEventListener('pointerdown', startToolbarDrag);
|
|
1247
|
+
});
|
|
1124
1248
|
}
|
|
1125
1249
|
|
|
1126
1250
|
/**
|
|
@@ -1132,7 +1256,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1132
1256
|
* also what keeps the add column tool's hold-to-pick working.
|
|
1133
1257
|
*/
|
|
1134
1258
|
function startToolbarDrag(e) {
|
|
1135
|
-
var button =
|
|
1259
|
+
var button = e.currentTarget;
|
|
1136
1260
|
var startX = e.pageX;
|
|
1137
1261
|
var startY = e.pageY;
|
|
1138
1262
|
var helper = null;
|
|
@@ -1148,35 +1272,37 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1148
1272
|
if (!helper) {
|
|
1149
1273
|
if (!far(move)) { return; }
|
|
1150
1274
|
|
|
1151
|
-
helper = button.
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
;
|
|
1155
|
-
canvas.addClass('ge-dropping');
|
|
1275
|
+
helper = dom.addClass(button.cloneNode(true), 'ge-toolbar-helper');
|
|
1276
|
+
document.body.appendChild(helper);
|
|
1277
|
+
dom.addClass(canvas, 'ge-dropping');
|
|
1156
1278
|
}
|
|
1157
1279
|
|
|
1158
|
-
|
|
1280
|
+
dom.css(helper, { left: move.pageX - 14, top: move.pageY - 14 });
|
|
1159
1281
|
showDropMarker(move.pageX, move.pageY);
|
|
1160
1282
|
}
|
|
1161
1283
|
|
|
1162
1284
|
function onUp(up) {
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
.off('pointerup.ge-toolbar pointercancel.ge-toolbar', onUp)
|
|
1166
|
-
;
|
|
1285
|
+
document.removeEventListener('pointermove', onMove);
|
|
1286
|
+
dom.off(document, 'pointerup pointercancel', onUp);
|
|
1167
1287
|
|
|
1168
1288
|
if (!helper) { return; }
|
|
1169
1289
|
|
|
1170
1290
|
helper.remove();
|
|
1171
|
-
|
|
1291
|
+
dom.removeClass(canvas, 'ge-dropping');
|
|
1172
1292
|
hideDropMarker();
|
|
1173
1293
|
|
|
1174
1294
|
// The click that follows a drag would add the block a second
|
|
1175
|
-
// time, at the end of the canvas
|
|
1176
|
-
button
|
|
1295
|
+
// time, at the end of the canvas. Caught on the way down, so
|
|
1296
|
+
// it never reaches the button's own handler.
|
|
1297
|
+
var swallow = function(click) {
|
|
1298
|
+
if (click.target !== button && !button.contains(click.target)) { return; }
|
|
1177
1299
|
click.preventDefault();
|
|
1178
1300
|
click.stopImmediatePropagation();
|
|
1179
|
-
}
|
|
1301
|
+
};
|
|
1302
|
+
window.addEventListener('click', swallow, { capture: true, once: true });
|
|
1303
|
+
// A drag the browser does not follow with a click leaves
|
|
1304
|
+
// nothing to swallow: the next click is a click
|
|
1305
|
+
window.setTimeout(function() { window.removeEventListener('click', swallow, { capture: true }); }, 0);
|
|
1180
1306
|
|
|
1181
1307
|
var where = dropPlaceAt(up.pageX, up.pageY);
|
|
1182
1308
|
if (where) { insertFromToolbar(button, where); }
|
|
@@ -1185,10 +1311,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1185
1311
|
// On the document, not on the button: until the gesture is far
|
|
1186
1312
|
// enough along to be a drag there is nothing to capture the
|
|
1187
1313
|
// pointer with, and the pointer has left the button by then
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
.on('pointerup.ge-toolbar pointercancel.ge-toolbar', onUp)
|
|
1191
|
-
;
|
|
1314
|
+
document.addEventListener('pointermove', onMove);
|
|
1315
|
+
dom.on(document, 'pointerup pointercancel', onUp);
|
|
1192
1316
|
}
|
|
1193
1317
|
|
|
1194
1318
|
/**
|
|
@@ -1208,18 +1332,18 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1208
1332
|
|
|
1209
1333
|
if (!under) { return null; }
|
|
1210
1334
|
|
|
1211
|
-
var region =
|
|
1212
|
-
if (!region
|
|
1335
|
+
var region = dom.closest(under, ['.column', '.ge-canvas'].concat(pluginHooks('regions')).join(', '));
|
|
1336
|
+
if (!region || (region !== canvas && !canvas.contains(region))) {
|
|
1213
1337
|
return null;
|
|
1214
1338
|
}
|
|
1215
1339
|
|
|
1216
1340
|
var before = null;
|
|
1217
1341
|
|
|
1218
|
-
|
|
1342
|
+
dom.children(region, blockSelector()).forEach(function(block) {
|
|
1219
1343
|
if (before) { return; }
|
|
1220
1344
|
|
|
1221
|
-
var box =
|
|
1222
|
-
if (y < box.top + box.height / 2) { before =
|
|
1345
|
+
var box = block.getBoundingClientRect();
|
|
1346
|
+
if (y < box.top + box.height / 2) { before = block; }
|
|
1223
1347
|
});
|
|
1224
1348
|
|
|
1225
1349
|
return { region: region, before: before };
|
|
@@ -1231,25 +1355,25 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1231
1355
|
* to the canvas, just after the top level block the pointer was in.
|
|
1232
1356
|
*/
|
|
1233
1357
|
function insertFeatureFromToolbar(button, where) {
|
|
1234
|
-
var item = FEATURES[button.
|
|
1358
|
+
var item = FEATURES[button.getAttribute('data-ge-feature')].toolbar[parseInt(button.getAttribute('data-ge-item'), 10)];
|
|
1235
1359
|
var made = item.create();
|
|
1236
1360
|
var placed = made;
|
|
1237
1361
|
|
|
1238
1362
|
if (item.inColumn) {
|
|
1239
1363
|
// Where it lands in a column, or in a row and a column of its
|
|
1240
1364
|
// own anywhere else
|
|
1241
|
-
if (!where.region
|
|
1365
|
+
if (!dom.is(where.region, '.column')) { placed = inRowOfItsOwn(made); }
|
|
1242
1366
|
} else if (!acceptsBlock(where.region, made)) {
|
|
1243
|
-
var
|
|
1244
|
-
|
|
1245
|
-
|
|
1367
|
+
var ancestors = where.region === canvas ? [] : dom.parentsUntil(where.region, canvas).reverse().concat([where.region]);
|
|
1368
|
+
var top = ancestors[0] || null;
|
|
1369
|
+
where = { region: canvas, before: top ? top.nextElementSibling : null };
|
|
1246
1370
|
}
|
|
1247
1371
|
|
|
1248
1372
|
return addNode(item.kind, made, function() {
|
|
1249
1373
|
if (where.before) {
|
|
1250
|
-
|
|
1374
|
+
where.before.parentNode.insertBefore(placed, where.before);
|
|
1251
1375
|
} else {
|
|
1252
|
-
|
|
1376
|
+
where.region.appendChild(placed);
|
|
1253
1377
|
}
|
|
1254
1378
|
}, { parent: where.region, source: item.source || 'dragdrop' });
|
|
1255
1379
|
}
|
|
@@ -1257,7 +1381,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1257
1381
|
/** A detached row with one full width column holding `node`. */
|
|
1258
1382
|
function inRowOfItsOwn(node) {
|
|
1259
1383
|
var row = createRow();
|
|
1260
|
-
createColumn(MAX_COL_SIZE)
|
|
1384
|
+
row.appendChild(createColumn(MAX_COL_SIZE)).appendChild(node);
|
|
1261
1385
|
|
|
1262
1386
|
return row;
|
|
1263
1387
|
}
|
|
@@ -1268,12 +1392,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1268
1392
|
|
|
1269
1393
|
if (!where) { return hideDropMarker(); }
|
|
1270
1394
|
|
|
1271
|
-
if (!dropMarker) { dropMarker =
|
|
1395
|
+
if (!dropMarker) { dropMarker = dom.element('div', { 'class': 'ge-drop-marker' }); }
|
|
1272
1396
|
|
|
1273
1397
|
if (where.before) {
|
|
1274
|
-
|
|
1398
|
+
where.before.parentNode.insertBefore(dropMarker, where.before);
|
|
1275
1399
|
} else {
|
|
1276
|
-
|
|
1400
|
+
where.region.appendChild(dropMarker);
|
|
1277
1401
|
}
|
|
1278
1402
|
|
|
1279
1403
|
return undefined;
|
|
@@ -1288,26 +1412,26 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1288
1412
|
* the pointer left it.
|
|
1289
1413
|
*/
|
|
1290
1414
|
function insertFromToolbar(button, where) {
|
|
1291
|
-
if (button.
|
|
1415
|
+
if (button.getAttribute('data-ge-toolbar') === 'feature') {
|
|
1292
1416
|
return insertFeatureFromToolbar(button, where);
|
|
1293
1417
|
}
|
|
1294
1418
|
|
|
1295
|
-
var container = button.
|
|
1296
|
-
var type = button.
|
|
1419
|
+
var container = button.getAttribute('data-ge-toolbar') === 'container';
|
|
1420
|
+
var type = button.getAttribute('data-ge-container-type');
|
|
1297
1421
|
var made = container
|
|
1298
1422
|
? CONTAINERS[type].create({})
|
|
1299
|
-
: rowFromLayout(button.
|
|
1423
|
+
: rowFromLayout(button.getAttribute('data-ge-layout'));
|
|
1300
1424
|
|
|
1301
1425
|
// A container belongs in a column: dropped straight onto the
|
|
1302
1426
|
// canvas it brings a row and a column of its own
|
|
1303
1427
|
var placed = made;
|
|
1304
|
-
if (container && !where.region
|
|
1428
|
+
if (container && !dom.is(where.region, '.column')) { placed = inRowOfItsOwn(made); }
|
|
1305
1429
|
|
|
1306
1430
|
return addNode(container ? type : 'row', made, function() {
|
|
1307
1431
|
if (where.before) {
|
|
1308
|
-
|
|
1432
|
+
where.before.parentNode.insertBefore(placed, where.before);
|
|
1309
1433
|
} else {
|
|
1310
|
-
|
|
1434
|
+
where.region.appendChild(placed);
|
|
1311
1435
|
}
|
|
1312
1436
|
}, { parent: where.region, source: 'dragdrop' });
|
|
1313
1437
|
}
|
|
@@ -1369,16 +1493,17 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1369
1493
|
var row = createRow();
|
|
1370
1494
|
|
|
1371
1495
|
if (Array.isArray(layout)) {
|
|
1372
|
-
layout.forEach(function(size) { createColumn(size)
|
|
1496
|
+
layout.forEach(function(size) { row.appendChild(createColumn(size)); });
|
|
1373
1497
|
return row;
|
|
1374
1498
|
}
|
|
1375
1499
|
|
|
1376
|
-
|
|
1500
|
+
Object.keys(layout.row_cols || {}).forEach(function(key) {
|
|
1501
|
+
var value = layout.row_cols[key];
|
|
1377
1502
|
var tier = breakpoint(key);
|
|
1378
|
-
if (tier && ROW_COLS_VALUES.indexOf(String(value)) !== -1) {
|
|
1503
|
+
if (tier && ROW_COLS_VALUES.indexOf(String(value)) !== -1) { dom.addClass(row, rowColsClass(tier, value)); }
|
|
1379
1504
|
});
|
|
1380
1505
|
|
|
1381
|
-
for (var i = 0; i < (layout.columns || 0); i++) { createColumn(null)
|
|
1506
|
+
for (var i = 0; i < (layout.columns || 0); i++) { row.appendChild(createColumn(null)); }
|
|
1382
1507
|
|
|
1383
1508
|
return row;
|
|
1384
1509
|
}
|
|
@@ -1393,49 +1518,46 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1393
1518
|
/** The icon of a row-cols layout: one line of equal columns, as many as its widest count. */
|
|
1394
1519
|
function rowColsIcon(layout) {
|
|
1395
1520
|
var widest = 1;
|
|
1396
|
-
|
|
1521
|
+
Object.keys(layout.row_cols || {}).forEach(function(key) {
|
|
1522
|
+
var value = layout.row_cols[key];
|
|
1397
1523
|
if (value !== 'auto') { widest = Math.max(widest, parseInt(value, 10) || 1); }
|
|
1398
1524
|
});
|
|
1399
1525
|
|
|
1400
1526
|
return Array.apply(null, Array(Math.min(widest, layout.columns || widest))).map(function() { return 'equal'; });
|
|
1401
1527
|
}
|
|
1402
1528
|
|
|
1403
|
-
function onScroll(
|
|
1404
|
-
var
|
|
1405
|
-
|
|
1529
|
+
function onScroll() {
|
|
1530
|
+
var scrollTop = window.pageYOffset;
|
|
1531
|
+
|
|
1406
1532
|
if (
|
|
1407
|
-
|
|
1408
|
-
|
|
1533
|
+
scrollTop > dom.offset(mainControls).top &&
|
|
1534
|
+
scrollTop < dom.offset(canvas).top + dom.contentHeight(canvas)
|
|
1409
1535
|
) {
|
|
1410
|
-
if (
|
|
1411
|
-
wrapper
|
|
1412
|
-
.
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
.addClass('ge-fixed')
|
|
1418
|
-
;
|
|
1536
|
+
if (dom.hasClass(wrapper, 'ge-top')) {
|
|
1537
|
+
dom.css(wrapper, {
|
|
1538
|
+
left: dom.offset(wrapper).left,
|
|
1539
|
+
width: dom.outerWidth(wrapper),
|
|
1540
|
+
});
|
|
1541
|
+
dom.removeClass(wrapper, 'ge-top');
|
|
1542
|
+
dom.addClass(wrapper, 'ge-fixed');
|
|
1419
1543
|
}
|
|
1420
1544
|
} else {
|
|
1421
|
-
if (
|
|
1422
|
-
wrapper
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
.addClass('ge-top')
|
|
1426
|
-
;
|
|
1545
|
+
if (dom.hasClass(wrapper, 'ge-fixed')) {
|
|
1546
|
+
dom.css(wrapper, { left: '', width: '' });
|
|
1547
|
+
dom.removeClass(wrapper, 'ge-fixed');
|
|
1548
|
+
dom.addClass(wrapper, 'ge-top');
|
|
1427
1549
|
}
|
|
1428
1550
|
}
|
|
1429
1551
|
}
|
|
1430
|
-
|
|
1552
|
+
|
|
1431
1553
|
/**
|
|
1432
1554
|
* A click on the host's plain content makes it a text: of the one
|
|
1433
1555
|
* editor offered, or of the one chosen when there are several. What
|
|
1434
1556
|
* a click on a text does is its editor plugin's business.
|
|
1435
1557
|
*/
|
|
1436
1558
|
function onContentClick() {
|
|
1437
|
-
var block =
|
|
1438
|
-
if (block.
|
|
1559
|
+
var block = this;
|
|
1560
|
+
if (block.getAttribute('data-ge-content-type')) { return; }
|
|
1439
1561
|
|
|
1440
1562
|
// A second click, with the choice still open, withdraws it
|
|
1441
1563
|
if (closeSizePicker()) { return; }
|
|
@@ -1443,7 +1565,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1443
1565
|
// Content nobody can see - a tab that is not the open one, a
|
|
1444
1566
|
// closed accordion item - has no geometry for an editor to lay
|
|
1445
1567
|
// its toolbar out against, and nothing anyone can type into
|
|
1446
|
-
if (!
|
|
1568
|
+
if (!dom.visible(block)) { return; }
|
|
1447
1569
|
|
|
1448
1570
|
var offers = textOffers();
|
|
1449
1571
|
if (!offers.length) { return; }
|
|
@@ -1474,11 +1596,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1474
1596
|
|
|
1475
1597
|
if (!emit('before-convert', payload)) { return false; }
|
|
1476
1598
|
|
|
1477
|
-
|
|
1599
|
+
dom.addClass(block, 'ge-content-type-' + offer.type);
|
|
1600
|
+
block.setAttribute('data-ge-content-type', offer.type);
|
|
1478
1601
|
|
|
1479
1602
|
// Its plain drawer goes: the block is the plugin's now, and
|
|
1480
1603
|
// the plugin gives it the drawer a text has
|
|
1481
|
-
block.
|
|
1604
|
+
var textBlock = block.parentElement;
|
|
1605
|
+
if (dom.hasClass(textBlock, 'ge-text-block')) {
|
|
1606
|
+
dom.removeClass(textBlock, 'ge-plain-block');
|
|
1607
|
+
dom.children(textBlock, '.ge-tools-drawer').forEach(function(drawer) { drawer.remove(); });
|
|
1608
|
+
}
|
|
1482
1609
|
|
|
1483
1610
|
emit('after-convert', payload);
|
|
1484
1611
|
offer.edit(block);
|
|
@@ -1492,9 +1619,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1492
1619
|
* drawer, when there is more than one to choose from.
|
|
1493
1620
|
*/
|
|
1494
1621
|
function openConvertPicker(block, offers) {
|
|
1495
|
-
var textBlock = block.
|
|
1622
|
+
var textBlock = dom.hasClass(block.parentElement, 'ge-text-block') ? block.parentElement : null;
|
|
1623
|
+
if (!textBlock) { return; }
|
|
1496
1624
|
|
|
1497
|
-
openPicker(
|
|
1625
|
+
openPicker(dom.child(textBlock, '.ge-tools-drawer'), offers.map(function(offer) {
|
|
1498
1626
|
return {
|
|
1499
1627
|
label: offer.label,
|
|
1500
1628
|
title: t('tool.convert_type', { editor: offer.label }),
|
|
@@ -1511,31 +1639,37 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1511
1639
|
*/
|
|
1512
1640
|
function openPicker(anchor, choices, className, hover) {
|
|
1513
1641
|
closeSizePicker();
|
|
1642
|
+
if (!anchor) { return; }
|
|
1514
1643
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1644
|
+
var drawer = dom.closest(anchor, '.ge-tools-drawer');
|
|
1645
|
+
if (drawer) { dom.addClass(drawer, 'ge-picker-open'); }
|
|
1646
|
+
sizePicker = anchor.appendChild(dom.addClass(dom.element('div', { 'class': 'ge-size-picker' }), className || ''));
|
|
1517
1647
|
|
|
1518
1648
|
choices.forEach(function(choice) {
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
;
|
|
1649
|
+
var button = dom.attr(dom.element('a', { 'class': 'ge-size ge-size-flex' }), choice.attributes || {});
|
|
1650
|
+
|
|
1651
|
+
button.setAttribute('title', choice.title || choice.label);
|
|
1652
|
+
button.textContent = choice.label;
|
|
1653
|
+
button.addEventListener('click', function(e) {
|
|
1654
|
+
e.preventDefault();
|
|
1655
|
+
e.stopPropagation();
|
|
1656
|
+
|
|
1657
|
+
closeSizePicker();
|
|
1658
|
+
choice.choose();
|
|
1659
|
+
});
|
|
1660
|
+
sizePicker.appendChild(button);
|
|
1532
1661
|
});
|
|
1533
1662
|
|
|
1534
|
-
(hover || anchor)
|
|
1663
|
+
withdrawOnLeave(hover || anchor);
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
/** Leaving `node` withdraws the picker open under it, unless the pointer went into the picker. */
|
|
1667
|
+
function withdrawOnLeave(node) {
|
|
1668
|
+
node.addEventListener('mouseleave', function() {
|
|
1535
1669
|
window.setTimeout(function() {
|
|
1536
|
-
if (sizePicker && !sizePicker.
|
|
1670
|
+
if (sizePicker && !sizePicker.matches(':hover')) { closeSizePicker(); }
|
|
1537
1671
|
}, 400);
|
|
1538
|
-
});
|
|
1672
|
+
}, { once: true });
|
|
1539
1673
|
}
|
|
1540
1674
|
|
|
1541
1675
|
/**
|
|
@@ -1546,7 +1680,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1546
1680
|
var owners = {};
|
|
1547
1681
|
var entries = [];
|
|
1548
1682
|
|
|
1549
|
-
|
|
1683
|
+
Object.keys(FEATURES).forEach(function(name) {
|
|
1684
|
+
var feature = FEATURES[name];
|
|
1550
1685
|
if (!feature.textTypes) { return; }
|
|
1551
1686
|
|
|
1552
1687
|
(feature.textTypes() || []).forEach(function(entry) {
|
|
@@ -1590,34 +1725,38 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1590
1725
|
*/
|
|
1591
1726
|
function openSource() {
|
|
1592
1727
|
deinit();
|
|
1593
|
-
htmlTextArea
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
;
|
|
1598
|
-
canvas.hide();
|
|
1728
|
+
htmlTextArea.style.height = (0.8 * document.documentElement.clientHeight) + 'px';
|
|
1729
|
+
htmlTextArea.value = canvas.innerHTML;
|
|
1730
|
+
dom.show(htmlTextArea);
|
|
1731
|
+
dom.hide(canvas);
|
|
1599
1732
|
sourceOpen = true;
|
|
1600
1733
|
plugins('onSourceOpen', htmlTextArea);
|
|
1601
1734
|
}
|
|
1602
1735
|
|
|
1736
|
+
/**
|
|
1737
|
+
* The textarea's html back into the canvas. innerHTML, so a <script>
|
|
1738
|
+
* typed into the source is markup like any other and does not run in
|
|
1739
|
+
* the editor; the page it is published on runs it.
|
|
1740
|
+
*/
|
|
1603
1741
|
function closeSource() {
|
|
1604
1742
|
plugins('onSourceClose', htmlTextArea);
|
|
1605
1743
|
sourceOpen = false;
|
|
1606
|
-
|
|
1744
|
+
dom.setHtml(canvas, htmlTextArea.value);
|
|
1745
|
+
dom.show(canvas);
|
|
1607
1746
|
init();
|
|
1608
|
-
|
|
1747
|
+
dom.hide(htmlTextArea);
|
|
1609
1748
|
}
|
|
1610
1749
|
|
|
1611
1750
|
function init() {
|
|
1612
1751
|
// The node whose settings were open is gone - deleted, say - and
|
|
1613
1752
|
// its panel with it
|
|
1614
|
-
if (openSettingsState &&
|
|
1753
|
+
if (openSettingsState && !dom.attached(openSettingsState.node)) {
|
|
1615
1754
|
closeSettings();
|
|
1616
1755
|
}
|
|
1617
1756
|
|
|
1618
1757
|
runFilter(true);
|
|
1619
|
-
|
|
1620
|
-
|
|
1758
|
+
dom.addClass(canvas, 'ge-editing');
|
|
1759
|
+
dom.toggleClass(canvas, 'ge-drag-drawer', settings.drag_handle === 'drawer');
|
|
1621
1760
|
addAllColClasses();
|
|
1622
1761
|
var cutter = textCutter();
|
|
1623
1762
|
splitTexts(cutter);
|
|
@@ -1636,26 +1775,26 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1636
1775
|
function deinit() {
|
|
1637
1776
|
// Its panel goes home to its drawer first, and both go together
|
|
1638
1777
|
closeSettings();
|
|
1639
|
-
|
|
1778
|
+
dom.removeClass(canvas, 'ge-editing ge-drag-drawer ge-dropping');
|
|
1640
1779
|
// Before the drawers and the text blocks come off: an editor
|
|
1641
1780
|
// plugin closes its editors here, and finds them where it left them
|
|
1642
1781
|
plugins('onBeforeDeinit');
|
|
1643
1782
|
closeSizePicker();
|
|
1644
1783
|
hideDropMarker();
|
|
1645
|
-
|
|
1784
|
+
dom.all(canvas, '.ge-tools-drawer').forEach(function(drawer) { drawer.remove(); });
|
|
1646
1785
|
unwrapTexts();
|
|
1647
1786
|
plugins('onDeinit');
|
|
1648
1787
|
// After the rich text editors have let go of their content areas:
|
|
1649
1788
|
// one that rebuilt its area's DOM brought the preview styles back
|
|
1650
1789
|
// with it, and the attribute recording them came back too
|
|
1651
1790
|
clearPreviews(canvas);
|
|
1652
|
-
|
|
1791
|
+
dom.all(canvas, '[data-ge-row-cols]').forEach(function(row) { row.removeAttribute('data-ge-row-cols'); });
|
|
1653
1792
|
unmarkContainers();
|
|
1654
1793
|
removeSortable();
|
|
1655
1794
|
removeResizable();
|
|
1656
1795
|
runFilter(false);
|
|
1657
1796
|
}
|
|
1658
|
-
|
|
1797
|
+
|
|
1659
1798
|
/**
|
|
1660
1799
|
* The markup as a host would save it: no drawers, no editor, no
|
|
1661
1800
|
* sortables. The canvas goes back to editing afterwards.
|
|
@@ -1663,7 +1802,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1663
1802
|
function getHtml() {
|
|
1664
1803
|
deinit();
|
|
1665
1804
|
stripPixelWidths(canvas);
|
|
1666
|
-
var html = canvas.
|
|
1805
|
+
var html = canvas.innerHTML;
|
|
1667
1806
|
init();
|
|
1668
1807
|
return html;
|
|
1669
1808
|
}
|
|
@@ -1675,7 +1814,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1675
1814
|
function nodeHtml(node) {
|
|
1676
1815
|
deinit();
|
|
1677
1816
|
stripPixelWidths(node);
|
|
1678
|
-
var html = node
|
|
1817
|
+
var html = node.outerHTML;
|
|
1679
1818
|
init();
|
|
1680
1819
|
return html;
|
|
1681
1820
|
}
|
|
@@ -1685,6 +1824,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1685
1824
|
return plainHtml(getHtml());
|
|
1686
1825
|
}
|
|
1687
1826
|
|
|
1827
|
+
/**
|
|
1828
|
+
* Take the editor off the canvas: the markup stays, as getHtml would
|
|
1829
|
+
* give it, and everything the editor added - controls, panels,
|
|
1830
|
+
* listeners - goes. Safe on a canvas already taken out of the page,
|
|
1831
|
+
* as a framework tearing a component down does.
|
|
1832
|
+
*/
|
|
1688
1833
|
function destroy() {
|
|
1689
1834
|
// The html being edited is what the canvas is left with
|
|
1690
1835
|
if (sourceOpen) { closeSource(); }
|
|
@@ -1693,43 +1838,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1693
1838
|
removeSettingsPanels();
|
|
1694
1839
|
mainControls.remove();
|
|
1695
1840
|
htmlTextArea.remove();
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
canvas.removeData('grideditor');
|
|
1841
|
+
lifetime.abort();
|
|
1842
|
+
instances.delete(canvas);
|
|
1843
|
+
destroyed = true;
|
|
1700
1844
|
}
|
|
1701
1845
|
|
|
1702
|
-
function deprecatedRemove() {
|
|
1703
|
-
warnOnceHere('remove', 'remove() is deprecated and will be removed in a later ' +
|
|
1704
|
-
'release. Use destroy(), which does the same thing.');
|
|
1705
|
-
destroy();
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
/** The elements of one content area: its marked children, or all of them. */
|
|
1710
|
-
|
|
1711
|
-
/**
|
|
1712
|
-
* Give every element its class, its drawer and, while editing, the
|
|
1713
|
-
* contenteditable="false" that makes a rich text editor treat it as
|
|
1714
|
-
* one atomic thing rather than as text it may rewrite.
|
|
1715
|
-
*
|
|
1716
|
-
* The class is re-applied on every init rather than trusted to
|
|
1717
|
-
* survive: an editor that snapshots and restores the markup inside a
|
|
1718
|
-
* content area can drop it, and the marking that identifies an
|
|
1719
|
-
* element lives in a data attribute for exactly that reason.
|
|
1720
|
-
*/
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
/**
|
|
1725
|
-
* What the info tool calls this element: its label, its type, or both.
|
|
1726
|
-
* An element found by elements.auto has neither, so it is named after
|
|
1727
|
-
* its tag, which is the only thing it has said about itself.
|
|
1728
|
-
*/
|
|
1729
|
-
|
|
1730
1846
|
/**
|
|
1731
|
-
* The
|
|
1732
|
-
* the
|
|
1847
|
+
* The plugins this editor is using: the ones registered by the files
|
|
1848
|
+
* the page loaded, narrowed by the plugins setting.
|
|
1733
1849
|
*
|
|
1734
1850
|
* Each is a factory, called once here with the handle it works
|
|
1735
1851
|
* through. Everything a plugin needs from the editor goes through
|
|
@@ -1752,33 +1868,28 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1752
1868
|
return factory.always === true || wanted(name);
|
|
1753
1869
|
};
|
|
1754
1870
|
|
|
1755
|
-
|
|
1756
|
-
if (wanted(type)) { CONTAINERS[type] =
|
|
1871
|
+
Object.keys(GridEditor.containers).forEach(function(type) {
|
|
1872
|
+
if (wanted(type)) { CONTAINERS[type] = GridEditor.containers[type](api); }
|
|
1757
1873
|
});
|
|
1758
1874
|
|
|
1759
|
-
|
|
1875
|
+
Object.keys(GridEditor.features).forEach(function(name) {
|
|
1876
|
+
var factory = GridEditor.features[name];
|
|
1760
1877
|
if (featureWanted(name, factory)) { FEATURES[name] = factory(api); }
|
|
1761
1878
|
});
|
|
1762
1879
|
|
|
1763
|
-
|
|
1764
|
-
// own is a plugin of its own since 6.0
|
|
1765
|
-
if (!$.isEmptyObject($.fn.gridEditor.RTEs || {})) {
|
|
1766
|
-
warnOnceHere('rtes', '$.fn.gridEditor.RTEs was removed in 6.0 and what is registered there ' +
|
|
1767
|
-
'is ignored: write the editor as a plugin, see docs/plugins.md');
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
|
-
$.each($.fn.gridEditor.utilities, function(name, factory) {
|
|
1880
|
+
Object.keys(GridEditor.utilities).forEach(function(name) {
|
|
1771
1881
|
if (!wanted(name)) { return; }
|
|
1772
1882
|
|
|
1773
|
-
UTILITIES[name] =
|
|
1883
|
+
UTILITIES[name] = GridEditor.utilities[name](api);
|
|
1774
1884
|
(UTILITIES[name].families || []).forEach(function(family) {
|
|
1775
1885
|
registerFamily(name, UTILITIES[name], family);
|
|
1776
1886
|
});
|
|
1777
1887
|
});
|
|
1778
1888
|
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1889
|
+
Object.keys(FEATURES).forEach(function(name) {
|
|
1890
|
+
var methods = FEATURES[name].methods || {};
|
|
1891
|
+
Object.keys(methods).forEach(function(method) {
|
|
1892
|
+
featureMethods[method] = methods[method];
|
|
1782
1893
|
});
|
|
1783
1894
|
});
|
|
1784
1895
|
|
|
@@ -1797,14 +1908,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1797
1908
|
* nodes the other two may have just made.
|
|
1798
1909
|
*/
|
|
1799
1910
|
function plugins(hook, argument) {
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
if (feature[hook]) { feature[hook](argument); }
|
|
1805
|
-
});
|
|
1806
|
-
$.each(UTILITIES, function(name, utility) {
|
|
1807
|
-
if (utility[hook]) { utility[hook](argument); }
|
|
1911
|
+
[CONTAINERS, FEATURES, UTILITIES].forEach(function(registry) {
|
|
1912
|
+
Object.keys(registry).forEach(function(name) {
|
|
1913
|
+
if (registry[name][hook]) { registry[name][hook](argument); }
|
|
1914
|
+
});
|
|
1808
1915
|
});
|
|
1809
1916
|
}
|
|
1810
1917
|
|
|
@@ -1845,7 +1952,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1845
1952
|
nodeHtml: nodeHtml,
|
|
1846
1953
|
// A text editor has rewritten a content area, so whatever the
|
|
1847
1954
|
// editor and its plugins had put in there goes back in
|
|
1848
|
-
textReady:
|
|
1955
|
+
textReady: textReady,
|
|
1849
1956
|
// A choice under a tool, offered by holding it
|
|
1850
1957
|
attachPicker: attachPicker,
|
|
1851
1958
|
openPicker: openPicker,
|
|
@@ -1854,19 +1961,24 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1854
1961
|
detailsOf: detailsOf,
|
|
1855
1962
|
// A node's drawer: its first child, or for a content area the
|
|
1856
1963
|
// one beside it in its text block
|
|
1857
|
-
drawerOf:
|
|
1858
|
-
return node.hasClass('ge-content')
|
|
1859
|
-
? node.parent('.ge-text-block').children('.ge-tools-drawer')
|
|
1860
|
-
: node.children('.ge-tools-drawer');
|
|
1861
|
-
},
|
|
1964
|
+
drawerOf: drawerOf,
|
|
1862
1965
|
toolbarItems: function(name) {
|
|
1863
1966
|
return mainControls
|
|
1864
|
-
?
|
|
1865
|
-
:
|
|
1967
|
+
? dom.all(mainControls, '[data-ge-toolbar="feature"][data-ge-feature="' + name + '"]')
|
|
1968
|
+
: [];
|
|
1866
1969
|
},
|
|
1867
1970
|
};
|
|
1868
1971
|
}
|
|
1869
1972
|
|
|
1973
|
+
function drawerOf(node) {
|
|
1974
|
+
if (dom.hasClass(node, 'ge-content')) {
|
|
1975
|
+
var textBlock = node.parentElement;
|
|
1976
|
+
return dom.hasClass(textBlock, 'ge-text-block') ? dom.child(textBlock, '.ge-tools-drawer') : null;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
return dom.child(node, '.ge-tools-drawer');
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1870
1982
|
/* --------------------------------------------------------------
|
|
1871
1983
|
* Utilities: Bootstrap's responsive utility classes.
|
|
1872
1984
|
*
|
|
@@ -1900,7 +2012,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1900
2012
|
|
|
1901
2013
|
FAMILIES[name] = {
|
|
1902
2014
|
plugin: pluginName,
|
|
1903
|
-
family:
|
|
2015
|
+
family: Object.assign({}, family, {
|
|
1904
2016
|
name: name,
|
|
1905
2017
|
values: family.values.map(String),
|
|
1906
2018
|
appliesTo: family.appliesTo || utility.appliesTo || ['row', 'column'],
|
|
@@ -1932,8 +2044,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1932
2044
|
}
|
|
1933
2045
|
|
|
1934
2046
|
function familiesFor(kind) {
|
|
1935
|
-
return
|
|
1936
|
-
return
|
|
2047
|
+
return Object.keys(FAMILIES).map(function(name) {
|
|
2048
|
+
return FAMILIES[name].family;
|
|
2049
|
+
}).filter(function(family) {
|
|
2050
|
+
return appliesTo(family, kind);
|
|
1937
2051
|
});
|
|
1938
2052
|
}
|
|
1939
2053
|
|
|
@@ -1945,7 +2059,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1945
2059
|
|
|
1946
2060
|
/** The value a node carries a class for at exactly this tier, or null. */
|
|
1947
2061
|
function ownUtility(node, family, tier) {
|
|
1948
|
-
var classes = (node.
|
|
2062
|
+
var classes = (node.getAttribute('class') || '').split(/\s+/);
|
|
1949
2063
|
|
|
1950
2064
|
for (var i = 0; i < family.values.length; i++) {
|
|
1951
2065
|
if (classes.indexOf(utilityClass(family, tier, family.values[i])) !== -1) {
|
|
@@ -1988,11 +2102,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1988
2102
|
|
|
1989
2103
|
function writeUtility(node, family, tier, value) {
|
|
1990
2104
|
family.values.forEach(function(candidate) {
|
|
1991
|
-
|
|
2105
|
+
dom.removeClass(node, utilityClass(family, tier, candidate));
|
|
1992
2106
|
});
|
|
1993
2107
|
|
|
1994
|
-
if (value !== null) {
|
|
1995
|
-
|
|
2108
|
+
if (value !== null) { dom.addClass(node, utilityClass(family, tier, value)); }
|
|
2109
|
+
dom.dropEmptyClass(node);
|
|
1996
2110
|
}
|
|
1997
2111
|
|
|
1998
2112
|
/**
|
|
@@ -2040,10 +2154,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2040
2154
|
|
|
2041
2155
|
/** getUtility(node, family, view?): the value that applies, or null. */
|
|
2042
2156
|
function getUtility(node, name, view) {
|
|
2043
|
-
node =
|
|
2157
|
+
node = nodeFrom(node);
|
|
2044
2158
|
|
|
2045
2159
|
var family = familyNamed(name, 'getUtility');
|
|
2046
|
-
if (!family || !node
|
|
2160
|
+
if (!family || !node) { return null; }
|
|
2047
2161
|
|
|
2048
2162
|
var key = view === undefined ? curView : viewKey(view);
|
|
2049
2163
|
if (key === null) {
|
|
@@ -2062,10 +2176,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2062
2176
|
*/
|
|
2063
2177
|
function setUtility(node, name, value, options) {
|
|
2064
2178
|
options = typeof options == 'string' ? { view: options } : (options || {});
|
|
2065
|
-
node =
|
|
2179
|
+
node = nodeFrom(node);
|
|
2066
2180
|
|
|
2067
2181
|
var family = familyNamed(name, 'setUtility');
|
|
2068
|
-
if (!family || !node
|
|
2182
|
+
if (!family || !node) { return false; }
|
|
2069
2183
|
|
|
2070
2184
|
var view = options.view === undefined ? curView : viewKey(options.view);
|
|
2071
2185
|
if (view === null) {
|
|
@@ -2130,15 +2244,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2130
2244
|
*/
|
|
2131
2245
|
function bareStyle(node, name, property) {
|
|
2132
2246
|
var family = familyNamed(name, 'bareStyle');
|
|
2133
|
-
node =
|
|
2134
|
-
if (!family || !node
|
|
2247
|
+
node = nodeFrom(node);
|
|
2248
|
+
if (!family || !node) { return null; }
|
|
2135
2249
|
|
|
2136
|
-
var original = node.
|
|
2250
|
+
var original = node.getAttribute('class');
|
|
2137
2251
|
BREAKPOINTS.forEach(function(tier) { writeUtility(node, family, tier, null); });
|
|
2138
2252
|
|
|
2139
|
-
var value = getComputedStyle(node
|
|
2253
|
+
var value = getComputedStyle(node).getPropertyValue(property);
|
|
2140
2254
|
|
|
2141
|
-
if (original ===
|
|
2255
|
+
if (original === null) { node.removeAttribute('class'); } else { node.setAttribute('class', original); }
|
|
2142
2256
|
|
|
2143
2257
|
return value;
|
|
2144
2258
|
}
|
|
@@ -2147,15 +2261,18 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2147
2261
|
function refreshUtilities(node) {
|
|
2148
2262
|
var details = detailsOf(node);
|
|
2149
2263
|
|
|
2150
|
-
details
|
|
2151
|
-
|
|
2264
|
+
if (details) {
|
|
2265
|
+
var classes = dom.one(details, '.ge-classes');
|
|
2266
|
+
if (classes) { classes.value = hostClasses(node).join(' '); }
|
|
2267
|
+
dom.children(details, '.ge-utilities').forEach(function(section) { renderUtilities(section); });
|
|
2268
|
+
}
|
|
2152
2269
|
refreshPreviews(node);
|
|
2153
2270
|
}
|
|
2154
2271
|
|
|
2155
2272
|
/* Preview */
|
|
2156
2273
|
|
|
2157
2274
|
function utilityNodes(scope) {
|
|
2158
|
-
return
|
|
2275
|
+
return dom.selfAndAll(scope, UTILITY_NODES);
|
|
2159
2276
|
}
|
|
2160
2277
|
|
|
2161
2278
|
/**
|
|
@@ -2181,57 +2298,58 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2181
2298
|
}
|
|
2182
2299
|
|
|
2183
2300
|
function previewTier(scope, tier) {
|
|
2184
|
-
utilityNodes(scope).
|
|
2185
|
-
var node = $(this);
|
|
2301
|
+
utilityNodes(scope).forEach(function(node) {
|
|
2186
2302
|
var kind = kindOf(node);
|
|
2187
2303
|
var styles = {};
|
|
2188
2304
|
|
|
2189
2305
|
familiesFor(kind).forEach(function(family) {
|
|
2190
2306
|
if (!family.preview || !utilityTiers(node, family).length) { return; }
|
|
2191
2307
|
|
|
2192
|
-
|
|
2308
|
+
Object.assign(styles, family.preview(effectiveUtility(node, family, tier), node, kind));
|
|
2193
2309
|
});
|
|
2194
2310
|
|
|
2195
|
-
if (kind === 'column') {
|
|
2311
|
+
if (kind === 'column') { Object.assign(styles, rowColsPreview(node, tier)); }
|
|
2196
2312
|
|
|
2197
2313
|
// A plugin whose families settle one property between them
|
|
2198
2314
|
// previews the node as a whole
|
|
2199
|
-
|
|
2200
|
-
|
|
2315
|
+
Object.keys(UTILITIES).forEach(function(name) {
|
|
2316
|
+
var utility = UTILITIES[name];
|
|
2317
|
+
if (utility.preview) { Object.assign(styles, utility.preview(node, kind, tier.key)); }
|
|
2201
2318
|
});
|
|
2202
2319
|
|
|
2203
|
-
if (
|
|
2320
|
+
if (Object.keys(styles).length) { applyPreview(node, styles); }
|
|
2204
2321
|
});
|
|
2205
2322
|
}
|
|
2206
2323
|
|
|
2207
2324
|
/**
|
|
2208
2325
|
* Set inline !important styles, which is the one thing that beats
|
|
2209
2326
|
* Bootstrap's own !important, and remember what each property was so
|
|
2210
|
-
* it can be put back. The record is an attribute
|
|
2211
|
-
*
|
|
2212
|
-
*
|
|
2327
|
+
* it can be put back. The record is an attribute because a rich text
|
|
2328
|
+
* editor rebuilds the DOM of the area it edits, and the record has to
|
|
2329
|
+
* come back with the node.
|
|
2213
2330
|
*/
|
|
2214
2331
|
function applyPreview(node, styles) {
|
|
2215
|
-
var style = node
|
|
2332
|
+
var style = node.style;
|
|
2216
2333
|
var was = {};
|
|
2217
2334
|
|
|
2218
|
-
|
|
2335
|
+
Object.keys(styles).forEach(function(property) {
|
|
2219
2336
|
was[property] = [style.getPropertyValue(property), style.getPropertyPriority(property)];
|
|
2220
|
-
style.setProperty(property, String(
|
|
2337
|
+
style.setProperty(property, String(styles[property]), 'important');
|
|
2221
2338
|
});
|
|
2222
2339
|
|
|
2223
|
-
node.
|
|
2340
|
+
node.setAttribute(PREVIEW_ATTR, JSON.stringify(was));
|
|
2224
2341
|
}
|
|
2225
2342
|
|
|
2226
2343
|
function clearPreviews(scope) {
|
|
2227
|
-
|
|
2228
|
-
var
|
|
2229
|
-
var style = this.style;
|
|
2344
|
+
dom.selfAndAll(scope, '[' + PREVIEW_ATTR + ']').forEach(function(node) {
|
|
2345
|
+
var style = node.style;
|
|
2230
2346
|
var was = {};
|
|
2231
2347
|
|
|
2232
|
-
try { was = JSON.parse(node.
|
|
2348
|
+
try { was = JSON.parse(node.getAttribute(PREVIEW_ATTR)) || {}; } catch (error) { /* a mangled record: drop it */ }
|
|
2349
|
+
|
|
2350
|
+
Object.keys(was).forEach(function(property) {
|
|
2351
|
+
var before = was[property];
|
|
2233
2352
|
|
|
2234
|
-
$.each(was, function(property, before) {
|
|
2235
2353
|
if (before && before[0]) {
|
|
2236
2354
|
style.setProperty(property, before[0], before[1]);
|
|
2237
2355
|
} else {
|
|
@@ -2239,8 +2357,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2239
2357
|
}
|
|
2240
2358
|
});
|
|
2241
2359
|
|
|
2242
|
-
node.
|
|
2243
|
-
|
|
2360
|
+
node.removeAttribute(PREVIEW_ATTR);
|
|
2361
|
+
dom.dropEmptyStyle(node);
|
|
2244
2362
|
});
|
|
2245
2363
|
}
|
|
2246
2364
|
|
|
@@ -2259,28 +2377,29 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2259
2377
|
.filter(function(family) { return family.panel !== false; })
|
|
2260
2378
|
.map(function(family) { return createField(node, family); });
|
|
2261
2379
|
|
|
2262
|
-
|
|
2380
|
+
Object.keys(UTILITIES).forEach(function(name) {
|
|
2381
|
+
var utility = UTILITIES[name];
|
|
2263
2382
|
var own = utility.panel ? utility.panel(node, kind) : null;
|
|
2264
|
-
if (own
|
|
2383
|
+
if (own) { fields.push(own); }
|
|
2265
2384
|
});
|
|
2266
2385
|
|
|
2267
2386
|
if (!fields.length) { return null; }
|
|
2268
2387
|
|
|
2269
|
-
var section =
|
|
2270
|
-
|
|
2271
|
-
.data('ge-node', node)
|
|
2272
|
-
;
|
|
2388
|
+
var section = dom.toggleClass(dom.element('div', { 'class': 'ge-utilities' }), 'ge-open', utilitiesOpen);
|
|
2389
|
+
sectionNodes.set(section, node);
|
|
2273
2390
|
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
.
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2391
|
+
var toggle = section.appendChild(dom.element('a', { 'class': 'ge-utilities-toggle' }));
|
|
2392
|
+
toggle.addEventListener('click', function() {
|
|
2393
|
+
utilitiesOpen = !dom.hasClass(section, 'ge-open');
|
|
2394
|
+
settingsScope().forEach(function(scope) {
|
|
2395
|
+
dom.all(scope, '.ge-utilities').forEach(function(each) {
|
|
2396
|
+
dom.toggleClass(each, 'ge-open', utilitiesOpen);
|
|
2397
|
+
});
|
|
2398
|
+
});
|
|
2399
|
+
});
|
|
2281
2400
|
|
|
2282
|
-
var body =
|
|
2283
|
-
fields.forEach(function(field) {
|
|
2401
|
+
var body = section.appendChild(dom.element('div', { 'class': 'ge-utilities-body' }));
|
|
2402
|
+
fields.forEach(function(field) { body.appendChild(field); });
|
|
2284
2403
|
|
|
2285
2404
|
renderUtilities(section);
|
|
2286
2405
|
|
|
@@ -2293,19 +2412,17 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2293
2412
|
* view or the node's classes change.
|
|
2294
2413
|
*/
|
|
2295
2414
|
function createField(node, family) {
|
|
2296
|
-
var field =
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
;
|
|
2302
|
-
|
|
2303
|
-
.
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
;
|
|
2308
|
-
$('<small class="ge-utility-note" />').appendTo(field);
|
|
2415
|
+
var field = dom.element('label', { 'class': 'ge-utility', 'data-ge-family': family.name });
|
|
2416
|
+
|
|
2417
|
+
field.appendChild(dom.element('span', { 'class': 'ge-utility-label' },
|
|
2418
|
+
family.labelKey ? t(family.labelKey) : family.name));
|
|
2419
|
+
|
|
2420
|
+
var select = field.appendChild(dom.element('select', { 'class': 'form-select form-select-sm' }));
|
|
2421
|
+
select.addEventListener('change', function() {
|
|
2422
|
+
setUtility(node, family.name, this.value, { source: 'panel' });
|
|
2423
|
+
});
|
|
2424
|
+
|
|
2425
|
+
field.appendChild(dom.element('small', { 'class': 'ge-utility-note' }));
|
|
2309
2426
|
|
|
2310
2427
|
return field;
|
|
2311
2428
|
}
|
|
@@ -2313,7 +2430,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2313
2430
|
/** ge.utilityField(node, family): a field a plugin places in a panel of its own. */
|
|
2314
2431
|
function utilityField(node, name) {
|
|
2315
2432
|
var family = familyNamed(name, 'utilityField');
|
|
2316
|
-
if (!family) { return
|
|
2433
|
+
if (!family) { return null; }
|
|
2317
2434
|
|
|
2318
2435
|
var field = createField(node, family);
|
|
2319
2436
|
renderField(field, node);
|
|
@@ -2323,20 +2440,23 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2323
2440
|
|
|
2324
2441
|
/** Fill a section's fields, the families' and the plugins' own, for the view being edited. */
|
|
2325
2442
|
function renderUtilities(section) {
|
|
2326
|
-
var node =
|
|
2443
|
+
var node = sectionNodes.get(section);
|
|
2327
2444
|
|
|
2328
|
-
|
|
2329
|
-
.
|
|
2445
|
+
dom.children(section, '.ge-utilities-toggle').forEach(function(toggle) {
|
|
2446
|
+
toggle.textContent = t('utility.section', { view: t(labelKeyFor(curView)) });
|
|
2447
|
+
});
|
|
2330
2448
|
|
|
2331
|
-
|
|
2449
|
+
dom.all(section, '.ge-utility').forEach(function(field) { renderField(field, node); });
|
|
2332
2450
|
}
|
|
2333
2451
|
|
|
2334
2452
|
function renderField(field, node) {
|
|
2335
|
-
var family = FAMILIES[field.
|
|
2336
|
-
var select =
|
|
2453
|
+
var family = FAMILIES[field.getAttribute('data-ge-family')].family;
|
|
2454
|
+
var select = dom.child(field, 'select');
|
|
2337
2455
|
var choices = family.choices ? family.choices(node, kindOf(node)) : family.values;
|
|
2338
2456
|
var own, blank, note = '';
|
|
2339
2457
|
|
|
2458
|
+
select.innerHTML = '';
|
|
2459
|
+
|
|
2340
2460
|
if (curView === ALL_VIEW) {
|
|
2341
2461
|
own = ownUtility(node, family, BREAKPOINTS[0]);
|
|
2342
2462
|
blank = t('utility.default');
|
|
@@ -2368,13 +2488,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2368
2488
|
// would not offer it here, rather than shown as something else
|
|
2369
2489
|
if (own !== null && choices.indexOf(own) === -1) { choices = choices.concat([own]); }
|
|
2370
2490
|
|
|
2371
|
-
|
|
2491
|
+
select.appendChild(dom.element('option', { value: '' }, blank));
|
|
2372
2492
|
choices.forEach(function(value) {
|
|
2373
|
-
|
|
2493
|
+
select.appendChild(dom.element('option', { value: value }, labelOf(family, value)));
|
|
2374
2494
|
});
|
|
2375
2495
|
|
|
2376
|
-
select.
|
|
2377
|
-
|
|
2496
|
+
select.value = own === null ? '' : own;
|
|
2497
|
+
|
|
2498
|
+
var noteNode = dom.child(field, '.ge-utility-note');
|
|
2499
|
+
noteNode.textContent = note;
|
|
2500
|
+
dom.toggle(noteNode, note !== '');
|
|
2378
2501
|
}
|
|
2379
2502
|
|
|
2380
2503
|
function labelOf(family, value) {
|
|
@@ -2401,9 +2524,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2401
2524
|
var containerCounter = 0;
|
|
2402
2525
|
|
|
2403
2526
|
/**
|
|
2404
|
-
* Ids go into the markup rather than into
|
|
2405
|
-
*
|
|
2406
|
-
*
|
|
2527
|
+
* Ids go into the markup rather than into memory: Bootstrap's toggles
|
|
2528
|
+
* are written in terms of them, and the markup has to survive getHtml
|
|
2529
|
+
* with those toggles still pointing at the right panes.
|
|
2407
2530
|
*/
|
|
2408
2531
|
function containerId(type) {
|
|
2409
2532
|
containerCounter++;
|
|
@@ -2415,17 +2538,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2415
2538
|
/** A pane's starting content: one full width column, ready to edit. */
|
|
2416
2539
|
function defaultRegion() {
|
|
2417
2540
|
var row = createRow();
|
|
2418
|
-
createColumn(MAX_COL_SIZE)
|
|
2541
|
+
row.appendChild(createColumn(MAX_COL_SIZE));
|
|
2419
2542
|
return row;
|
|
2420
2543
|
}
|
|
2421
2544
|
|
|
2422
2545
|
function containerTypeOf(container) {
|
|
2423
|
-
return container.
|
|
2546
|
+
return container ? container.getAttribute('data-ge-container') : null;
|
|
2424
2547
|
}
|
|
2425
2548
|
|
|
2426
2549
|
function markContainers() {
|
|
2427
|
-
|
|
2428
|
-
var container = $(this);
|
|
2550
|
+
dom.all(canvas, '[data-ge-container]').forEach(function(container) {
|
|
2429
2551
|
var type = containerTypeOf(container);
|
|
2430
2552
|
var definition = CONTAINERS[type];
|
|
2431
2553
|
|
|
@@ -2434,43 +2556,54 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2434
2556
|
return;
|
|
2435
2557
|
}
|
|
2436
2558
|
|
|
2437
|
-
|
|
2559
|
+
dom.addClass(container, 'ge-container ge-container-' + type);
|
|
2438
2560
|
definition.mark(container);
|
|
2439
2561
|
|
|
2440
|
-
if (!
|
|
2562
|
+
if (!dom.child(container, '.ge-tools-drawer')) {
|
|
2441
2563
|
createContainerControls(container, type, definition);
|
|
2442
2564
|
}
|
|
2443
2565
|
});
|
|
2444
2566
|
}
|
|
2445
2567
|
|
|
2446
2568
|
function unmarkContainers() {
|
|
2447
|
-
|
|
2448
|
-
var container = $(this);
|
|
2569
|
+
dom.all(canvas, '[data-ge-container]').forEach(function(container) {
|
|
2449
2570
|
var definition = CONTAINERS[containerTypeOf(container)];
|
|
2450
2571
|
|
|
2451
2572
|
if (definition) { definition.unmark(container); }
|
|
2452
2573
|
|
|
2453
|
-
|
|
2454
|
-
|
|
2574
|
+
dom.removeClass(container, 'ge-container ge-container-' + containerTypeOf(container));
|
|
2575
|
+
dom.dropEmptyClass(container);
|
|
2576
|
+
});
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
/** A new drawer as the first child of `node`. */
|
|
2580
|
+
function prependDrawer(node, className) {
|
|
2581
|
+
var drawer = dom.element('div', { 'class': className });
|
|
2582
|
+
node.insertBefore(drawer, node.firstChild);
|
|
2583
|
+
return drawer;
|
|
2584
|
+
}
|
|
2585
|
+
|
|
2586
|
+
/** The host's own tools, from a *_tools setting, in a drawer. */
|
|
2587
|
+
function hostTools(drawer, tools) {
|
|
2588
|
+
(tools || []).forEach(function(hostTool) {
|
|
2589
|
+
createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
2590
|
+
hostTool.iconClass || 'bi bi-wrench', hostTool.on);
|
|
2455
2591
|
});
|
|
2456
2592
|
}
|
|
2457
2593
|
|
|
2458
2594
|
function createContainerControls(container, type, definition) {
|
|
2459
|
-
var drawer =
|
|
2595
|
+
var drawer = prependDrawer(container, 'ge-tools-drawer ge-container-drawer');
|
|
2460
2596
|
|
|
2461
2597
|
createMoveTool(drawer);
|
|
2462
2598
|
addSettingsTool(drawer, container, settings.container_classes);
|
|
2463
2599
|
|
|
2464
|
-
settings.container_tools
|
|
2465
|
-
createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
2466
|
-
hostTool.iconClass || 'bi bi-wrench', hostTool.on);
|
|
2467
|
-
});
|
|
2600
|
+
hostTools(drawer, settings.container_tools);
|
|
2468
2601
|
|
|
2469
2602
|
if (definition.tools) { definition.tools(drawer, container); }
|
|
2470
2603
|
|
|
2471
2604
|
createTool(drawer, t('tool.delete_container'), 'ge-delete-container', 'bi bi-trash', function() {
|
|
2472
2605
|
deleteNode(type, container, t('confirm.delete_container'), function(removed) {
|
|
2473
|
-
|
|
2606
|
+
dom.slideUp(container, removed);
|
|
2474
2607
|
});
|
|
2475
2608
|
});
|
|
2476
2609
|
|
|
@@ -2492,16 +2625,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2492
2625
|
* A pane drawer: small, inline, and made the same way for every
|
|
2493
2626
|
* container type so a tab and an accordion item behave alike.
|
|
2494
2627
|
*/
|
|
2495
|
-
function createPaneControls(pane, kind,
|
|
2496
|
-
var drawer =
|
|
2628
|
+
function createPaneControls(pane, kind, tools, confirmText, remove) {
|
|
2629
|
+
var drawer = prependDrawer(pane, 'ge-tools-drawer ge-pane-drawer');
|
|
2497
2630
|
|
|
2498
2631
|
createMoveTool(drawer);
|
|
2499
2632
|
addSettingsTool(drawer, pane, settings.pane_classes);
|
|
2500
2633
|
|
|
2501
|
-
hostTools
|
|
2502
|
-
createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
2503
|
-
hostTool.iconClass || 'bi bi-wrench', hostTool.on);
|
|
2504
|
-
});
|
|
2634
|
+
hostTools(drawer, tools);
|
|
2505
2635
|
|
|
2506
2636
|
createTool(drawer, t('tool.delete_pane'), 'ge-delete-pane', 'bi bi-trash', function() {
|
|
2507
2637
|
deleteNode(kind, pane, confirmText, function(removed) {
|
|
@@ -2523,31 +2653,31 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2523
2653
|
* way out.
|
|
2524
2654
|
*/
|
|
2525
2655
|
function suspendToggles(scope) {
|
|
2526
|
-
scope
|
|
2527
|
-
.each(function() {
|
|
2528
|
-
var node = $(this);
|
|
2656
|
+
if (!scope) { return; }
|
|
2529
2657
|
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2658
|
+
dom.selfAndAll(scope, '[data-bs-toggle], [data-bs-dismiss]').forEach(function(node) {
|
|
2659
|
+
['toggle', 'dismiss'].forEach(function(name) {
|
|
2660
|
+
var value = node.getAttribute('data-bs-' + name);
|
|
2661
|
+
if (value === null) { return; }
|
|
2533
2662
|
|
|
2534
|
-
|
|
2535
|
-
|
|
2663
|
+
node.setAttribute('data-ge-bs-' + name, value);
|
|
2664
|
+
node.removeAttribute('data-bs-' + name);
|
|
2536
2665
|
});
|
|
2666
|
+
});
|
|
2537
2667
|
}
|
|
2538
2668
|
|
|
2539
2669
|
function resumeToggles(scope) {
|
|
2540
|
-
scope
|
|
2541
|
-
.each(function() {
|
|
2542
|
-
var node = $(this);
|
|
2670
|
+
if (!scope) { return; }
|
|
2543
2671
|
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2672
|
+
dom.selfAndAll(scope, '[data-ge-bs-toggle], [data-ge-bs-dismiss]').forEach(function(node) {
|
|
2673
|
+
['toggle', 'dismiss'].forEach(function(name) {
|
|
2674
|
+
var value = node.getAttribute('data-ge-bs-' + name);
|
|
2675
|
+
if (value === null) { return; }
|
|
2547
2676
|
|
|
2548
|
-
|
|
2549
|
-
|
|
2677
|
+
node.setAttribute('data-bs-' + name, value);
|
|
2678
|
+
node.removeAttribute('data-ge-bs-' + name);
|
|
2550
2679
|
});
|
|
2680
|
+
});
|
|
2551
2681
|
}
|
|
2552
2682
|
|
|
2553
2683
|
/**
|
|
@@ -2556,100 +2686,52 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2556
2686
|
* edited: typing in a tab's name must not switch tabs.
|
|
2557
2687
|
*/
|
|
2558
2688
|
function makeLabelEditable(label) {
|
|
2559
|
-
if (
|
|
2689
|
+
if (editableLabels.has(label)) { return; }
|
|
2560
2690
|
|
|
2561
|
-
var toggle =
|
|
2691
|
+
var toggle = dom.closest(label, '[data-bs-toggle], [data-ge-bs-toggle]');
|
|
2562
2692
|
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2693
|
+
editableLabels.add(label);
|
|
2694
|
+
label.setAttribute('title', t('tool.rename'));
|
|
2695
|
+
label.addEventListener('dblclick', function(e) {
|
|
2696
|
+
e.preventDefault();
|
|
2697
|
+
e.stopPropagation();
|
|
2568
2698
|
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2699
|
+
suspendToggles(toggle);
|
|
2700
|
+
label.setAttribute('contenteditable', 'true');
|
|
2701
|
+
label.focus();
|
|
2702
|
+
window.getSelection().selectAllChildren(label);
|
|
2703
|
+
});
|
|
2704
|
+
label.addEventListener('keydown', function(e) {
|
|
2705
|
+
if (label.getAttribute('contenteditable') !== 'true') { return; }
|
|
2575
2706
|
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
;
|
|
2707
|
+
if (e.key === 'Enter') {
|
|
2708
|
+
e.preventDefault();
|
|
2709
|
+
label.blur();
|
|
2710
|
+
}
|
|
2711
|
+
});
|
|
2712
|
+
label.addEventListener('blur', function() {
|
|
2713
|
+
label.removeAttribute('contenteditable');
|
|
2714
|
+
resumeToggles(toggle);
|
|
2715
|
+
});
|
|
2586
2716
|
}
|
|
2587
2717
|
|
|
2588
|
-
|
|
2589
|
-
/** Exactly one tab is the active one, in the strip and in the content. */
|
|
2590
|
-
|
|
2591
|
-
/**
|
|
2592
|
-
* An accordion whose items carry no data-bs-parent is one Bootstrap
|
|
2593
|
-
* lets you open several items in at once. The markup is the state:
|
|
2594
|
-
* there is nothing else to remember it in.
|
|
2595
|
-
*/
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
/**
|
|
2599
|
-
* An item dropped into another accordion collapses against the one it
|
|
2600
|
-
* landed in, and takes on that accordion's idea of whether several
|
|
2601
|
-
* items may be open at once.
|
|
2602
|
-
*/
|
|
2603
|
-
/**
|
|
2604
|
-
* Open or close an item while editing.
|
|
2605
|
-
*
|
|
2606
|
-
* The editor does this itself rather than letting Bootstrap's collapse
|
|
2607
|
-
* run over the canvas, and it writes what it does to data-ge-open, so
|
|
2608
|
-
* what is left open here is what the authored page opens with. An
|
|
2609
|
-
* accordion that closes its siblings - one without stay_open - closes
|
|
2610
|
-
* them here too, because the canvas is meant to look like the page.
|
|
2611
|
-
*/
|
|
2612
|
-
|
|
2613
|
-
/** One item's state, in the attribute and in Bootstrap's own classes. */
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
/**
|
|
2619
|
-
* A trigger is any node the host marked with data-ge-popup-target,
|
|
2620
|
-
* plus the button the container makes for itself. Ids go stale - a
|
|
2621
|
-
* popup deleted, a trigger pasted from another page - so what can be
|
|
2622
|
-
* repaired is repaired, and the rest is reported rather than removed.
|
|
2623
|
-
* Grid-editor never deletes a node the host wrote.
|
|
2624
|
-
*/
|
|
2625
|
-
|
|
2626
|
-
/**
|
|
2627
|
-
* On the way out, every trigger gets the attributes that make
|
|
2628
|
-
* Bootstrap open the modal in the authored page. An orphan gets
|
|
2629
|
-
* nothing, because there is nothing to point it at.
|
|
2630
|
-
*/
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
/**
|
|
2634
|
-
* What each container type is made of, and what has to happen to one
|
|
2635
|
-
* while it is being edited. Everything type specific lives here; the
|
|
2636
|
-
* core above treats them all the same.
|
|
2637
|
-
*/
|
|
2638
2718
|
/** The label inside a pane's button, wrapped so it can be edited alone. */
|
|
2639
2719
|
function labelIn(button) {
|
|
2640
|
-
var label =
|
|
2720
|
+
var label = dom.child(button, '.ge-pane-label');
|
|
2641
2721
|
|
|
2642
|
-
if (!label
|
|
2643
|
-
label =
|
|
2644
|
-
button.
|
|
2722
|
+
if (!label) {
|
|
2723
|
+
label = dom.element('span', { 'class': 'ge-pane-label' }, button.textContent.trim());
|
|
2724
|
+
button.innerHTML = '';
|
|
2725
|
+
button.appendChild(label);
|
|
2645
2726
|
}
|
|
2646
2727
|
|
|
2647
2728
|
return label;
|
|
2648
2729
|
}
|
|
2649
2730
|
|
|
2650
2731
|
function unwrapLabels(scope) {
|
|
2651
|
-
|
|
2652
|
-
|
|
2732
|
+
dom.all(scope, '.ge-pane-label').forEach(function(label) {
|
|
2733
|
+
editableLabels.delete(label);
|
|
2734
|
+
dom.unwrap(label);
|
|
2653
2735
|
});
|
|
2654
2736
|
}
|
|
2655
2737
|
|
|
@@ -2660,7 +2742,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2660
2742
|
var column = createColumn(size);
|
|
2661
2743
|
|
|
2662
2744
|
return addNode('column', column, function() {
|
|
2663
|
-
row.
|
|
2745
|
+
row.appendChild(column);
|
|
2664
2746
|
}, { parent: row, source: 'tool' });
|
|
2665
2747
|
}
|
|
2666
2748
|
|
|
@@ -2673,7 +2755,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2673
2755
|
* see is a gesture nobody finds.
|
|
2674
2756
|
*/
|
|
2675
2757
|
function attachSizePicker(tool, row) {
|
|
2676
|
-
if (!settings.add_column.picker) { return; }
|
|
2758
|
+
if (!settings.add_column.picker || !tool) { return; }
|
|
2677
2759
|
|
|
2678
2760
|
attachPicker(tool, function() { openSizePicker(tool, row); });
|
|
2679
2761
|
}
|
|
@@ -2690,7 +2772,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2690
2772
|
timer = null;
|
|
2691
2773
|
};
|
|
2692
2774
|
|
|
2693
|
-
|
|
2775
|
+
dom.on(tool, 'mouseenter mousedown', function() {
|
|
2694
2776
|
if (timer || sizePicker) { return; }
|
|
2695
2777
|
|
|
2696
2778
|
timer = window.setTimeout(function() {
|
|
@@ -2699,8 +2781,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2699
2781
|
}, settings.add_column.delay);
|
|
2700
2782
|
});
|
|
2701
2783
|
|
|
2702
|
-
|
|
2703
|
-
tool.on('mouseup', cancel);
|
|
2784
|
+
dom.on(tool, 'mouseleave mouseup', cancel);
|
|
2704
2785
|
}
|
|
2705
2786
|
|
|
2706
2787
|
/**
|
|
@@ -2716,37 +2797,34 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2716
2797
|
// The drawer it hangs off is raised while it is open: drawers sit
|
|
2717
2798
|
// below the resize handles, so without this the drawer of the
|
|
2718
2799
|
// column below takes the clicks meant for the picker
|
|
2719
|
-
|
|
2800
|
+
var drawer = dom.closest(tool, '.ge-tools-drawer');
|
|
2801
|
+
if (drawer) { dom.addClass(drawer, 'ge-picker-open'); }
|
|
2720
2802
|
|
|
2721
|
-
sizePicker =
|
|
2803
|
+
sizePicker = tool.appendChild(dom.element('div', { 'class': 'ge-size-picker' }));
|
|
2722
2804
|
|
|
2723
2805
|
settings.valid_col_sizes.forEach(function(size) {
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
;
|
|
2806
|
+
var choice = dom.element('a', {
|
|
2807
|
+
'class': 'ge-size',
|
|
2808
|
+
'data-ge-size': size,
|
|
2809
|
+
title: sizeTitle(size),
|
|
2810
|
+
}, isUnits(size) ? size : sizeClass(BREAKPOINTS[0], size));
|
|
2811
|
+
|
|
2812
|
+
dom.toggleClass(choice, 'ge-size-tight', isUnits(size) && size > room);
|
|
2813
|
+
dom.toggleClass(choice, 'ge-size-flex', !isUnits(size));
|
|
2814
|
+
choice.addEventListener('click', function(e) {
|
|
2815
|
+
e.preventDefault();
|
|
2816
|
+
e.stopPropagation();
|
|
2817
|
+
|
|
2818
|
+
closeSizePicker();
|
|
2819
|
+
addColumnTo(row, size);
|
|
2820
|
+
});
|
|
2821
|
+
sizePicker.appendChild(choice);
|
|
2739
2822
|
});
|
|
2740
2823
|
|
|
2741
2824
|
// Anywhere else, and the question is withdrawn
|
|
2742
|
-
tool
|
|
2743
|
-
window.setTimeout(function() {
|
|
2744
|
-
if (sizePicker && !sizePicker.is(':hover')) { closeSizePicker(); }
|
|
2745
|
-
}, 400);
|
|
2746
|
-
});
|
|
2825
|
+
withdrawOnLeave(tool);
|
|
2747
2826
|
}
|
|
2748
2827
|
|
|
2749
|
-
/** True when there was one to close, which is also a click's answer. */
|
|
2750
2828
|
function sizeTitle(size) {
|
|
2751
2829
|
if (size === 'equal') { return t('tool.column_equal'); }
|
|
2752
2830
|
if (size === 'auto') { return t('tool.column_auto'); }
|
|
@@ -2754,10 +2832,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2754
2832
|
return t('tool.column_size', { size: size });
|
|
2755
2833
|
}
|
|
2756
2834
|
|
|
2835
|
+
/** True when there was one to close, which is also a click's answer. */
|
|
2757
2836
|
function closeSizePicker() {
|
|
2758
2837
|
if (!sizePicker) { return false; }
|
|
2759
2838
|
|
|
2760
|
-
|
|
2839
|
+
var drawer = dom.closest(sizePicker, '.ge-tools-drawer');
|
|
2840
|
+
if (drawer) { dom.removeClass(drawer, 'ge-picker-open'); }
|
|
2761
2841
|
sizePicker.remove();
|
|
2762
2842
|
sizePicker = null;
|
|
2763
2843
|
|
|
@@ -2765,21 +2845,17 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2765
2845
|
}
|
|
2766
2846
|
|
|
2767
2847
|
function createRowControls() {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
if (row.find('> .ge-tools-drawer').length) { return; }
|
|
2848
|
+
dom.all(canvas, '.row').forEach(function(row) {
|
|
2849
|
+
if (dom.child(row, '.ge-tools-drawer')) { return; }
|
|
2771
2850
|
|
|
2772
|
-
var drawer =
|
|
2851
|
+
var drawer = prependDrawer(row, 'ge-tools-drawer');
|
|
2773
2852
|
createMoveTool(drawer);
|
|
2774
2853
|
addSettingsTool(drawer, row, settings.row_classes);
|
|
2775
2854
|
|
|
2776
|
-
settings.row_tools
|
|
2777
|
-
createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
2778
|
-
hostTool.iconClass || 'bi bi-wrench', hostTool.on);
|
|
2779
|
-
});
|
|
2855
|
+
hostTools(drawer, settings.row_tools);
|
|
2780
2856
|
createTool(drawer, t('tool.delete_row'), 'ge-delete-row', 'bi bi-trash', function() {
|
|
2781
2857
|
deleteNode('row', row, t('confirm.delete_row'), function(removed) {
|
|
2782
|
-
|
|
2858
|
+
dom.slideUp(row, removed);
|
|
2783
2859
|
});
|
|
2784
2860
|
});
|
|
2785
2861
|
createTool(drawer, t('tool.add_column'), 'ge-add-column', 'bi bi-plus-circle', function() {
|
|
@@ -2789,17 +2865,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2789
2865
|
addColumnTo(row, rowColsSource(row, leadingTier()) ? null : settings.add_column.size);
|
|
2790
2866
|
});
|
|
2791
2867
|
|
|
2792
|
-
attachSizePicker(
|
|
2868
|
+
attachSizePicker(dom.child(drawer, '.ge-add-column'), row);
|
|
2793
2869
|
|
|
2794
2870
|
});
|
|
2795
2871
|
}
|
|
2796
2872
|
|
|
2797
2873
|
function createColControls() {
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
if (col.find('> .ge-tools-drawer').length) { return; }
|
|
2874
|
+
dom.all(canvas, '.column').forEach(function(col) {
|
|
2875
|
+
if (dom.child(col, '.ge-tools-drawer')) { return; }
|
|
2801
2876
|
|
|
2802
|
-
var drawer =
|
|
2877
|
+
var drawer = prependDrawer(col, 'ge-tools-drawer');
|
|
2803
2878
|
|
|
2804
2879
|
createMoveTool(drawer);
|
|
2805
2880
|
|
|
@@ -2830,18 +2905,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2830
2905
|
|
|
2831
2906
|
addSettingsTool(drawer, col, settings.col_classes);
|
|
2832
2907
|
|
|
2833
|
-
settings.col_tools
|
|
2834
|
-
createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
2835
|
-
hostTool.iconClass || 'bi bi-wrench', hostTool.on);
|
|
2836
|
-
});
|
|
2908
|
+
hostTools(drawer, settings.col_tools);
|
|
2837
2909
|
|
|
2838
2910
|
createTool(drawer, t('tool.delete_column'), 'ge-delete-column', 'bi bi-trash', function() {
|
|
2839
2911
|
deleteNode('column', col, t('confirm.delete_column'), function(removed) {
|
|
2840
|
-
|
|
2841
|
-
opacity: 'hide',
|
|
2842
|
-
width: 'hide',
|
|
2843
|
-
height: 'hide'
|
|
2844
|
-
}, 400, removed);
|
|
2912
|
+
dom.shrinkAway(col, 400, removed, true);
|
|
2845
2913
|
});
|
|
2846
2914
|
});
|
|
2847
2915
|
|
|
@@ -2851,7 +2919,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2851
2919
|
var row = createRow();
|
|
2852
2920
|
|
|
2853
2921
|
addNode('row', row, function() {
|
|
2854
|
-
col.
|
|
2922
|
+
col.appendChild(row);
|
|
2855
2923
|
}, { parent: col, source: 'tool' });
|
|
2856
2924
|
});
|
|
2857
2925
|
|
|
@@ -2892,14 +2960,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2892
2960
|
var size = currentSize(col);
|
|
2893
2961
|
if (isUnits(size)) { return size; }
|
|
2894
2962
|
|
|
2895
|
-
var units = Math.round(
|
|
2963
|
+
var units = Math.round(dom.outerWidth(col) / rowContentWidth(col.parentElement) * MAX_COL_SIZE);
|
|
2896
2964
|
return Math.min(Math.max(units, 1), MAX_COL_SIZE);
|
|
2897
2965
|
}
|
|
2898
2966
|
|
|
2899
2967
|
function rowContentWidth(row) {
|
|
2900
|
-
var style = window.getComputedStyle(row
|
|
2968
|
+
var style = window.getComputedStyle(row);
|
|
2901
2969
|
|
|
2902
|
-
return row
|
|
2970
|
+
return row.clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
|
|
2903
2971
|
}
|
|
2904
2972
|
|
|
2905
2973
|
function currentOffset(col) {
|
|
@@ -2933,7 +3001,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2933
3001
|
* its own indent. What "hold shift for max" means.
|
|
2934
3002
|
*/
|
|
2935
3003
|
function widestFor(col) {
|
|
2936
|
-
var room = spare(col.
|
|
3004
|
+
var room = spare(col.parentElement, leadingTier(), col) - currentOffset(col);
|
|
2937
3005
|
|
|
2938
3006
|
return Math.min(largest(settings.valid_col_sizes), Math.max(room, 1));
|
|
2939
3007
|
}
|
|
@@ -2943,7 +3011,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2943
3011
|
* itself left inside the row.
|
|
2944
3012
|
*/
|
|
2945
3013
|
function deepestFor(col) {
|
|
2946
|
-
var room = spare(col.
|
|
3014
|
+
var room = spare(col.parentElement, leadingTier(), col) - currentUnits(col);
|
|
2947
3015
|
|
|
2948
3016
|
return Math.min(largest(settings.valid_col_offsets), Math.max(room, 0));
|
|
2949
3017
|
}
|
|
@@ -2953,29 +3021,34 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2953
3021
|
* a tool that only says "drag from here" is one tool too many.
|
|
2954
3022
|
*/
|
|
2955
3023
|
function createMoveTool(drawer) {
|
|
2956
|
-
if (settings.drag_handle === 'drawer') { return; }
|
|
3024
|
+
if (settings.drag_handle === 'drawer') { return null; }
|
|
2957
3025
|
|
|
2958
|
-
createTool(drawer, t('tool.move'), 'ge-move', 'bi bi-arrows-move');
|
|
3026
|
+
return createTool(drawer, t('tool.move'), 'ge-move', 'bi bi-arrows-move');
|
|
2959
3027
|
}
|
|
2960
3028
|
|
|
3029
|
+
/**
|
|
3030
|
+
* A tool in a drawer: a link with an icon, and what it does. The
|
|
3031
|
+
* handlers are a click handler, or { eventName: handler }; each gets
|
|
3032
|
+
* the DOM event, with `this` the tool. Hands back the tool.
|
|
3033
|
+
*/
|
|
2961
3034
|
function createTool(drawer, title, className, iconClass, eventHandlers) {
|
|
2962
|
-
// Through
|
|
2963
|
-
// and a quote in it - a type name, a host's own title -
|
|
2964
|
-
// end the attribute early
|
|
2965
|
-
var tool =
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
.appendTo(drawer)
|
|
2970
|
-
;
|
|
3035
|
+
// Through setAttribute rather than spliced into markup: a title is
|
|
3036
|
+
// text, and a quote in it - a type name, a host's own title -
|
|
3037
|
+
// would end the attribute early
|
|
3038
|
+
var tool = dom.element('a', { title: title, 'class': className });
|
|
3039
|
+
tool.appendChild(dom.element('i', { 'class': iconClass }));
|
|
3040
|
+
drawer.appendChild(tool);
|
|
3041
|
+
|
|
2971
3042
|
if (typeof eventHandlers == 'function') {
|
|
2972
|
-
tool.
|
|
3043
|
+
tool.addEventListener('click', eventHandlers);
|
|
2973
3044
|
}
|
|
2974
|
-
if (typeof eventHandlers == 'object') {
|
|
2975
|
-
|
|
2976
|
-
|
|
3045
|
+
if (eventHandlers && typeof eventHandlers == 'object') {
|
|
3046
|
+
Object.keys(eventHandlers).forEach(function(name) {
|
|
3047
|
+
dom.on(tool, name, eventHandlers[name]);
|
|
2977
3048
|
});
|
|
2978
3049
|
}
|
|
3050
|
+
|
|
3051
|
+
return tool;
|
|
2979
3052
|
}
|
|
2980
3053
|
|
|
2981
3054
|
/**
|
|
@@ -2984,7 +3057,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2984
3057
|
* and the only ones it is allowed to take away.
|
|
2985
3058
|
*/
|
|
2986
3059
|
function hostClasses(node) {
|
|
2987
|
-
return (node.
|
|
3060
|
+
return (node.getAttribute('class') || '').split(/\s+/).filter(function(name) {
|
|
2988
3061
|
return name !== '' && !isEditorClass(name);
|
|
2989
3062
|
});
|
|
2990
3063
|
}
|
|
@@ -3000,13 +3073,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3000
3073
|
}
|
|
3001
3074
|
|
|
3002
3075
|
function setHostClasses(node, value) {
|
|
3003
|
-
hostClasses(node).forEach(function(name) {
|
|
3076
|
+
hostClasses(node).forEach(function(name) { dom.removeClass(node, name); });
|
|
3004
3077
|
|
|
3005
3078
|
value.split(/\s+/).forEach(function(name) {
|
|
3006
|
-
if (name !== '') {
|
|
3079
|
+
if (name !== '') { dom.addClass(node, name); }
|
|
3007
3080
|
});
|
|
3008
3081
|
|
|
3009
|
-
|
|
3082
|
+
dom.dropEmptyClass(node);
|
|
3010
3083
|
}
|
|
3011
3084
|
|
|
3012
3085
|
/**
|
|
@@ -3015,10 +3088,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3015
3088
|
*/
|
|
3016
3089
|
function addSettingsTool(drawer, node, presets) {
|
|
3017
3090
|
var details = createDetails(node, presets || []);
|
|
3018
|
-
|
|
3091
|
+
detailsFor.set(node, details);
|
|
3019
3092
|
|
|
3020
3093
|
createTool(drawer, t('tool.settings'), 'ge-settings', 'bi bi-gear-fill', function() {
|
|
3021
|
-
toggleSettings(node, details,
|
|
3094
|
+
toggleSettings(node, details, this);
|
|
3022
3095
|
});
|
|
3023
3096
|
|
|
3024
3097
|
// Beside the gear, because every node that has one is a node a
|
|
@@ -3026,71 +3099,79 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3026
3099
|
// feature plugin's tools go there too, for the same reason: the
|
|
3027
3100
|
// gear is the one tool every drawer has.
|
|
3028
3101
|
var kind = kindOf(node);
|
|
3029
|
-
|
|
3030
|
-
if (
|
|
3102
|
+
Object.keys(UTILITIES).forEach(function(name) {
|
|
3103
|
+
if (UTILITIES[name].drawerTools) { UTILITIES[name].drawerTools(drawer, node, kind); }
|
|
3031
3104
|
});
|
|
3032
|
-
|
|
3033
|
-
if (
|
|
3105
|
+
Object.keys(FEATURES).forEach(function(name) {
|
|
3106
|
+
if (FEATURES[name].drawerTools) { FEATURES[name].drawerTools(drawer, node, kind); }
|
|
3034
3107
|
});
|
|
3035
3108
|
|
|
3036
|
-
return
|
|
3109
|
+
return drawer.appendChild(details);
|
|
3037
3110
|
}
|
|
3038
3111
|
|
|
3039
3112
|
function createDetails(container, cssClasses) {
|
|
3040
|
-
var detailsDiv =
|
|
3041
|
-
var general =
|
|
3113
|
+
var detailsDiv = dom.element('div', { 'class': 'ge-details' });
|
|
3114
|
+
var general = detailsDiv.appendChild(dom.element('div', { 'class': 'ge-details-general' }));
|
|
3042
3115
|
var field = function(label) {
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3116
|
+
var holder = dom.element('label', { 'class': 'ge-field' });
|
|
3117
|
+
holder.appendChild(dom.element('span', { 'class': 'ge-field-label' }, label));
|
|
3118
|
+
return general.appendChild(holder);
|
|
3046
3119
|
};
|
|
3047
3120
|
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3121
|
+
var id = dom.element('input', {
|
|
3122
|
+
'class': 'ge-id form-control form-control-sm',
|
|
3123
|
+
placeholder: t('tool.id_placeholder'),
|
|
3124
|
+
title: t('tool.id_title'),
|
|
3125
|
+
});
|
|
3126
|
+
id.value = container.getAttribute('id') || '';
|
|
3127
|
+
field(t('panel.id')).appendChild(id);
|
|
3128
|
+
id.addEventListener('change', function() {
|
|
3129
|
+
// An empty field means no id, not an empty one
|
|
3130
|
+
if (this.value === '') {
|
|
3131
|
+
container.removeAttribute('id');
|
|
3132
|
+
} else {
|
|
3133
|
+
container.setAttribute('id', this.value);
|
|
3134
|
+
}
|
|
3135
|
+
});
|
|
3136
|
+
|
|
3137
|
+
var classes = dom.element('input', {
|
|
3138
|
+
'class': 'ge-classes form-control form-control-sm',
|
|
3139
|
+
placeholder: t('tool.classes_placeholder'),
|
|
3140
|
+
title: t('tool.classes_title'),
|
|
3141
|
+
});
|
|
3142
|
+
classes.value = hostClasses(container).join(' ');
|
|
3143
|
+
field(t('panel.classes')).appendChild(classes);
|
|
3144
|
+
classes.addEventListener('change', function() {
|
|
3145
|
+
setHostClasses(container, this.value);
|
|
3146
|
+
refreshUtilities(container);
|
|
3147
|
+
});
|
|
3073
3148
|
|
|
3074
3149
|
// Bootstrap 5's outline buttons, filled while their class is on;
|
|
3075
3150
|
// up to 5.x they carried Bootstrap 3's btn-default, which 5 lacks
|
|
3076
|
-
var classGroup =
|
|
3151
|
+
var classGroup = general.appendChild(dom.element('div', { 'class': 'btn-group btn-group-sm ge-presets', role: 'group' }));
|
|
3077
3152
|
cssClasses.forEach(function(rowClass) {
|
|
3078
|
-
var
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3153
|
+
var on = dom.hasClass(container, rowClass.cssClass);
|
|
3154
|
+
var btn = dom.element('a', {
|
|
3155
|
+
role: 'button',
|
|
3156
|
+
'class': 'btn btn-sm btn-outline-secondary',
|
|
3157
|
+
title: rowClass.title ? rowClass.title : t('tool.toggle_class', { label: rowClass.label }),
|
|
3158
|
+
'aria-pressed': on ? 'true' : 'false',
|
|
3159
|
+
});
|
|
3160
|
+
|
|
3161
|
+
// A preset's label is the host's markup, as it was in 6.x
|
|
3162
|
+
btn.innerHTML = rowClass.label;
|
|
3163
|
+
dom.toggleClass(btn, 'active', on);
|
|
3164
|
+
btn.addEventListener('click', function() {
|
|
3165
|
+
dom.toggleClass(btn, 'active');
|
|
3166
|
+
btn.setAttribute('aria-pressed', dom.hasClass(btn, 'active') ? 'true' : 'false');
|
|
3167
|
+
dom.toggleClass(container, rowClass.cssClass, dom.hasClass(btn, 'active'));
|
|
3168
|
+
refreshUtilities(container);
|
|
3169
|
+
});
|
|
3170
|
+
classGroup.appendChild(btn);
|
|
3090
3171
|
});
|
|
3091
3172
|
|
|
3092
3173
|
var utilities = createUtilitiesSection(container);
|
|
3093
|
-
if (utilities) {
|
|
3174
|
+
if (utilities) { detailsDiv.appendChild(utilities); }
|
|
3094
3175
|
|
|
3095
3176
|
return detailsDiv;
|
|
3096
3177
|
}
|
|
@@ -3113,6 +3194,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3113
3194
|
var PANEL_MODES = ['offcanvas', 'popover', 'modal', 'inline'];
|
|
3114
3195
|
var settingsPanels = {}; // One of each, built on first use, outside the canvas
|
|
3115
3196
|
var openSettingsState = null; // What is open: { mode, node, details, home, next, gear }
|
|
3197
|
+
var modalState = new WeakMap(); // modal panel -> { watched, wanted, busy }
|
|
3116
3198
|
|
|
3117
3199
|
function panelMode() {
|
|
3118
3200
|
if (PANEL_MODES.indexOf(settings.settings_panel) !== -1) { return settings.settings_panel; }
|
|
@@ -3122,17 +3204,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3122
3204
|
return 'offcanvas';
|
|
3123
3205
|
}
|
|
3124
3206
|
|
|
3125
|
-
/** A node's panel, wherever it is at the moment. */
|
|
3207
|
+
/** A node's panel, wherever it is at the moment, or null. */
|
|
3126
3208
|
function detailsOf(node) {
|
|
3127
|
-
|
|
3128
|
-
return details && details.length ? details : $();
|
|
3209
|
+
return (node && detailsFor.get(node)) || null;
|
|
3129
3210
|
}
|
|
3130
3211
|
|
|
3131
3212
|
/** Where settings fields are found: the canvas, and the panel open outside it. */
|
|
3132
3213
|
function settingsScope() {
|
|
3133
3214
|
return openSettingsState && openSettingsState.mode !== 'inline'
|
|
3134
|
-
? canvas
|
|
3135
|
-
: canvas;
|
|
3215
|
+
? [canvas, openSettingsState.details]
|
|
3216
|
+
: [canvas];
|
|
3136
3217
|
}
|
|
3137
3218
|
|
|
3138
3219
|
/** The gear: its node's panel, opened or closed; another node's closes first. */
|
|
@@ -3140,57 +3221,61 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3140
3221
|
var mode = panelMode();
|
|
3141
3222
|
|
|
3142
3223
|
if (mode === 'inline') {
|
|
3143
|
-
|
|
3224
|
+
dom.toggle(details);
|
|
3144
3225
|
return;
|
|
3145
3226
|
}
|
|
3146
3227
|
|
|
3147
|
-
var same = openSettingsState && openSettingsState.details
|
|
3228
|
+
var same = openSettingsState && openSettingsState.details === details;
|
|
3148
3229
|
closeSettings();
|
|
3149
3230
|
if (!same) { openSettings(mode, node, details, gear); }
|
|
3150
3231
|
}
|
|
3151
3232
|
|
|
3152
3233
|
function openSettings(mode, node, details, gear) {
|
|
3153
3234
|
var panel = settingsPanel(mode);
|
|
3235
|
+
var listening = new AbortController();
|
|
3154
3236
|
|
|
3155
3237
|
openSettingsState = {
|
|
3156
3238
|
mode: mode,
|
|
3157
3239
|
node: node,
|
|
3158
3240
|
details: details,
|
|
3159
|
-
home: details.
|
|
3160
|
-
next: details.
|
|
3241
|
+
home: details.parentElement,
|
|
3242
|
+
next: details.nextElementSibling,
|
|
3161
3243
|
gear: gear,
|
|
3244
|
+
listening: listening,
|
|
3162
3245
|
};
|
|
3163
3246
|
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3247
|
+
dom.one(panel, '.ge-settings-title').textContent = t('panel.title', { kind: kindLabel(node) });
|
|
3248
|
+
dom.one(panel, '.ge-settings-body').appendChild(details);
|
|
3249
|
+
dom.show(details);
|
|
3250
|
+
dom.addClass(node, 'ge-settings-target');
|
|
3167
3251
|
|
|
3168
|
-
var
|
|
3169
|
-
|
|
3252
|
+
var signal = { signal: listening.signal };
|
|
3253
|
+
document.addEventListener('keydown', function(e) {
|
|
3170
3254
|
if (e.key === 'Escape') { closeSettings(); }
|
|
3171
|
-
});
|
|
3255
|
+
}, signal);
|
|
3172
3256
|
|
|
3173
3257
|
if (mode === 'offcanvas') {
|
|
3174
3258
|
// From the bottom on a phone, from the side anywhere wider
|
|
3175
3259
|
var narrow = window.innerWidth < 576;
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
panel.
|
|
3260
|
+
dom.toggleClass(panel, 'offcanvas-end', !narrow);
|
|
3261
|
+
dom.toggleClass(panel, 'offcanvas-bottom', narrow);
|
|
3262
|
+
dom.removeClass(panel, 'hiding');
|
|
3263
|
+
panel.getBoundingClientRect(); // So the slide in is a transition, not a jump
|
|
3264
|
+
dom.addClass(panel, 'show');
|
|
3180
3265
|
} else if (mode === 'popover') {
|
|
3181
3266
|
placePopover(panel, gear);
|
|
3182
|
-
|
|
3267
|
+
dom.on(window, 'scroll resize', function() { placePopover(panel, gear); }, signal);
|
|
3183
3268
|
|
|
3184
3269
|
// And again whenever what is in it changes size: the
|
|
3185
3270
|
// Responsive section unfolding, a plugin swapping a field
|
|
3186
3271
|
if (window.ResizeObserver) {
|
|
3187
3272
|
openSettingsState.observer = new window.ResizeObserver(function() { placePopover(panel, gear); });
|
|
3188
|
-
openSettingsState.observer.observe(details
|
|
3273
|
+
openSettingsState.observer.observe(details);
|
|
3189
3274
|
}
|
|
3190
3275
|
// A press anywhere else puts it away, as a popover does
|
|
3191
|
-
|
|
3192
|
-
if (
|
|
3193
|
-
});
|
|
3276
|
+
dom.on(document, 'mousedown touchstart', function(e) {
|
|
3277
|
+
if (!panel.contains(e.target) && !gear.contains(e.target)) { closeSettings(); }
|
|
3278
|
+
}, signal);
|
|
3194
3279
|
} else {
|
|
3195
3280
|
showModal(panel);
|
|
3196
3281
|
}
|
|
@@ -3203,29 +3288,30 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3203
3288
|
openSettingsState = null;
|
|
3204
3289
|
|
|
3205
3290
|
var panel = settingsPanels[open.mode];
|
|
3206
|
-
|
|
3207
|
-
$(window).off('.ge-settings-' + instanceId);
|
|
3291
|
+
open.listening.abort();
|
|
3208
3292
|
if (open.observer) { open.observer.disconnect(); }
|
|
3209
3293
|
|
|
3210
3294
|
if (open.mode === 'offcanvas') {
|
|
3211
|
-
|
|
3212
|
-
|
|
3295
|
+
dom.removeClass(panel, 'show');
|
|
3296
|
+
dom.addClass(panel, 'hiding');
|
|
3297
|
+
window.setTimeout(function() { dom.removeClass(panel, 'hiding'); }, 300);
|
|
3213
3298
|
} else if (open.mode === 'popover') {
|
|
3214
|
-
|
|
3299
|
+
dom.hide(panel);
|
|
3215
3300
|
} else {
|
|
3216
3301
|
hideModal(panel);
|
|
3217
3302
|
}
|
|
3218
3303
|
|
|
3219
|
-
open.node
|
|
3220
|
-
open.details.
|
|
3304
|
+
dom.removeClass(open.node, 'ge-settings-target');
|
|
3305
|
+
open.details.style.removeProperty('display');
|
|
3306
|
+
dom.dropEmptyStyle(open.details);
|
|
3221
3307
|
|
|
3222
3308
|
// Where it was in its drawer, if the drawer is still there: a
|
|
3223
3309
|
// node deleted while its settings were open took it with it
|
|
3224
|
-
if (open.home
|
|
3225
|
-
if (open.next
|
|
3226
|
-
open.
|
|
3310
|
+
if (open.home && dom.attached(open.home)) {
|
|
3311
|
+
if (open.next && open.next.parentElement === open.home) {
|
|
3312
|
+
open.home.insertBefore(open.details, open.next);
|
|
3227
3313
|
} else {
|
|
3228
|
-
open.
|
|
3314
|
+
open.home.appendChild(open.details);
|
|
3229
3315
|
}
|
|
3230
3316
|
} else {
|
|
3231
3317
|
open.details.remove();
|
|
@@ -3236,58 +3322,64 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3236
3322
|
function settingsPanel(mode) {
|
|
3237
3323
|
if (settingsPanels[mode]) { return settingsPanels[mode]; }
|
|
3238
3324
|
|
|
3239
|
-
var closeButton = function(
|
|
3240
|
-
return
|
|
3241
|
-
|
|
3242
|
-
|
|
3325
|
+
var closeButton = function() {
|
|
3326
|
+
return dom.element('button', {
|
|
3327
|
+
type: 'button',
|
|
3328
|
+
'class': 'btn-close ge-settings-close',
|
|
3329
|
+
'aria-label': t('panel.close'),
|
|
3330
|
+
});
|
|
3243
3331
|
};
|
|
3244
3332
|
var panel;
|
|
3245
3333
|
|
|
3246
3334
|
if (mode === 'offcanvas') {
|
|
3247
|
-
panel =
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3335
|
+
panel = dom.create('<div class="offcanvas offcanvas-end ge-settings-panel ge-settings-offcanvas" tabindex="-1" role="dialog">' +
|
|
3336
|
+
'<div class="offcanvas-header"><h5 class="offcanvas-title ge-settings-title"></h5></div>' +
|
|
3337
|
+
'<div class="offcanvas-body ge-settings-body"></div>' +
|
|
3338
|
+
'</div>');
|
|
3339
|
+
dom.one(panel, '.offcanvas-header').appendChild(closeButton());
|
|
3252
3340
|
} else if (mode === 'popover') {
|
|
3253
|
-
panel =
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3341
|
+
panel = dom.create('<div class="popover bs-popover-bottom ge-settings-panel ge-settings-popover" role="dialog">' +
|
|
3342
|
+
'<div class="popover-arrow"></div>' +
|
|
3343
|
+
'<div class="popover-header"><span class="ge-settings-title"></span></div>' +
|
|
3344
|
+
'<div class="popover-body ge-settings-body"></div>' +
|
|
3345
|
+
'</div>');
|
|
3346
|
+
dom.one(panel, '.popover-header').appendChild(closeButton());
|
|
3347
|
+
dom.hide(panel);
|
|
3260
3348
|
} else {
|
|
3261
|
-
panel =
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3349
|
+
panel = dom.create('<div class="modal fade ge-settings-panel ge-settings-modal" tabindex="-1" role="dialog" aria-hidden="true">' +
|
|
3350
|
+
'<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">' +
|
|
3351
|
+
'<div class="modal-content">' +
|
|
3352
|
+
'<div class="modal-header"><h5 class="modal-title ge-settings-title"></h5></div>' +
|
|
3353
|
+
'<div class="modal-body ge-settings-body"></div>' +
|
|
3354
|
+
'<div class="modal-footer"></div>' +
|
|
3355
|
+
'</div>' +
|
|
3356
|
+
'</div>' +
|
|
3357
|
+
'</div>');
|
|
3358
|
+
dom.one(panel, '.modal-header').appendChild(closeButton());
|
|
3359
|
+
dom.one(panel, '.modal-footer').appendChild(dom.element('button', {
|
|
3360
|
+
type: 'button',
|
|
3361
|
+
'class': 'btn btn-primary ge-settings-close',
|
|
3362
|
+
}, t('panel.done')));
|
|
3271
3363
|
}
|
|
3272
3364
|
|
|
3273
|
-
|
|
3365
|
+
dom.delegate(panel, 'click', '.ge-settings-close', function(e) {
|
|
3274
3366
|
e.preventDefault();
|
|
3275
3367
|
closeSettings();
|
|
3276
3368
|
});
|
|
3277
3369
|
|
|
3278
|
-
settingsPanels[mode] =
|
|
3370
|
+
settingsPanels[mode] = document.body.appendChild(panel);
|
|
3279
3371
|
return panel;
|
|
3280
3372
|
}
|
|
3281
3373
|
|
|
3282
3374
|
function removeSettingsPanels() {
|
|
3283
3375
|
closeSettings();
|
|
3284
3376
|
|
|
3285
|
-
|
|
3286
|
-
if (mode === 'modal'
|
|
3287
|
-
|
|
3288
|
-
|
|
3377
|
+
Object.keys(settingsPanels).forEach(function(mode) {
|
|
3378
|
+
if (mode === 'modal') {
|
|
3379
|
+
retireModal(settingsPanels[mode]);
|
|
3380
|
+
} else {
|
|
3381
|
+
settingsPanels[mode].remove();
|
|
3289
3382
|
}
|
|
3290
|
-
panel.remove();
|
|
3291
3383
|
});
|
|
3292
3384
|
if (settingsBackdrop) { settingsBackdrop.remove(); settingsBackdrop = null; }
|
|
3293
3385
|
settingsPanels = {};
|
|
@@ -3299,37 +3391,37 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3299
3391
|
* scrolls.
|
|
3300
3392
|
*/
|
|
3301
3393
|
function placePopover(panel, gear) {
|
|
3302
|
-
if (
|
|
3394
|
+
if (!dom.attached(gear)) { return; }
|
|
3303
3395
|
|
|
3304
|
-
|
|
3396
|
+
dom.show(panel);
|
|
3305
3397
|
|
|
3306
|
-
var tool = gear
|
|
3398
|
+
var tool = gear.getBoundingClientRect();
|
|
3307
3399
|
var gap = 8;
|
|
3308
|
-
var body =
|
|
3309
|
-
|
|
3310
|
-
var
|
|
3400
|
+
var body = dom.child(panel, '.popover-body');
|
|
3401
|
+
body.style.removeProperty('max-height');
|
|
3402
|
+
var width = dom.outerWidth(panel);
|
|
3403
|
+
var height = dom.outerHeight(panel);
|
|
3311
3404
|
var roomBelow = window.innerHeight - tool.bottom - 2 * gap;
|
|
3312
3405
|
var roomAbove = tool.top - 2 * gap;
|
|
3313
3406
|
var below = height <= roomBelow || roomBelow >= roomAbove;
|
|
3314
3407
|
var room = below ? roomBelow : roomAbove;
|
|
3315
3408
|
|
|
3316
3409
|
if (height > room) {
|
|
3317
|
-
|
|
3318
|
-
height =
|
|
3410
|
+
dom.css(body, { 'max-height': Math.max(120, room - (height - dom.outerHeight(body))) });
|
|
3411
|
+
height = dom.outerHeight(panel);
|
|
3319
3412
|
}
|
|
3320
3413
|
|
|
3321
3414
|
var top = below ? tool.bottom + gap : tool.top - gap - height;
|
|
3322
3415
|
var left = Math.max(gap, Math.min(tool.left + tool.width / 2 - 24, window.innerWidth - width - gap));
|
|
3323
3416
|
|
|
3324
|
-
panel
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
.css({ top: top + window.pageYOffset, left: left + window.pageXOffset })
|
|
3328
|
-
;
|
|
3417
|
+
dom.toggleClass(panel, 'bs-popover-bottom', below);
|
|
3418
|
+
dom.toggleClass(panel, 'bs-popover-top', !below);
|
|
3419
|
+
dom.css(panel, { top: top + window.pageYOffset, left: left + window.pageXOffset });
|
|
3329
3420
|
|
|
3330
3421
|
// The arrow points at the gear, wherever the popover had to go
|
|
3331
|
-
|
|
3332
|
-
Math.max(gap, Math.min(tool.left + tool.width / 2 - left - 8, width - 24))
|
|
3422
|
+
dom.css(dom.child(panel, '.popover-arrow'), {
|
|
3423
|
+
left: Math.max(gap, Math.min(tool.left + tool.width / 2 - left - 8, width - 24)),
|
|
3424
|
+
});
|
|
3333
3425
|
}
|
|
3334
3426
|
|
|
3335
3427
|
var settingsBackdrop = null; // The modal's backdrop, when Bootstrap's javascript is not there to make one
|
|
@@ -3343,32 +3435,40 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3343
3435
|
* closes the settings as the close button does.
|
|
3344
3436
|
*/
|
|
3345
3437
|
function showModal(panel) {
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3438
|
+
var Modal = modalLibrary();
|
|
3439
|
+
|
|
3440
|
+
if (!Modal) {
|
|
3441
|
+
settingsBackdrop = dom.element('div', { 'class': 'modal-backdrop fade show ge-settings-backdrop' });
|
|
3442
|
+
settingsBackdrop.addEventListener('click', function() { closeSettings(); });
|
|
3443
|
+
document.body.appendChild(settingsBackdrop);
|
|
3444
|
+
dom.addClass(panel, 'show');
|
|
3445
|
+
panel.style.display = 'block';
|
|
3446
|
+
panel.removeAttribute('aria-hidden');
|
|
3351
3447
|
return;
|
|
3352
3448
|
}
|
|
3353
3449
|
|
|
3354
|
-
var modal =
|
|
3450
|
+
var modal = Modal.getOrCreateInstance(panel);
|
|
3451
|
+
var state = modalState.get(panel);
|
|
3355
3452
|
|
|
3356
|
-
if (!
|
|
3357
|
-
|
|
3358
|
-
|
|
3453
|
+
if (!state) {
|
|
3454
|
+
state = { wanted: null, busy: false };
|
|
3455
|
+
modalState.set(panel, state);
|
|
3456
|
+
trackModal(panel);
|
|
3457
|
+
|
|
3458
|
+
panel.addEventListener('hide.bs.modal', function() {
|
|
3359
3459
|
// Not asked for: Escape or the backdrop
|
|
3360
|
-
if (
|
|
3361
|
-
|
|
3362
|
-
|
|
3460
|
+
if (state.wanted === 'open') {
|
|
3461
|
+
state.wanted = 'closed';
|
|
3462
|
+
state.busy = true;
|
|
3363
3463
|
}
|
|
3364
3464
|
});
|
|
3365
|
-
panel.
|
|
3366
|
-
|
|
3367
|
-
if (
|
|
3465
|
+
panel.addEventListener('shown.bs.modal', function() {
|
|
3466
|
+
state.busy = false;
|
|
3467
|
+
if (state.wanted === 'closed') { hideModal(panel); }
|
|
3368
3468
|
});
|
|
3369
|
-
panel.
|
|
3370
|
-
|
|
3371
|
-
if (
|
|
3469
|
+
panel.addEventListener('hidden.bs.modal', function() {
|
|
3470
|
+
state.busy = false;
|
|
3471
|
+
if (state.wanted === 'open') {
|
|
3372
3472
|
showModal(panel);
|
|
3373
3473
|
} else if (openSettingsState && openSettingsState.mode === 'modal') {
|
|
3374
3474
|
closeSettings();
|
|
@@ -3376,28 +3476,33 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3376
3476
|
});
|
|
3377
3477
|
}
|
|
3378
3478
|
|
|
3379
|
-
|
|
3380
|
-
if (!
|
|
3381
|
-
|
|
3479
|
+
state.wanted = 'open';
|
|
3480
|
+
if (!state.busy) {
|
|
3481
|
+
state.busy = true;
|
|
3382
3482
|
modal.show();
|
|
3383
3483
|
}
|
|
3384
3484
|
}
|
|
3385
3485
|
|
|
3386
3486
|
function hideModal(panel) {
|
|
3387
|
-
|
|
3487
|
+
var Modal = modalLibrary();
|
|
3488
|
+
|
|
3489
|
+
if (!Modal) {
|
|
3388
3490
|
if (settingsBackdrop) { settingsBackdrop.remove(); settingsBackdrop = null; }
|
|
3389
|
-
|
|
3491
|
+
dom.removeClass(panel, 'show');
|
|
3492
|
+
panel.style.removeProperty('display');
|
|
3493
|
+
panel.setAttribute('aria-hidden', 'true');
|
|
3390
3494
|
return;
|
|
3391
3495
|
}
|
|
3392
3496
|
|
|
3393
|
-
|
|
3497
|
+
var state = modalState.get(panel) || { wanted: null, busy: false };
|
|
3498
|
+
state.wanted = 'closed';
|
|
3394
3499
|
|
|
3395
3500
|
// Already out of sight - Bootstrap hid it itself, and this is its
|
|
3396
3501
|
// hidden event closing the settings - and nothing is under way:
|
|
3397
3502
|
// a hide now would be ignored, and no event would come to say so
|
|
3398
|
-
if (!
|
|
3399
|
-
|
|
3400
|
-
|
|
3503
|
+
if (!state.busy && dom.hasClass(panel, 'show')) {
|
|
3504
|
+
state.busy = true;
|
|
3505
|
+
Modal.getOrCreateInstance(panel).hide();
|
|
3401
3506
|
}
|
|
3402
3507
|
}
|
|
3403
3508
|
|
|
@@ -3430,11 +3535,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3430
3535
|
* column that had none.
|
|
3431
3536
|
*/
|
|
3432
3537
|
function addAllColClasses() {
|
|
3433
|
-
|
|
3434
|
-
|
|
3538
|
+
dom.all(canvas, '.column, div[class*="col-"], div.col').forEach(function(col) {
|
|
3539
|
+
dom.addClass(col, 'column');
|
|
3435
3540
|
|
|
3436
3541
|
// A column in a row with row-cols is sized by its row
|
|
3437
|
-
if (sizedTiers(col).length || hasRowCols(col.
|
|
3542
|
+
if (sizedTiers(col).length || hasRowCols(col.parentElement)) { return; }
|
|
3438
3543
|
|
|
3439
3544
|
setSize(col, BREAKPOINTS[0], MAX_COL_SIZE);
|
|
3440
3545
|
});
|
|
@@ -3452,18 +3557,18 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3452
3557
|
* -------------------------------------------------------------- */
|
|
3453
3558
|
|
|
3454
3559
|
function hasRowCols(row) {
|
|
3455
|
-
return
|
|
3456
|
-
return ROW_COLS_VALUES.some(function(value) { return
|
|
3560
|
+
return dom.hasClass(row, 'row') && BREAKPOINTS.some(function(tier) {
|
|
3561
|
+
return ROW_COLS_VALUES.some(function(value) { return dom.hasClass(row, rowColsClass(tier, value)); });
|
|
3457
3562
|
});
|
|
3458
3563
|
}
|
|
3459
3564
|
|
|
3460
3565
|
/** The row-cols class that applies to a row at a tier, as { tier, value }, or null. */
|
|
3461
3566
|
function rowColsSource(row, tier) {
|
|
3462
|
-
if (!
|
|
3567
|
+
if (!dom.hasClass(row, 'row')) { return null; }
|
|
3463
3568
|
|
|
3464
3569
|
for (var i = BREAKPOINTS.indexOf(tier); i >= 0; i--) {
|
|
3465
3570
|
for (var v = 0; v < ROW_COLS_VALUES.length; v++) {
|
|
3466
|
-
if (
|
|
3571
|
+
if (dom.hasClass(row, rowColsClass(BREAKPOINTS[i], ROW_COLS_VALUES[v]))) {
|
|
3467
3572
|
return { tier: i, value: ROW_COLS_VALUES[v] };
|
|
3468
3573
|
}
|
|
3469
3574
|
}
|
|
@@ -3487,7 +3592,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3487
3592
|
* the column's own size does.
|
|
3488
3593
|
*/
|
|
3489
3594
|
function rowColsWinner(col, tier) {
|
|
3490
|
-
var row = rowColsSource(col.
|
|
3595
|
+
var row = rowColsSource(col.parentElement, tier);
|
|
3491
3596
|
if (!row) { return null; }
|
|
3492
3597
|
|
|
3493
3598
|
var own = columnSource(col, tier);
|
|
@@ -3520,7 +3625,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3520
3625
|
|
|
3521
3626
|
// A wider breakpoint's row-cols is live in a wide window; a
|
|
3522
3627
|
// column with no size of its own here is a full width one
|
|
3523
|
-
if (hasRowCols(col.
|
|
3628
|
+
if (hasRowCols(col.parentElement) && !columnSource(col, tier)) {
|
|
3524
3629
|
return { flex: '0 0 auto', width: '100%', 'max-width': '100%' };
|
|
3525
3630
|
}
|
|
3526
3631
|
|
|
@@ -3532,16 +3637,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3532
3637
|
* and in the all view by its row-cols with no breakpoint.
|
|
3533
3638
|
*/
|
|
3534
3639
|
function markRowCols(scope) {
|
|
3535
|
-
|
|
3536
|
-
var row = $(this);
|
|
3640
|
+
dom.selfAndAll(scope, '.row').forEach(function(row) {
|
|
3537
3641
|
var source = settings.row_cols === false ? null : (curView === ALL_VIEW
|
|
3538
3642
|
? (rowColsSource(row, BREAKPOINTS[0]) || null)
|
|
3539
3643
|
: rowColsSource(row, breakpoint(curView)));
|
|
3540
3644
|
|
|
3541
3645
|
if (!source) {
|
|
3542
|
-
row.
|
|
3646
|
+
row.removeAttribute('data-ge-row-cols');
|
|
3543
3647
|
} else {
|
|
3544
|
-
row.
|
|
3648
|
+
row.setAttribute('data-ge-row-cols', rowColsLabel(source.value));
|
|
3545
3649
|
}
|
|
3546
3650
|
});
|
|
3547
3651
|
}
|
|
@@ -3578,8 +3682,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3578
3682
|
var units = readUnits(col, tier.colPrefix);
|
|
3579
3683
|
if (units !== null) { return units; }
|
|
3580
3684
|
|
|
3581
|
-
if (
|
|
3582
|
-
if (
|
|
3685
|
+
if (dom.hasClass(col, sizeClass(tier, 'auto'))) { return 'auto'; }
|
|
3686
|
+
if (dom.hasClass(col, sizeClass(tier, 'equal'))) { return 'equal'; }
|
|
3583
3687
|
|
|
3584
3688
|
return null;
|
|
3585
3689
|
}
|
|
@@ -3617,26 +3721,26 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3617
3721
|
}
|
|
3618
3722
|
|
|
3619
3723
|
function readUnits(col, prefix) {
|
|
3620
|
-
var match = new RegExp('(?:^|\\s)' + prefix + '(\\d+)(?:\\s|$)').exec(col.
|
|
3724
|
+
var match = new RegExp('(?:^|\\s)' + prefix + '(\\d+)(?:\\s|$)').exec(col.getAttribute('class') || '');
|
|
3621
3725
|
return match ? parseInt(match[1], 10) : null;
|
|
3622
3726
|
}
|
|
3623
3727
|
|
|
3624
3728
|
function writeUnits(col, prefix, units) {
|
|
3625
|
-
var classes = (col.
|
|
3729
|
+
var classes = (col.getAttribute('class') || '').split(/\s+/).filter(function(name) {
|
|
3626
3730
|
return name !== '' && !new RegExp('^' + prefix + '\\d+$').test(name);
|
|
3627
3731
|
});
|
|
3628
3732
|
|
|
3629
3733
|
if (units !== null) { classes.push(prefix + units); }
|
|
3630
3734
|
|
|
3631
|
-
col.
|
|
3735
|
+
col.setAttribute('class', classes.join(' '));
|
|
3632
3736
|
}
|
|
3633
3737
|
|
|
3634
3738
|
/** One size per tier: writing a size takes whatever size the tier had off. */
|
|
3635
3739
|
function setSize(col, tier, size) {
|
|
3636
3740
|
writeUnits(col, tier.colPrefix, null);
|
|
3637
|
-
FLEX_SIZES.forEach(function(flex) {
|
|
3741
|
+
FLEX_SIZES.forEach(function(flex) { dom.removeClass(col, sizeClass(tier, flex)); });
|
|
3638
3742
|
|
|
3639
|
-
if (size !== null && size !== undefined) {
|
|
3743
|
+
if (size !== null && size !== undefined) { dom.addClass(col, sizeClass(tier, size)); }
|
|
3640
3744
|
}
|
|
3641
3745
|
|
|
3642
3746
|
/** An offset of 0 is written as no class at all, which is what it means. */
|
|
@@ -3658,9 +3762,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3658
3762
|
function spare(row, tier, ignore) {
|
|
3659
3763
|
var used = 0;
|
|
3660
3764
|
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
if (ignore && sibling[0] === ignore[0]) { return; }
|
|
3765
|
+
dom.children(row, '.column').forEach(function(sibling) {
|
|
3766
|
+
if (ignore && sibling === ignore) { return; }
|
|
3664
3767
|
|
|
3665
3768
|
// An equal or auto column takes what is left, so it uses none;
|
|
3666
3769
|
// one its row sizes uses its share of the line
|
|
@@ -3709,14 +3812,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3709
3812
|
* been written.
|
|
3710
3813
|
*/
|
|
3711
3814
|
function stripPixelWidths(scope) {
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
col.css({ width: '', height: '', left: '', top: '' });
|
|
3815
|
+
dom.selfAndAll(scope, '.column').forEach(function(col) {
|
|
3816
|
+
dom.css(col, { width: '', height: '', left: '', top: '' });
|
|
3716
3817
|
|
|
3717
3818
|
// Clearing the last property leaves style="" behind, which is
|
|
3718
3819
|
// an editor leftover like any other
|
|
3719
|
-
|
|
3820
|
+
dom.dropEmptyStyle(col);
|
|
3720
3821
|
});
|
|
3721
3822
|
}
|
|
3722
3823
|
|
|
@@ -3744,7 +3845,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3744
3845
|
|
|
3745
3846
|
/** A selector every feature plugin may contribute to, under one name. */
|
|
3746
3847
|
function pluginHooks(name) {
|
|
3747
|
-
return
|
|
3848
|
+
return Object.keys(FEATURES).map(function(key) {
|
|
3849
|
+
return FEATURES[key][name] || null;
|
|
3850
|
+
}).filter(function(hook) { return hook !== null; });
|
|
3748
3851
|
}
|
|
3749
3852
|
|
|
3750
3853
|
/**
|
|
@@ -3755,7 +3858,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3755
3858
|
function acceptsBlock(region, node) {
|
|
3756
3859
|
var accepted = true;
|
|
3757
3860
|
|
|
3758
|
-
|
|
3861
|
+
Object.keys(FEATURES).forEach(function(name) {
|
|
3862
|
+
var feature = FEATURES[name];
|
|
3759
3863
|
if (accepted && feature.accepts && feature.accepts(region, node) === false) { accepted = false; }
|
|
3760
3864
|
});
|
|
3761
3865
|
|
|
@@ -3786,17 +3890,21 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3786
3890
|
* function's business. That is the whole point of it: the toolkit
|
|
3787
3891
|
* underneath is named in one place, so replacing it is one function
|
|
3788
3892
|
* and not thirty call sites.
|
|
3893
|
+
*
|
|
3894
|
+
* `lists` is an element or an array of them; `options.accepts`, when
|
|
3895
|
+
* given, is asked (list, item) with elements.
|
|
3789
3896
|
*/
|
|
3790
3897
|
function sortable(lists, options) {
|
|
3791
|
-
|
|
3898
|
+
var Sortable = sortableLibrary();
|
|
3899
|
+
|
|
3900
|
+
lists = Array.isArray(lists) ? lists : (lists ? [lists] : []);
|
|
3901
|
+
if (!lists.length || !Sortable) { return; }
|
|
3792
3902
|
|
|
3793
3903
|
var wholeDrawer = settings.drag_handle === 'drawer';
|
|
3794
3904
|
var cancel = dragCancelSelector();
|
|
3795
3905
|
var soloGroup = 0;
|
|
3796
3906
|
|
|
3797
|
-
lists.
|
|
3798
|
-
var list = this;
|
|
3799
|
-
|
|
3907
|
+
lists.forEach(function(list) {
|
|
3800
3908
|
// A list with no group sorts only within itself, which is what
|
|
3801
3909
|
// a tab strip wants: a name of its own, closed both ways
|
|
3802
3910
|
var group = options.group
|
|
@@ -3809,11 +3917,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3809
3917
|
// a column would drop into the canvas, or into another editor
|
|
3810
3918
|
if (options.group && options.accepts) {
|
|
3811
3919
|
group.put = function(to, from, dragged) {
|
|
3812
|
-
return from.options.group.name === group.name && options.accepts(
|
|
3920
|
+
return from.options.group.name === group.name && options.accepts(to.el, dragged);
|
|
3813
3921
|
};
|
|
3814
3922
|
}
|
|
3815
3923
|
|
|
3816
|
-
sortables.push(
|
|
3924
|
+
sortables.push(Sortable.create(list, Object.assign({
|
|
3817
3925
|
group: group,
|
|
3818
3926
|
draggable: options.draggable,
|
|
3819
3927
|
handle: wholeDrawer ? '.ge-tools-drawer' : '.ge-tools-drawer .ge-move',
|
|
@@ -3828,7 +3936,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3828
3936
|
* row nested three columns down and drag that.
|
|
3829
3937
|
*/
|
|
3830
3938
|
filter: function(e, item) {
|
|
3831
|
-
if (
|
|
3939
|
+
if (dom.closest(e.target, cancel, list)) { return true; }
|
|
3832
3940
|
|
|
3833
3941
|
return !item || item.parentNode !== list;
|
|
3834
3942
|
},
|
|
@@ -3873,17 +3981,17 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3873
3981
|
}
|
|
3874
3982
|
|
|
3875
3983
|
function makeSortable() {
|
|
3876
|
-
if (!
|
|
3984
|
+
if (!sortableLibrary()) {
|
|
3877
3985
|
warnOnceHere('sortable_missing', t('error.sortable_missing'));
|
|
3878
3986
|
return;
|
|
3879
3987
|
}
|
|
3880
3988
|
|
|
3881
|
-
sortable(
|
|
3989
|
+
sortable(dom.all(canvas, '.row'), {
|
|
3882
3990
|
draggable: '.column',
|
|
3883
3991
|
group: 'column',
|
|
3884
3992
|
});
|
|
3885
3993
|
|
|
3886
|
-
sortable(canvas.
|
|
3994
|
+
sortable([canvas].concat(dom.all(canvas, '.column')), {
|
|
3887
3995
|
draggable: blockSelector(),
|
|
3888
3996
|
group: 'block',
|
|
3889
3997
|
accepts: acceptsBlock,
|
|
@@ -3896,7 +4004,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3896
4004
|
// SortableJS for "direct children only", which the list is not.
|
|
3897
4005
|
var regions = pluginHooks('regions');
|
|
3898
4006
|
if (regions.length) {
|
|
3899
|
-
sortable(
|
|
4007
|
+
sortable(dom.all(canvas, regions.join(', ')), {
|
|
3900
4008
|
draggable: '>' + blockSelector(),
|
|
3901
4009
|
group: 'block',
|
|
3902
4010
|
accepts: acceptsBlock,
|
|
@@ -3914,12 +4022,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3914
4022
|
* always reported by the list that started the drag.
|
|
3915
4023
|
*/
|
|
3916
4024
|
function sortStart(e) {
|
|
3917
|
-
var node =
|
|
4025
|
+
var node = e.item;
|
|
3918
4026
|
var from = positionOf(node);
|
|
3919
4027
|
var subject = moveSubject(node);
|
|
4028
|
+
var move = { from: from, canceled: false };
|
|
3920
4029
|
|
|
3921
|
-
|
|
3922
|
-
node.removeData('ge-move-canceled');
|
|
4030
|
+
moves.set(node, move);
|
|
3923
4031
|
|
|
3924
4032
|
operate(function() {
|
|
3925
4033
|
var moving = emit('before-move', payloadFor(subject.kind, subject.node, {
|
|
@@ -3928,7 +4036,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3928
4036
|
from: from,
|
|
3929
4037
|
}));
|
|
3930
4038
|
|
|
3931
|
-
if (!moving) {
|
|
4039
|
+
if (!moving) { move.canceled = true; }
|
|
3932
4040
|
});
|
|
3933
4041
|
}
|
|
3934
4042
|
|
|
@@ -3937,40 +4045,42 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3937
4045
|
* wrapper, so what moved is the content area inside it.
|
|
3938
4046
|
*/
|
|
3939
4047
|
function moveSubject(item) {
|
|
3940
|
-
var node =
|
|
4048
|
+
var node = dom.hasClass(item, 'ge-text-block') ? (dom.child(item, '.ge-content') || item) : item;
|
|
3941
4049
|
|
|
3942
4050
|
return { kind: kindOf(node), node: node };
|
|
3943
4051
|
}
|
|
3944
4052
|
|
|
3945
4053
|
/** Put a node back where a refused drag found it. */
|
|
3946
4054
|
function putBack(node, from) {
|
|
3947
|
-
var siblings =
|
|
4055
|
+
var siblings = dom.children(from.parent).filter(function(child) {
|
|
4056
|
+
return child !== node && !dom.hasClass(child, 'ge-tools-drawer');
|
|
4057
|
+
});
|
|
3948
4058
|
|
|
3949
4059
|
if (!siblings.length || from.index >= siblings.length) {
|
|
3950
|
-
|
|
4060
|
+
from.parent.appendChild(node);
|
|
3951
4061
|
} else {
|
|
3952
|
-
|
|
4062
|
+
from.parent.insertBefore(node, siblings[from.index]);
|
|
3953
4063
|
}
|
|
3954
4064
|
}
|
|
3955
4065
|
|
|
3956
4066
|
function sortEnd(e) {
|
|
3957
|
-
var node =
|
|
3958
|
-
var
|
|
4067
|
+
var node = e.item;
|
|
4068
|
+
var move = moves.get(node);
|
|
4069
|
+
var from = move ? move.from : positionOf(node);
|
|
3959
4070
|
|
|
3960
|
-
|
|
4071
|
+
moves.delete(node);
|
|
3961
4072
|
|
|
3962
|
-
if (
|
|
3963
|
-
node.removeData('ge-move-canceled');
|
|
4073
|
+
if (move && move.canceled) {
|
|
3964
4074
|
putBack(node, from);
|
|
3965
4075
|
return;
|
|
3966
4076
|
}
|
|
3967
4077
|
|
|
3968
4078
|
var to = positionOf(node);
|
|
3969
|
-
if (to.parent
|
|
4079
|
+
if (to.parent === from.parent && to.index === from.index) {
|
|
3970
4080
|
return; // A drag that went nowhere is not a move
|
|
3971
4081
|
}
|
|
3972
4082
|
|
|
3973
|
-
var container =
|
|
4083
|
+
var container = dom.closest(node, '[data-ge-container]');
|
|
3974
4084
|
var definition = CONTAINERS[containerTypeOf(container)];
|
|
3975
4085
|
if (definition && definition.afterPaneMove) {
|
|
3976
4086
|
definition.afterPaneMove(container, node, from);
|
|
@@ -3987,7 +4097,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3987
4097
|
source: 'dragdrop',
|
|
3988
4098
|
from: from,
|
|
3989
4099
|
to: to,
|
|
3990
|
-
container: container
|
|
4100
|
+
container: container || undefined,
|
|
3991
4101
|
}));
|
|
3992
4102
|
});
|
|
3993
4103
|
}
|
|
@@ -4004,19 +4114,19 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4004
4114
|
function makeResizable() {
|
|
4005
4115
|
if (!settings.resize.enabled) { return; }
|
|
4006
4116
|
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
if (col.find('> .ge-resize-handle').length) { return; }
|
|
4117
|
+
dom.all(canvas, '.column').forEach(function(col) {
|
|
4118
|
+
if (dom.child(col, '.ge-resize-handle')) { return; }
|
|
4010
4119
|
|
|
4011
|
-
|
|
4120
|
+
var drawer = dom.child(col, '.ge-tools-drawer');
|
|
4121
|
+
if (drawer) { drawer.appendChild(dom.element('span', { 'class': 'ge-resize-size' })); }
|
|
4012
4122
|
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
;
|
|
4123
|
+
resizeEdges().forEach(function(edge) {
|
|
4124
|
+
var handle = dom.element('span', {
|
|
4125
|
+
'class': 'ge-resize-handle ge-resize-' + edge,
|
|
4126
|
+
'data-ge-edge': edge,
|
|
4127
|
+
});
|
|
4128
|
+
handle.addEventListener('pointerdown', startResizeDrag);
|
|
4129
|
+
col.appendChild(handle);
|
|
4020
4130
|
});
|
|
4021
4131
|
});
|
|
4022
4132
|
}
|
|
@@ -4037,19 +4147,19 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4037
4147
|
* starts: nothing is written and the column does not move.
|
|
4038
4148
|
*/
|
|
4039
4149
|
function startResizeDrag(e) {
|
|
4040
|
-
var handle =
|
|
4041
|
-
var col = handle.
|
|
4042
|
-
var west = handle.
|
|
4150
|
+
var handle = e.currentTarget;
|
|
4151
|
+
var col = handle.parentElement;
|
|
4152
|
+
var west = handle.getAttribute('data-ge-edge') === 'w';
|
|
4043
4153
|
var startX = e.pageX;
|
|
4044
|
-
var startWidth =
|
|
4154
|
+
var startWidth = dom.outerWidth(col);
|
|
4045
4155
|
|
|
4046
4156
|
e.preventDefault();
|
|
4047
4157
|
|
|
4048
4158
|
if (!resizeStart(col)) { return; }
|
|
4049
4159
|
|
|
4050
|
-
|
|
4051
|
-
if (e.pointerId !== undefined && handle
|
|
4052
|
-
handle
|
|
4160
|
+
dom.addClass(col, 'ge-resizing');
|
|
4161
|
+
if (e.pointerId !== undefined && handle.setPointerCapture) {
|
|
4162
|
+
handle.setPointerCapture(e.pointerId);
|
|
4053
4163
|
}
|
|
4054
4164
|
|
|
4055
4165
|
function widthAt(move) {
|
|
@@ -4059,23 +4169,25 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4059
4169
|
}
|
|
4060
4170
|
|
|
4061
4171
|
function onMove(move) {
|
|
4062
|
-
col.
|
|
4172
|
+
col.style.width = widthAt(move) + 'px';
|
|
4063
4173
|
resizeMove(col, widthAt(move));
|
|
4064
4174
|
}
|
|
4065
4175
|
|
|
4066
4176
|
function onUp(up) {
|
|
4067
|
-
handle.
|
|
4068
|
-
|
|
4177
|
+
handle.removeEventListener('pointermove', onMove);
|
|
4178
|
+
dom.off(handle, 'pointerup pointercancel', onUp);
|
|
4179
|
+
dom.removeClass(col, 'ge-resizing');
|
|
4069
4180
|
resizeStop(col, widthAt(up));
|
|
4070
4181
|
}
|
|
4071
4182
|
|
|
4072
|
-
handle.
|
|
4183
|
+
handle.addEventListener('pointermove', onMove);
|
|
4184
|
+
dom.on(handle, 'pointerup pointercancel', onUp);
|
|
4073
4185
|
}
|
|
4074
4186
|
|
|
4075
4187
|
function removeResizable() {
|
|
4076
|
-
|
|
4188
|
+
dom.all(canvas, '.ge-resize-handle').forEach(function(handle) { handle.remove(); });
|
|
4077
4189
|
|
|
4078
|
-
|
|
4190
|
+
dom.all(canvas, '.ge-resize-size').forEach(function(readout) { readout.remove(); });
|
|
4079
4191
|
stripPixelWidths(canvas);
|
|
4080
4192
|
}
|
|
4081
4193
|
|
|
@@ -4086,13 +4198,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4086
4198
|
* divider between two columns looks like it should do.
|
|
4087
4199
|
*/
|
|
4088
4200
|
function snapUnits(col, pixels) {
|
|
4089
|
-
var units = Math.round(pixels / rowContentWidth(col.
|
|
4201
|
+
var units = Math.round(pixels / rowContentWidth(col.parentElement) * MAX_COL_SIZE);
|
|
4090
4202
|
var next = balanceSibling(col);
|
|
4091
4203
|
var nextSize = next ? currentSize(next) : null;
|
|
4092
4204
|
|
|
4093
4205
|
// Measured when the drag started: the column is the width of the
|
|
4094
4206
|
// pointer now, which is not what it was
|
|
4095
|
-
var
|
|
4207
|
+
var resize = resizes.get(col);
|
|
4208
|
+
var own = resize ? resize.units : currentUnits(col);
|
|
4096
4209
|
|
|
4097
4210
|
// With a sibling to balance against, the drag may take that
|
|
4098
4211
|
// column's units but not its last one. Without one, the row is
|
|
@@ -4114,12 +4227,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4114
4227
|
function balanceSibling(col) {
|
|
4115
4228
|
if (settings.resize.balance !== 'next') { return null; }
|
|
4116
4229
|
|
|
4117
|
-
|
|
4118
|
-
return next.length ? next : null;
|
|
4230
|
+
return dom.nextAll(col, '.column')[0] || null;
|
|
4119
4231
|
}
|
|
4120
4232
|
|
|
4121
4233
|
function resizeReadout(col, text) {
|
|
4122
|
-
|
|
4234
|
+
var drawer = dom.child(col, '.ge-tools-drawer');
|
|
4235
|
+
var readout = drawer ? dom.child(drawer, '.ge-resize-size') : null;
|
|
4236
|
+
if (readout) { readout.textContent = text; }
|
|
4123
4237
|
}
|
|
4124
4238
|
|
|
4125
4239
|
function sizeLabel(units) {
|
|
@@ -4145,9 +4259,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4145
4259
|
|
|
4146
4260
|
if (!allowed) { return false; }
|
|
4147
4261
|
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
resizeReadout(col, sizeLabel(
|
|
4262
|
+
var resize = { from: from, units: currentUnits(col) };
|
|
4263
|
+
resizes.set(col, resize);
|
|
4264
|
+
resizeReadout(col, sizeLabel(resize.units));
|
|
4151
4265
|
|
|
4152
4266
|
return true;
|
|
4153
4267
|
}
|
|
@@ -4157,44 +4271,40 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4157
4271
|
}
|
|
4158
4272
|
|
|
4159
4273
|
function resizeStop(col, width) {
|
|
4160
|
-
var
|
|
4161
|
-
var started = col.data('ge-resize-units');
|
|
4274
|
+
var resize = resizes.get(col);
|
|
4162
4275
|
var units = snapUnits(col, width);
|
|
4163
4276
|
|
|
4164
|
-
|
|
4277
|
+
resizes.delete(col);
|
|
4165
4278
|
resizeReadout(col, '');
|
|
4166
4279
|
stripPixelWidths(col);
|
|
4167
4280
|
|
|
4168
|
-
if (
|
|
4281
|
+
if (!resize) { return; }
|
|
4169
4282
|
|
|
4170
4283
|
// A drag of a couple of pixels lands on the size it started from,
|
|
4171
4284
|
// and is not a resize - not even of an equal or auto column,
|
|
4172
4285
|
// which it would otherwise turn into a number
|
|
4173
|
-
if (units ===
|
|
4286
|
+
if (units === resize.units) { return; }
|
|
4174
4287
|
|
|
4175
4288
|
var plan = planSize(col, units);
|
|
4176
4289
|
if (!plan) { return; }
|
|
4177
4290
|
|
|
4178
4291
|
operate(function() {
|
|
4179
4292
|
writeSize(col, plan);
|
|
4180
|
-
balanceAfterResize(col, units -
|
|
4293
|
+
balanceAfterResize(col, units - resize.units);
|
|
4181
4294
|
refreshUtilities(col);
|
|
4182
4295
|
|
|
4183
4296
|
emit('after-resize', payloadFor('column', col, withCleared({
|
|
4184
4297
|
source: 'dragdrop',
|
|
4185
|
-
from: from,
|
|
4298
|
+
from: resize.from,
|
|
4186
4299
|
to: plan.size,
|
|
4187
4300
|
}, plan.cleared)));
|
|
4188
4301
|
});
|
|
4189
4302
|
}
|
|
4190
4303
|
|
|
4191
|
-
/**
|
|
4192
|
-
* Move the delta into the following column, so a full row stays full.
|
|
4193
|
-
* It is part of the same gesture, so it is not announced separately.
|
|
4194
|
-
*/
|
|
4195
4304
|
/**
|
|
4196
4305
|
* The column after takes what the resized one gave or took, unless it
|
|
4197
|
-
* is equal or auto: those take what is left by themselves.
|
|
4306
|
+
* is equal or auto: those take what is left by themselves. It is part
|
|
4307
|
+
* of the same gesture, so it is not announced separately.
|
|
4198
4308
|
*/
|
|
4199
4309
|
function balanceAfterResize(col, delta) {
|
|
4200
4310
|
var next = balanceSibling(col);
|
|
@@ -4218,13 +4328,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4218
4328
|
* is none of the editor's business.
|
|
4219
4329
|
*/
|
|
4220
4330
|
function removeSortable() {
|
|
4221
|
-
|
|
4331
|
+
sortables.forEach(function(sortableInstance) { sortableInstance.destroy(); });
|
|
4222
4332
|
|
|
4223
4333
|
sortables = [];
|
|
4224
4334
|
}
|
|
4225
4335
|
|
|
4226
4336
|
function createRow() {
|
|
4227
|
-
return
|
|
4337
|
+
return dom.element('div', { 'class': 'row' });
|
|
4228
4338
|
}
|
|
4229
4339
|
|
|
4230
4340
|
/**
|
|
@@ -4234,6 +4344,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4234
4344
|
* detached, and placing it and calling reset() is the host's job
|
|
4235
4345
|
* (spec 1.2).
|
|
4236
4346
|
*
|
|
4347
|
+
* The place is an element, or the first one a selector matches.
|
|
4237
4348
|
* Returns the node, or null when a handler canceled the add. A call
|
|
4238
4349
|
* made from inside an event handler is queued, and then returns the
|
|
4239
4350
|
* node without knowing yet whether the add will be canceled.
|
|
@@ -4249,14 +4360,27 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4249
4360
|
|
|
4250
4361
|
if (placement === null) { return node; }
|
|
4251
4362
|
|
|
4252
|
-
var target =
|
|
4363
|
+
var target = nodeFrom(options[placement]);
|
|
4364
|
+
if (!target) {
|
|
4365
|
+
warn(kind + ': ' + placement + ' matches no element; the ' + kind + ' is left detached');
|
|
4366
|
+
return node;
|
|
4367
|
+
}
|
|
4368
|
+
|
|
4253
4369
|
var parent = (placement === 'appendTo' || placement === 'prependTo')
|
|
4254
4370
|
? target
|
|
4255
|
-
: target.
|
|
4371
|
+
: target.parentElement;
|
|
4256
4372
|
|
|
4257
4373
|
var add = function() {
|
|
4258
4374
|
return addNode(kind, node, function() {
|
|
4259
|
-
|
|
4375
|
+
if (placement === 'appendTo') {
|
|
4376
|
+
target.appendChild(node);
|
|
4377
|
+
} else if (placement === 'prependTo') {
|
|
4378
|
+
target.insertBefore(node, target.firstChild);
|
|
4379
|
+
} else if (placement === 'insertBefore') {
|
|
4380
|
+
target.parentNode.insertBefore(node, target);
|
|
4381
|
+
} else {
|
|
4382
|
+
dom.insertAfter(node, target);
|
|
4383
|
+
}
|
|
4260
4384
|
}, { parent: parent, source: options.source || 'api' });
|
|
4261
4385
|
};
|
|
4262
4386
|
|
|
@@ -4283,7 +4407,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4283
4407
|
if (layout && !Array.isArray(layout)) { row = rowFromLayoutValue(layout); }
|
|
4284
4408
|
|
|
4285
4409
|
(Array.isArray(layout) ? layout : []).forEach(function(size) {
|
|
4286
|
-
createColumn(size)
|
|
4410
|
+
row.appendChild(createColumn(size));
|
|
4287
4411
|
});
|
|
4288
4412
|
|
|
4289
4413
|
return place(row, 'row', options);
|
|
@@ -4296,9 +4420,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4296
4420
|
options = options || {};
|
|
4297
4421
|
|
|
4298
4422
|
// Going into a row with row-cols, no size is a size: the row's share
|
|
4299
|
-
var into =
|
|
4423
|
+
var into = nodeFrom(options.appendTo || options.prependTo || null);
|
|
4300
4424
|
|
|
4301
|
-
if (size === undefined && into
|
|
4425
|
+
if (size === undefined && into && rowColsSource(into, leadingTier())) {
|
|
4302
4426
|
size = null;
|
|
4303
4427
|
} else if (!isUnits(size) && FLEX_SIZES.indexOf(size) === -1) {
|
|
4304
4428
|
warn('createColumn: no column size given, using ' + MAX_COL_SIZE);
|
|
@@ -4307,7 +4431,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4307
4431
|
|
|
4308
4432
|
var column = createColumn(size, options.offset);
|
|
4309
4433
|
if (options.content !== undefined) {
|
|
4310
|
-
column.
|
|
4434
|
+
column.appendChild(contentFor(options.content));
|
|
4311
4435
|
}
|
|
4312
4436
|
|
|
4313
4437
|
return place(column, 'column', options);
|
|
@@ -4330,7 +4454,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4330
4454
|
|
|
4331
4455
|
/** A pane appended to a container, through the add events. */
|
|
4332
4456
|
function addPaneTo(container, type, options) {
|
|
4333
|
-
container =
|
|
4457
|
+
container = nodeFrom(container);
|
|
4334
4458
|
options = options || {};
|
|
4335
4459
|
|
|
4336
4460
|
var definition = CONTAINERS[containerTypeOf(container)];
|
|
@@ -4350,20 +4474,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4350
4474
|
}
|
|
4351
4475
|
|
|
4352
4476
|
/**
|
|
4353
|
-
*
|
|
4354
|
-
*
|
|
4355
|
-
*/
|
|
4356
|
-
|
|
4357
|
-
/**
|
|
4358
|
-
* A shallow frozen copy of the settings for the instance handle, so a
|
|
4359
|
-
* host can read what the editor is running with without changing it
|
|
4477
|
+
* A shallow frozen copy of the settings for the instance, so a host
|
|
4478
|
+
* can read what the editor is running with without changing it
|
|
4360
4479
|
* behind the editor's back. Arrays are copied; the objects inside them
|
|
4361
4480
|
* are the host's own and stay shared.
|
|
4362
4481
|
*/
|
|
4363
4482
|
function settingsCopy() {
|
|
4364
4483
|
var copy = {};
|
|
4365
4484
|
|
|
4366
|
-
|
|
4485
|
+
Object.keys(settings).forEach(function(key) {
|
|
4486
|
+
var value = settings[key];
|
|
4367
4487
|
copy[key] = Array.isArray(value) ? value.slice() : value;
|
|
4368
4488
|
});
|
|
4369
4489
|
|
|
@@ -4377,7 +4497,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4377
4497
|
function createColumn(size, offset) {
|
|
4378
4498
|
// Empty: what goes in it is the next decision, and the tools of
|
|
4379
4499
|
// the column and the toolbar are where it is made
|
|
4380
|
-
var column =
|
|
4500
|
+
var column = dom.element('div', { 'class': 'column' });
|
|
4381
4501
|
|
|
4382
4502
|
// The tier being edited, or the base class in the all view
|
|
4383
4503
|
var tier = tiersFor(curView)[0];
|
|
@@ -4390,18 +4510,24 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4390
4510
|
}
|
|
4391
4511
|
|
|
4392
4512
|
/**
|
|
4393
|
-
* Run custom content filter on init and deinit
|
|
4513
|
+
* Run custom content filter on init and deinit. A filter is a
|
|
4514
|
+
* function, or the name of one on window, and gets the canvas and
|
|
4515
|
+
* whether this is init.
|
|
4394
4516
|
*/
|
|
4395
4517
|
function runFilter(isInit) {
|
|
4396
|
-
if (settings.custom_filter.length) {
|
|
4397
|
-
$.each(settings.custom_filter, function(key, func) {
|
|
4398
|
-
if (typeof func == 'string') {
|
|
4399
|
-
func = window[func];
|
|
4400
|
-
}
|
|
4518
|
+
if (!settings.custom_filter || !settings.custom_filter.length) { return; }
|
|
4401
4519
|
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4520
|
+
var filters = typeof settings.custom_filter === 'string' || typeof settings.custom_filter === 'function'
|
|
4521
|
+
? [settings.custom_filter]
|
|
4522
|
+
: settings.custom_filter;
|
|
4523
|
+
|
|
4524
|
+
Array.prototype.forEach.call(filters, function(func) {
|
|
4525
|
+
if (typeof func == 'string') {
|
|
4526
|
+
func = window[func];
|
|
4527
|
+
}
|
|
4528
|
+
|
|
4529
|
+
func(canvas, isInit);
|
|
4530
|
+
});
|
|
4405
4531
|
}
|
|
4406
4532
|
|
|
4407
4533
|
/**
|
|
@@ -4412,7 +4538,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4412
4538
|
function textCutter() {
|
|
4413
4539
|
var cuts = ['.row', '[data-ge-container]'];
|
|
4414
4540
|
|
|
4415
|
-
|
|
4541
|
+
Object.keys(FEATURES).forEach(function(name) {
|
|
4542
|
+
var feature = FEATURES[name];
|
|
4416
4543
|
var cut = typeof feature.cuts === 'function' ? feature.cuts() : feature.cuts;
|
|
4417
4544
|
if (cut) { cuts.push(cut); }
|
|
4418
4545
|
});
|
|
@@ -4438,17 +4565,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4438
4565
|
* content area its editor is open on is left for the next init.
|
|
4439
4566
|
*/
|
|
4440
4567
|
function splitTexts(cutter) {
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
if (area.hasClass('ge-rte-active') || !area.children().filter(cutter).length) { return; }
|
|
4568
|
+
dom.all(canvas, '.column > .ge-content, .column > .ge-text-block > .ge-content').forEach(function(area) {
|
|
4569
|
+
if (dom.hasClass(area, 'ge-rte-active') || !dom.children(area, cutter).length) { return; }
|
|
4444
4570
|
|
|
4445
|
-
var type = area.
|
|
4446
|
-
var anchor = area.
|
|
4571
|
+
var type = area.getAttribute('data-ge-content-type');
|
|
4572
|
+
var anchor = dom.hasClass(area.parentElement, 'ge-text-block') ? area.parentElement : area;
|
|
4447
4573
|
var pieces = [];
|
|
4448
4574
|
var run = [];
|
|
4449
4575
|
|
|
4450
|
-
|
|
4451
|
-
if (node.nodeType === 1 &&
|
|
4576
|
+
Array.prototype.slice.call(area.childNodes).forEach(function(node) {
|
|
4577
|
+
if (node.nodeType === 1 && node.matches(cutter)) {
|
|
4452
4578
|
pieces.push({ text: run }, { block: node });
|
|
4453
4579
|
run = [];
|
|
4454
4580
|
} else {
|
|
@@ -4457,7 +4583,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4457
4583
|
});
|
|
4458
4584
|
pieces.push({ text: run });
|
|
4459
4585
|
|
|
4460
|
-
|
|
4586
|
+
while (area.firstChild) { area.removeChild(area.firstChild); }
|
|
4461
4587
|
|
|
4462
4588
|
var kept = false;
|
|
4463
4589
|
var last = anchor;
|
|
@@ -4466,21 +4592,22 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4466
4592
|
var placed;
|
|
4467
4593
|
|
|
4468
4594
|
if (piece.block) {
|
|
4469
|
-
placed =
|
|
4595
|
+
placed = piece.block;
|
|
4470
4596
|
} else if (!hasContent(piece.text)) {
|
|
4471
4597
|
return;
|
|
4472
4598
|
} else if (kept) {
|
|
4473
4599
|
// Of the same type, or of none if it had none
|
|
4474
|
-
placed = createDefaultContentWrapper(type)
|
|
4600
|
+
placed = createDefaultContentWrapper(type);
|
|
4601
|
+
piece.text.forEach(function(node) { placed.appendChild(node); });
|
|
4475
4602
|
} else {
|
|
4476
4603
|
// The content area itself, moved along if an
|
|
4477
4604
|
// element came before the first text
|
|
4478
|
-
|
|
4605
|
+
piece.text.forEach(function(node) { area.appendChild(node); });
|
|
4479
4606
|
placed = anchor;
|
|
4480
4607
|
kept = true;
|
|
4481
4608
|
}
|
|
4482
4609
|
|
|
4483
|
-
if (placed
|
|
4610
|
+
if (placed !== last) { dom.insertAfter(placed, last); }
|
|
4484
4611
|
last = placed;
|
|
4485
4612
|
});
|
|
4486
4613
|
|
|
@@ -4499,26 +4626,23 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4499
4626
|
* Wrap column content in <div class="ge-content"> where neccesary
|
|
4500
4627
|
*/
|
|
4501
4628
|
function wrapContent(cutter) {
|
|
4502
|
-
|
|
4503
|
-
var
|
|
4504
|
-
var contents = $();
|
|
4505
|
-
|
|
4506
|
-
col.children().each(function() {
|
|
4507
|
-
var child = $(this);
|
|
4629
|
+
dom.all(canvas, '.column').forEach(function(col) {
|
|
4630
|
+
var contents = [];
|
|
4508
4631
|
|
|
4632
|
+
dom.children(col).forEach(function(child) {
|
|
4509
4633
|
// The editor's own furniture is not content and not a
|
|
4510
4634
|
// boundary either. The resize handle used to be treated as
|
|
4511
4635
|
// content and wrapped into a content area of its own on
|
|
4512
4636
|
// the next init.
|
|
4513
|
-
if (
|
|
4637
|
+
if (dom.is(child, '.ge-tools-drawer, .ge-resize-handle')) { return; }
|
|
4514
4638
|
|
|
4515
4639
|
// A container, or an element, sits in the column beside
|
|
4516
4640
|
// the content areas, not inside one, so it ends a run of
|
|
4517
4641
|
// loose content rather than joining it
|
|
4518
|
-
if (
|
|
4642
|
+
if (dom.is(child, '.ge-content, .ge-text-block') || child.matches(cutter)) {
|
|
4519
4643
|
contents = doWrap(contents);
|
|
4520
4644
|
} else {
|
|
4521
|
-
contents
|
|
4645
|
+
contents.push(child);
|
|
4522
4646
|
}
|
|
4523
4647
|
});
|
|
4524
4648
|
|
|
@@ -4529,17 +4653,17 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4529
4653
|
/**
|
|
4530
4654
|
* Wrap a run of loose column content in a content area of no type -
|
|
4531
4655
|
* the host's plain content - and hand back
|
|
4532
|
-
* an empty
|
|
4656
|
+
* an empty run: the caller has to forget what it just wrapped, or the
|
|
4533
4657
|
* next boundary wraps the same nodes again and leaves the first
|
|
4534
4658
|
* wrapper behind, empty.
|
|
4535
4659
|
*/
|
|
4536
4660
|
function doWrap(contents) {
|
|
4537
4661
|
if (contents.length) {
|
|
4538
|
-
var contentArea = createDefaultContentWrapper()
|
|
4539
|
-
contents.
|
|
4662
|
+
var contentArea = dom.insertAfter(createDefaultContentWrapper(), contents[contents.length - 1]);
|
|
4663
|
+
contents.forEach(function(node) { contentArea.appendChild(node); });
|
|
4540
4664
|
}
|
|
4541
4665
|
|
|
4542
|
-
return
|
|
4666
|
+
return [];
|
|
4543
4667
|
}
|
|
4544
4668
|
|
|
4545
4669
|
/**
|
|
@@ -4547,10 +4671,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4547
4671
|
* content: a content area and nothing more.
|
|
4548
4672
|
*/
|
|
4549
4673
|
function createDefaultContentWrapper(type) {
|
|
4550
|
-
var contentArea =
|
|
4674
|
+
var contentArea = dom.element('div', { 'class': 'ge-content' });
|
|
4551
4675
|
|
|
4552
4676
|
if (type) {
|
|
4553
|
-
|
|
4677
|
+
dom.addClass(contentArea, 'ge-content-type-' + type);
|
|
4678
|
+
contentArea.setAttribute('data-ge-content-type', type);
|
|
4554
4679
|
}
|
|
4555
4680
|
|
|
4556
4681
|
return contentArea;
|
|
@@ -4575,15 +4700,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4575
4700
|
* -------------------------------------------------------------- */
|
|
4576
4701
|
|
|
4577
4702
|
function wrapTexts() {
|
|
4578
|
-
|
|
4579
|
-
|
|
4703
|
+
dom.all(canvas, '.column > .ge-content').forEach(function(area) {
|
|
4704
|
+
dom.wrap(area, dom.element('div', { 'class': 'ge-text-block' }));
|
|
4580
4705
|
});
|
|
4581
4706
|
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
if (textBlock.children('.ge-tools-drawer').length) { return; }
|
|
4707
|
+
dom.all(canvas, '.ge-text-block').forEach(function(textBlock) {
|
|
4708
|
+
if (dom.child(textBlock, '.ge-tools-drawer')) { return; }
|
|
4585
4709
|
|
|
4586
|
-
var
|
|
4710
|
+
var area = dom.child(textBlock, '.ge-content');
|
|
4711
|
+
var type = area ? area.getAttribute('data-ge-content-type') : null;
|
|
4587
4712
|
|
|
4588
4713
|
if (!type) {
|
|
4589
4714
|
createPlainControls(textBlock);
|
|
@@ -4595,28 +4720,28 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4595
4720
|
|
|
4596
4721
|
/** After the drawers are gone, so a wrapper holds its content area and nothing else. */
|
|
4597
4722
|
function unwrapTexts() {
|
|
4598
|
-
|
|
4599
|
-
|
|
4723
|
+
dom.all(canvas, '.ge-text-block').forEach(function(textBlock) {
|
|
4724
|
+
dom.unwrap(textBlock);
|
|
4600
4725
|
});
|
|
4601
4726
|
}
|
|
4602
4727
|
|
|
4603
4728
|
/** The host's plain content: moved and deleted here, edited in the source. */
|
|
4604
4729
|
function createPlainControls(textBlock) {
|
|
4605
|
-
var block =
|
|
4606
|
-
var drawer =
|
|
4607
|
-
|
|
4730
|
+
var block = dom.child(textBlock, '.ge-content');
|
|
4731
|
+
var drawer = prependDrawer(textBlock, 'ge-tools-drawer ge-text-drawer ge-plain-drawer');
|
|
4732
|
+
dom.addClass(textBlock, 'ge-plain-block');
|
|
4608
4733
|
|
|
4609
4734
|
createMoveTool(drawer);
|
|
4610
4735
|
|
|
4611
4736
|
// The tools a feature plugin gives plain content, which is not
|
|
4612
4737
|
// every plugin's drawerTools: no gear, no utilities, no copy
|
|
4613
|
-
|
|
4614
|
-
if (
|
|
4738
|
+
Object.keys(FEATURES).forEach(function(name) {
|
|
4739
|
+
if (FEATURES[name].plainTools) { FEATURES[name].plainTools(drawer, block); }
|
|
4615
4740
|
});
|
|
4616
4741
|
|
|
4617
4742
|
createTool(drawer, t('tool.delete_plain'), 'ge-delete-plain', 'bi bi-trash', function() {
|
|
4618
4743
|
deleteNode('plain', block, t('confirm.delete_plain'), function(removed) {
|
|
4619
|
-
|
|
4744
|
+
dom.slideUp(textBlock, function() {
|
|
4620
4745
|
textBlock.remove();
|
|
4621
4746
|
removed();
|
|
4622
4747
|
});
|
|
@@ -4629,15 +4754,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4629
4754
|
* and its drawer says why it cannot be edited.
|
|
4630
4755
|
*/
|
|
4631
4756
|
function createOrphanControls(textBlock, type) {
|
|
4632
|
-
var block =
|
|
4633
|
-
var drawer =
|
|
4757
|
+
var block = dom.child(textBlock, '.ge-content');
|
|
4758
|
+
var drawer = prependDrawer(textBlock, 'ge-tools-drawer ge-text-drawer');
|
|
4634
4759
|
|
|
4635
4760
|
createMoveTool(drawer);
|
|
4636
4761
|
createTool(drawer, t('text.no_editor', { type: type }), 'ge-text-info ge-text-missing',
|
|
4637
4762
|
'bi bi-exclamation-triangle');
|
|
4638
4763
|
createTool(drawer, t('tool.delete_text'), 'ge-delete-text', 'bi bi-trash', function() {
|
|
4639
4764
|
deleteNode('text', block, t('confirm.delete_text'), function(removed) {
|
|
4640
|
-
|
|
4765
|
+
dom.slideUp(textBlock, function() {
|
|
4641
4766
|
textBlock.remove();
|
|
4642
4767
|
removed();
|
|
4643
4768
|
});
|
|
@@ -4646,13 +4771,21 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4646
4771
|
}
|
|
4647
4772
|
|
|
4648
4773
|
/**
|
|
4649
|
-
* A detached content area holding `content
|
|
4650
|
-
* offered, or the host's plain content when no
|
|
4774
|
+
* A detached content area holding `content` - html, or a node - as a
|
|
4775
|
+
* text of the first type offered, or the host's plain content when no
|
|
4776
|
+
* editor is offered.
|
|
4651
4777
|
*/
|
|
4652
4778
|
function contentFor(content) {
|
|
4653
4779
|
var offers = textOffers();
|
|
4780
|
+
var area = createDefaultContentWrapper(offers.length ? offers[0].type : null);
|
|
4781
|
+
|
|
4782
|
+
if (content && content.nodeType) {
|
|
4783
|
+
area.appendChild(content);
|
|
4784
|
+
} else {
|
|
4785
|
+
dom.setHtml(area, content);
|
|
4786
|
+
}
|
|
4654
4787
|
|
|
4655
|
-
return
|
|
4788
|
+
return area;
|
|
4656
4789
|
}
|
|
4657
4790
|
|
|
4658
4791
|
/**
|
|
@@ -4664,9 +4797,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4664
4797
|
curView = view;
|
|
4665
4798
|
|
|
4666
4799
|
VIEW_KEYS.forEach(function(key) {
|
|
4667
|
-
|
|
4800
|
+
dom.toggleClass(canvas, 'ge-layout-' + key, key === view);
|
|
4668
4801
|
});
|
|
4669
|
-
|
|
4802
|
+
dom.one(layoutDropdown, 'button').textContent = t(labelKeyFor(view));
|
|
4670
4803
|
}
|
|
4671
4804
|
|
|
4672
4805
|
/**
|
|
@@ -4699,7 +4832,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4699
4832
|
|
|
4700
4833
|
if (key === from) { return; }
|
|
4701
4834
|
|
|
4702
|
-
settingsScope().
|
|
4835
|
+
settingsScope().forEach(function(scope) {
|
|
4836
|
+
dom.all(scope, '.ge-utilities').forEach(function(section) { renderUtilities(section); });
|
|
4837
|
+
});
|
|
4703
4838
|
refreshPreviews(canvas);
|
|
4704
4839
|
plugins('onViewChange', key);
|
|
4705
4840
|
emit('view-change', { canvas: canvas, breakpoint: key, from: from, to: key });
|
|
@@ -4708,22 +4843,33 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4708
4843
|
function getView() {
|
|
4709
4844
|
return curView;
|
|
4710
4845
|
}
|
|
4711
|
-
|
|
4846
|
+
|
|
4847
|
+
/** A method a feature plugin contributes, or a warning that the plugin is not loaded. */
|
|
4848
|
+
function featureMethod(name, plugin, file) {
|
|
4849
|
+
return function() {
|
|
4850
|
+
if (!featureMethods[name]) {
|
|
4851
|
+
warnOnceHere('plugin:' + plugin, name + ' needs the ' + plugin + ' plugin: ' +
|
|
4852
|
+
'include dist/plugins/grideditor.' + file + '.js after the editor');
|
|
4853
|
+
return null;
|
|
4854
|
+
}
|
|
4855
|
+
|
|
4856
|
+
return featureMethods[name].apply(null, arguments);
|
|
4857
|
+
};
|
|
4858
|
+
}
|
|
4859
|
+
|
|
4712
4860
|
/**
|
|
4713
|
-
* The instance
|
|
4714
|
-
*
|
|
4715
|
-
*
|
|
4861
|
+
* The instance's own methods: the documented API. init and reset are
|
|
4862
|
+
* deferred when a handler calls them, so an operation in flight
|
|
4863
|
+
* finishes before the canvas is rebuilt. The ones that do something,
|
|
4864
|
+
* rather than answer something, hand back the instance, to chain.
|
|
4716
4865
|
*/
|
|
4717
|
-
var
|
|
4866
|
+
var own = {
|
|
4718
4867
|
getHtml: getHtml,
|
|
4719
4868
|
getPlainHtml: getPlainHtml,
|
|
4720
|
-
// init and reset are deferred when a handler calls them, so an
|
|
4721
|
-
// operation in flight finishes before the canvas is rebuilt
|
|
4722
4869
|
init: function() { defer(init); },
|
|
4723
4870
|
reset: function() { defer(reset); },
|
|
4724
4871
|
deinit: deinit,
|
|
4725
4872
|
destroy: destroy,
|
|
4726
|
-
remove: deprecatedRemove,
|
|
4727
4873
|
changeView: changeView,
|
|
4728
4874
|
getView: getView,
|
|
4729
4875
|
createRow: apiCreateRow,
|
|
@@ -4737,24 +4883,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4737
4883
|
|
|
4738
4884
|
return featureMethods.createText(type, options);
|
|
4739
4885
|
},
|
|
4740
|
-
createElement:
|
|
4741
|
-
|
|
4742
|
-
warnOnceHere('plugin:elements', 'createElement needs the elements plugin: ' +
|
|
4743
|
-
'include dist/plugins/grideditor.elements.js after the editor');
|
|
4744
|
-
return null;
|
|
4745
|
-
}
|
|
4746
|
-
|
|
4747
|
-
return featureMethods.createElement(content, options);
|
|
4748
|
-
},
|
|
4749
|
-
createSection: function(options) {
|
|
4750
|
-
if (!featureMethods.createSection) {
|
|
4751
|
-
warnOnceHere('plugin:sections', 'createSection needs the sections plugin: ' +
|
|
4752
|
-
'include dist/plugins/grideditor.sections.js after the editor');
|
|
4753
|
-
return null;
|
|
4754
|
-
}
|
|
4755
|
-
|
|
4756
|
-
return featureMethods.createSection(options);
|
|
4757
|
-
},
|
|
4886
|
+
createElement: featureMethod('createElement', 'elements', 'elements'),
|
|
4887
|
+
createSection: featureMethod('createSection', 'sections', 'sections'),
|
|
4758
4888
|
createContainer: apiCreateContainer,
|
|
4759
4889
|
addTab: function(container, options) { return addPaneTo(container, 'tabs', options); },
|
|
4760
4890
|
addAccordionItem: function(container, options) {
|
|
@@ -4763,42 +4893,45 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4763
4893
|
setLocale: setLocale,
|
|
4764
4894
|
getUtility: getUtility,
|
|
4765
4895
|
setUtility: setUtility,
|
|
4766
|
-
canvas: canvas,
|
|
4767
|
-
settings: settingsCopy(),
|
|
4768
4896
|
};
|
|
4769
4897
|
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
$.each(METHODS, function(name, descriptor) {
|
|
4773
|
-
if (!descriptor.unimplemented) { return; }
|
|
4898
|
+
Object.keys(own).forEach(function(name) {
|
|
4899
|
+
var value = !!(METHODS[name] && METHODS[name].value);
|
|
4774
4900
|
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4901
|
+
instance[name] = function() {
|
|
4902
|
+
if (destroyed) {
|
|
4903
|
+
warnOnceHere('destroyed:' + name, t('warning.destroyed', { method: name }));
|
|
4904
|
+
if (name === 'getHtml') { return canvas.innerHTML; }
|
|
4905
|
+
if (name === 'getPlainHtml') { return plainHtml(canvas.innerHTML); }
|
|
4906
|
+
return value ? null : instance;
|
|
4907
|
+
}
|
|
4908
|
+
|
|
4909
|
+
var result = own[name].apply(instance, arguments);
|
|
4910
|
+
return value ? result : instance;
|
|
4778
4911
|
};
|
|
4779
4912
|
});
|
|
4780
4913
|
|
|
4781
|
-
|
|
4914
|
+
instance.canvas = canvas;
|
|
4915
|
+
instance.settings = settingsCopy();
|
|
4916
|
+
|
|
4917
|
+
instances.set(canvas, instance);
|
|
4782
4918
|
|
|
4783
4919
|
loadPlugins();
|
|
4784
4920
|
// Again, with what the plugins filled in: the text editors'
|
|
4785
4921
|
// content_types when the host gave none
|
|
4786
|
-
|
|
4922
|
+
instance.settings = settingsCopy();
|
|
4787
4923
|
setup();
|
|
4788
4924
|
init();
|
|
4789
4925
|
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
return self;
|
|
4793
|
-
|
|
4794
|
-
};
|
|
4926
|
+
GridEditor._created.forEach(function(hook) { hook(instance); });
|
|
4927
|
+
}
|
|
4795
4928
|
|
|
4796
4929
|
/**
|
|
4797
|
-
*
|
|
4798
|
-
*
|
|
4799
|
-
*
|
|
4930
|
+
* What a module that builds on the editor - the jQuery adapter - is told:
|
|
4931
|
+
* each editor as it is made. Not the plugin contract; a plugin is handed
|
|
4932
|
+
* the editor through its factory.
|
|
4800
4933
|
*/
|
|
4801
|
-
|
|
4934
|
+
GridEditor._created = [];
|
|
4802
4935
|
|
|
4803
4936
|
/**
|
|
4804
4937
|
* Container plugins: tabs, accordions, popups, and whatever a host writes.
|
|
@@ -4807,11 +4940,11 @@ $.fn.gridEditor.RTEs = {};
|
|
|
4807
4940
|
* editor with the handle described in docs/plugins.md. Loading its file is
|
|
4808
4941
|
* what makes the type available; the `plugins` setting narrows that list.
|
|
4809
4942
|
*
|
|
4810
|
-
*
|
|
4943
|
+
* GridEditor.containers.carousel = function(ge) {
|
|
4811
4944
|
* return { labelKey: ..., create: ..., mark: ..., unmark: ... };
|
|
4812
4945
|
* };
|
|
4813
4946
|
*/
|
|
4814
|
-
|
|
4947
|
+
GridEditor.containers = {};
|
|
4815
4948
|
|
|
4816
4949
|
/**
|
|
4817
4950
|
* Feature plugins: a piece of the editor that is not a container type, in a
|
|
@@ -4820,7 +4953,7 @@ $.fn.gridEditor.containers = {};
|
|
|
4820
4953
|
* the handle in docs/plugins.md - and the same `plugins` setting decides
|
|
4821
4954
|
* which of the loaded ones are used.
|
|
4822
4955
|
*/
|
|
4823
|
-
|
|
4956
|
+
GridEditor.features = {};
|
|
4824
4957
|
|
|
4825
4958
|
/**
|
|
4826
4959
|
* Utility plugins: Bootstrap's responsive utility classes - order-md-2,
|
|
@@ -4828,14 +4961,35 @@ $.fn.gridEditor.features = {};
|
|
|
4828
4961
|
* and the editor reads them, writes them, puts them in the settings panel and
|
|
4829
4962
|
* previews them in each view. Same factory, same `plugins` setting.
|
|
4830
4963
|
*
|
|
4831
|
-
*
|
|
4964
|
+
* GridEditor.utilities.order = function(ge) {
|
|
4832
4965
|
* return { families: [{ name: 'order', prefix: 'order', values: [...] }] };
|
|
4833
4966
|
* };
|
|
4834
4967
|
*/
|
|
4835
|
-
|
|
4968
|
+
GridEditor.utilities = {};
|
|
4969
|
+
|
|
4970
|
+
/**
|
|
4971
|
+
* The text editors, by the content type each edits: what the text plugins
|
|
4972
|
+
* (tinymce, ckeditor, summernote, a host's own) register, and the text
|
|
4973
|
+
* feature, src/js/text/grideditor.text.js, reads.
|
|
4974
|
+
*/
|
|
4975
|
+
GridEditor.texts = {};
|
|
4976
|
+
|
|
4977
|
+
/** Translator for the plugins, which get settings and no instance. */
|
|
4978
|
+
GridEditor.t = translate;
|
|
4979
|
+
|
|
4980
|
+
/** getPlainHtml for html that is not on a canvas, for the jQuery adapter. Not the public API. */
|
|
4981
|
+
GridEditor._plainHtml = plainHtml;
|
|
4982
|
+
|
|
4983
|
+
/**
|
|
4984
|
+
* SortableJS and Bootstrap's javascript, for a page that imports them as
|
|
4985
|
+
* modules and so has no window.Sortable or window.bootstrap. Looked up
|
|
4986
|
+
* before the globals; only Bootstrap's Modal is used.
|
|
4987
|
+
*/
|
|
4988
|
+
GridEditor.Sortable = null;
|
|
4989
|
+
GridEditor.bootstrap = null;
|
|
4836
4990
|
|
|
4837
|
-
/**
|
|
4838
|
-
|
|
4991
|
+
/** The version of the build, filled in by build/build.js. */
|
|
4992
|
+
GridEditor.version = typeof __GRIDEDITOR_VERSION__ === 'undefined' ? 'dev' : __GRIDEDITOR_VERSION__;
|
|
4839
4993
|
|
|
4840
4994
|
/**
|
|
4841
4995
|
* Locale registry: code -> { key: string }.
|
|
@@ -4848,7 +5002,7 @@ $.fn.gridEditor.t = translate;
|
|
|
4848
5002
|
* Every key is listed in docs/locale-keys.md, which test/locales.js holds to
|
|
4849
5003
|
* this catalogue in both directions.
|
|
4850
5004
|
*/
|
|
4851
|
-
|
|
5005
|
+
GridEditor.locales = {
|
|
4852
5006
|
en: {
|
|
4853
5007
|
'tool.move': 'Move',
|
|
4854
5008
|
'tool.settings': 'Settings',
|
|
@@ -4918,10 +5072,16 @@ $.fn.gridEditor.locales = {
|
|
|
4918
5072
|
'utility.varies': 'Changes at {breakpoints}; choosing here replaces that',
|
|
4919
5073
|
'error.sortable_missing': 'SortableJS not available! Make sure you loaded the Sortable js file; dragging is off without it.',
|
|
4920
5074
|
'warning.setting_removed': 'The {setting} setting was removed in 4.0. Use {replacement} instead.',
|
|
5075
|
+
'warning.already_editing': 'This element already has an editor: that one is handed back, with the options it was made with.',
|
|
5076
|
+
'warning.destroyed': '{method}() was called on an editor that has been destroyed, and does nothing.',
|
|
5077
|
+
'warning.duplicate_build': 'grideditor.js was loaded twice: the first GridEditor is kept.',
|
|
5078
|
+
'warning.plugin_6x': 'The "{name}" plugin is written for grid-editor 6 and is not loaded. Plugins register on GridEditor since 7.0: see UPGRADING.md.',
|
|
5079
|
+
'warning.adapter_no_jquery': 'grideditor.jquery.js needs jQuery 4, and there is no jQuery on the page: the jQuery API is not there.',
|
|
4921
5080
|
'error.tinymce_missing': 'tinyMCE not available! Make sure you loaded the tinyMCE js file.',
|
|
4922
|
-
'error.ckeditor_missing': 'CKEditor not available! Make sure you loaded the
|
|
4923
|
-
'error.summernote_missing': 'Summernote not available! Make sure you loaded the Summernote js file.',
|
|
5081
|
+
'error.ckeditor_missing': 'CKEditor not available! Make sure you loaded the CKEditor js file.',
|
|
5082
|
+
'error.summernote_missing': 'Summernote not available! Make sure you loaded jQuery and the Summernote js file.',
|
|
4924
5083
|
},
|
|
4925
5084
|
};
|
|
4926
5085
|
|
|
4927
|
-
|
|
5086
|
+
export { GridEditor };
|
|
5087
|
+
export default GridEditor;
|