@themarioga/grid-editor 8.3.0 → 8.4.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/CHANGELOG.md +22 -0
- package/README.md +17 -1
- package/dist/grideditor.bundle.min.js +3 -3
- package/dist/grideditor.css +49 -0
- package/dist/grideditor.d.ts +4 -0
- package/dist/grideditor.esm.js +200 -8
- package/dist/grideditor.js +200 -8
- package/dist/grideditor.min.css +1 -1
- package/dist/grideditor.min.css.map +1 -1
- package/dist/grideditor.min.js +2 -2
- package/dist/grideditor.min.js.map +3 -3
- package/dist/locales/grideditor.es.esm.js +3 -0
- package/dist/locales/grideditor.es.js +3 -0
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +2 -2
- package/dist/plugins/grideditor.ckeditor.esm.js +1 -0
- package/dist/plugins/grideditor.ckeditor.js +1 -0
- package/dist/plugins/grideditor.ckeditor.min.js +1 -1
- package/dist/plugins/grideditor.ckeditor.min.js.map +2 -2
- package/dist/plugins/grideditor.sections.esm.js +1 -0
- package/dist/plugins/grideditor.sections.js +1 -0
- package/dist/plugins/grideditor.sections.min.js +1 -1
- package/dist/plugins/grideditor.sections.min.js.map +2 -2
- package/dist/plugins/grideditor.summernote.esm.js +1 -0
- package/dist/plugins/grideditor.summernote.js +1 -0
- package/dist/plugins/grideditor.summernote.min.js +1 -1
- package/dist/plugins/grideditor.summernote.min.js.map +2 -2
- package/dist/plugins/grideditor.tinymce.esm.js +1 -0
- package/dist/plugins/grideditor.tinymce.js +1 -0
- package/dist/plugins/grideditor.tinymce.min.js +1 -1
- package/dist/plugins/grideditor.tinymce.min.js.map +2 -2
- package/docs/locale-keys.md +4 -1
- package/docs/plugins.md +22 -0
- package/package.json +1 -1
- package/src/js/grideditor.js +246 -8
- package/src/js/locales/grideditor.es.js +3 -0
- package/src/js/plugins/grideditor.sections.js +1 -0
- package/src/js/text/grideditor.text.js +1 -0
- package/src/less/grideditor.less +58 -0
- package/types/grideditor.d.ts +4 -0
package/src/js/grideditor.js
CHANGED
|
@@ -198,6 +198,15 @@ function translate(settings, key, params) {
|
|
|
198
198
|
});
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
/** Whether some locale has a string for the key, asked without the warning a missing one gets. */
|
|
202
|
+
function hasString(settings, key) {
|
|
203
|
+
var locales = GridEditor.locales;
|
|
204
|
+
|
|
205
|
+
return (settings.locale_strings || {})[key] !== undefined ||
|
|
206
|
+
(locales[settings.locale] || {})[key] !== undefined ||
|
|
207
|
+
locales.en[key] !== undefined;
|
|
208
|
+
}
|
|
209
|
+
|
|
201
210
|
function warn(message) {
|
|
202
211
|
if (window.console && window.console.warn) {
|
|
203
212
|
window.console.warn('grid-editor: ' + message);
|
|
@@ -367,6 +376,8 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
367
376
|
'drag_handle' : 'tool', // 'tool' for the move tool, 'drawer' for the whole drawer
|
|
368
377
|
'toolbar_drag' : 'auto', // Drag the toolbar's buttons onto the canvas. 'auto' follows drag_handle
|
|
369
378
|
'toolbar_overflow' : 'menu', // What doesn't fit on one line: 'menu' behind a button, 'wrap' onto another line
|
|
379
|
+
'drawer_overflow' : 'menu', // The same for the drawers' tools: 'menu' behind a button, 'wrap' onto another line
|
|
380
|
+
'toolbar_groups' : false, // The add buttons in categories, one shown at a time, picked with tabs
|
|
370
381
|
'active_target' : false, // A click in a column makes it where the toolbar's buttons add
|
|
371
382
|
'element_tools' : [], // Host tools on element drawers, same shape as row_tools
|
|
372
383
|
'element_classes' : [], // Preset class toggles on an element's settings panel
|
|
@@ -423,6 +434,9 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
423
434
|
var activeTarget = null; // The column or region the toolbar adds to, with active_target
|
|
424
435
|
var toolbarLifetime = null; // Aborted when the toolbar is rebuilt or taken away
|
|
425
436
|
var closeOverflowMenu = function() {}; // Folds the toolbar's overflow menu away, when it has one
|
|
437
|
+
var refitToolbar = function() {}; // Works out again what the toolbar's overflow menu holds, when it has one
|
|
438
|
+
var addButtons = []; // The toolbar's add buttons, in toolbar order: { button, home, group }
|
|
439
|
+
var toolbarGroup = null; // The category shown, with toolbar_groups. Kept when the toolbar is rebuilt
|
|
426
440
|
var warnedHere = {}; // Some warnings are worth saying once per instance, not once per call
|
|
427
441
|
var sortables = []; // Every list made sortable, so deinit destroys exactly those
|
|
428
442
|
var instanceId = ++editorCounter; // Scopes the sortable groups to this editor
|
|
@@ -972,6 +986,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
972
986
|
canvas.parentNode.insertBefore(htmlTextArea, canvas);
|
|
973
987
|
|
|
974
988
|
createMainControls();
|
|
989
|
+
watchDrawers();
|
|
975
990
|
|
|
976
991
|
var signal = { signal: lifetime.signal };
|
|
977
992
|
|
|
@@ -1003,6 +1018,16 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1003
1018
|
if (!dom.hasClass(canvas, 'ge-editing')) { return; }
|
|
1004
1019
|
if (from && Math.abs(e.clientX - from.x) + Math.abs(e.clientY - from.y) > settings.drag.threshold) { return; }
|
|
1005
1020
|
var region = dom.closest(e.target, targetSelector());
|
|
1021
|
+
|
|
1022
|
+
// The target's own background, or its drawer's, clicked
|
|
1023
|
+
// again takes it back. What is in it - a text, a tool, a
|
|
1024
|
+
// nested column - keeps it, or makes that the target
|
|
1025
|
+
if (region && region === activeTarget &&
|
|
1026
|
+
(e.target === region || e.target === dom.child(region, '.ge-tools-drawer'))) {
|
|
1027
|
+
changeTarget(null);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1006
1031
|
changeTarget(region && region !== canvas && canvas.contains(region) ? region : null);
|
|
1007
1032
|
}, signal);
|
|
1008
1033
|
|
|
@@ -1047,6 +1072,8 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1047
1072
|
start = wrapper.appendChild(dom.element('div', { 'class': 'ge-toolbar-start' }));
|
|
1048
1073
|
}
|
|
1049
1074
|
|
|
1075
|
+
addButtons = [];
|
|
1076
|
+
|
|
1050
1077
|
// Add row
|
|
1051
1078
|
addRowGroup = start.appendChild(dom.element('div', { 'class': 'ge-addRowGroup btn-group' }));
|
|
1052
1079
|
addContainerGroup = dom.element('div', { 'class': 'ge-addContainerGroup btn-group ms-1' });
|
|
@@ -1077,6 +1104,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1077
1104
|
}
|
|
1078
1105
|
});
|
|
1079
1106
|
addRowGroup.appendChild(btn);
|
|
1107
|
+
addButtons.push({ button: btn, home: addRowGroup, group: 'rows' });
|
|
1080
1108
|
|
|
1081
1109
|
btn.appendChild(dom.create('<i class="bi bi-plus"></i>'));
|
|
1082
1110
|
|
|
@@ -1113,6 +1141,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1113
1141
|
}, { parent: canvas, source: 'tool' });
|
|
1114
1142
|
});
|
|
1115
1143
|
addContainerGroup.appendChild(button);
|
|
1144
|
+
addButtons.push({ button: button, home: addContainerGroup, group: toolbarGroupOf(definition.group) || 'content' });
|
|
1116
1145
|
});
|
|
1117
1146
|
|
|
1118
1147
|
// A feature plugin's own buttons, beside the containers': what
|
|
@@ -1128,6 +1157,8 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1128
1157
|
endItems.push(button);
|
|
1129
1158
|
} else {
|
|
1130
1159
|
addContainerGroup.appendChild(button);
|
|
1160
|
+
// One that names no category of its own has its plugin's
|
|
1161
|
+
addButtons.push({ button: button, home: addContainerGroup, group: toolbarGroupOf(item.group) || name });
|
|
1131
1162
|
}
|
|
1132
1163
|
});
|
|
1133
1164
|
});
|
|
@@ -1198,16 +1229,96 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1198
1229
|
endItems.forEach(function(button) { end.appendChild(button); });
|
|
1199
1230
|
}
|
|
1200
1231
|
|
|
1232
|
+
if (settings.toolbar_groups) { createGroupTabs(start); }
|
|
1201
1233
|
if (overflowMenu) { createOverflowMenu(start); }
|
|
1202
1234
|
|
|
1203
1235
|
makeToolbarDraggable();
|
|
1204
1236
|
}
|
|
1205
1237
|
|
|
1238
|
+
/** The core's categories, ahead of the plugins' own. */
|
|
1239
|
+
var CORE_GROUPS = [
|
|
1240
|
+
{ name: 'rows', labelKey: 'group.rows' },
|
|
1241
|
+
{ name: 'content', labelKey: 'group.content' },
|
|
1242
|
+
];
|
|
1243
|
+
|
|
1244
|
+
/** A plugin's category, when it names one. */
|
|
1245
|
+
function toolbarGroupOf(value) {
|
|
1246
|
+
return typeof value === 'string' && value.trim() !== '' ? value : null;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
/**
|
|
1250
|
+
* toolbar_groups: tabs at the start of the toolbar, one per category
|
|
1251
|
+
* of add buttons, and only the chosen one's buttons on it. The rest
|
|
1252
|
+
* wait in a hidden stash inside the toolbar, so toolbarItems still
|
|
1253
|
+
* finds them and the btn-groups round the corners of what shows. With
|
|
1254
|
+
* a single category there is nothing to choose, and no tabs.
|
|
1255
|
+
*/
|
|
1256
|
+
function createGroupTabs(start) {
|
|
1257
|
+
// The core's two first, then the rest as their first button comes
|
|
1258
|
+
var names = CORE_GROUPS.map(function(group) { return group.name; });
|
|
1259
|
+
addButtons.forEach(function(entry) {
|
|
1260
|
+
if (names.indexOf(entry.group) < 0) { names.push(entry.group); }
|
|
1261
|
+
});
|
|
1262
|
+
names = names.filter(function(name) {
|
|
1263
|
+
return addButtons.some(function(entry) { return entry.group === name; });
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
if (names.length < 2) { return; }
|
|
1267
|
+
|
|
1268
|
+
var tabs = dom.element('div', { 'class': 'ge-toolbar-groups btn-group', role: 'tablist', 'aria-label': t('group.select') });
|
|
1269
|
+
start.insertBefore(tabs, start.firstChild);
|
|
1270
|
+
var stash = mainControls.appendChild(dom.element('div', { 'class': 'ge-toolbar-stash', hidden: 'hidden' }));
|
|
1271
|
+
|
|
1272
|
+
names.forEach(function(name) {
|
|
1273
|
+
var tab = tabs.appendChild(dom.element('button', {
|
|
1274
|
+
type: 'button',
|
|
1275
|
+
'class': 'btn btn-sm btn-outline-primary',
|
|
1276
|
+
role: 'tab',
|
|
1277
|
+
'data-ge-group': name,
|
|
1278
|
+
}, groupLabel(name)));
|
|
1279
|
+
|
|
1280
|
+
tab.addEventListener('click', function() { showGroup(name); });
|
|
1281
|
+
});
|
|
1282
|
+
|
|
1283
|
+
showGroup(names.indexOf(toolbarGroup) >= 0 ? toolbarGroup : names[0]);
|
|
1284
|
+
|
|
1285
|
+
function showGroup(name) {
|
|
1286
|
+
toolbarGroup = name;
|
|
1287
|
+
|
|
1288
|
+
addButtons.forEach(function(entry) {
|
|
1289
|
+
(entry.group === name ? entry.home : stash).appendChild(entry.button);
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
dom.children(tabs).forEach(function(tab) {
|
|
1293
|
+
var chosen = tab.getAttribute('data-ge-group') === name;
|
|
1294
|
+
dom.toggleClass(tab, 'active', chosen);
|
|
1295
|
+
tab.setAttribute('aria-selected', chosen ? 'true' : 'false');
|
|
1296
|
+
});
|
|
1297
|
+
|
|
1298
|
+
refitToolbar();
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
/** A category's label: its group.<name> string, or its first button's when it has none. */
|
|
1303
|
+
function groupLabel(name) {
|
|
1304
|
+
var key = 'group.' + name;
|
|
1305
|
+
if (hasString(settings, key)) { return t(key); }
|
|
1306
|
+
|
|
1307
|
+
var first = addButtons.filter(function(entry) { return entry.group === name; })[0];
|
|
1308
|
+
return first.button.getAttribute('title') || name;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/** The add buttons on the toolbar's line: all of them, or the chosen category's. */
|
|
1312
|
+
function shownAddButtons() {
|
|
1313
|
+
return addButtons.filter(function(entry) { return !dom.closest(entry.button, '.ge-toolbar-stash'); });
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1206
1316
|
/** The toolbar off the page, with what keeps its overflow menu up to date. */
|
|
1207
1317
|
function removeMainControls() {
|
|
1208
1318
|
if (toolbarLifetime) { toolbarLifetime.abort(); }
|
|
1209
1319
|
toolbarLifetime = null;
|
|
1210
1320
|
closeOverflowMenu = function() {};
|
|
1321
|
+
refitToolbar = function() {};
|
|
1211
1322
|
mainControls.remove();
|
|
1212
1323
|
}
|
|
1213
1324
|
|
|
@@ -1231,13 +1342,10 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1231
1342
|
var toggle = dom.one(more, 'button');
|
|
1232
1343
|
var panel = dom.one(more, '.ge-toolbar-overflow');
|
|
1233
1344
|
var spares = dom.all(panel, '.btn-group');
|
|
1234
|
-
//
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
homes.push({ button: button, home: group, spare: spares[index] });
|
|
1239
|
-
});
|
|
1240
|
-
});
|
|
1345
|
+
// The spare group in the menu for each group on the line
|
|
1346
|
+
function spareOf(home) {
|
|
1347
|
+
return home === addRowGroup ? spares[0] : spares[1];
|
|
1348
|
+
}
|
|
1241
1349
|
|
|
1242
1350
|
toggle.setAttribute('title', t('tool.more'));
|
|
1243
1351
|
toggle.setAttribute('aria-haspopup', 'true');
|
|
@@ -1258,6 +1366,8 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1258
1366
|
if (e.key === 'Escape') { openOverflow(false); }
|
|
1259
1367
|
}, signal);
|
|
1260
1368
|
closeOverflowMenu = function() { openOverflow(false); };
|
|
1369
|
+
// A category chosen: another set of buttons to fit
|
|
1370
|
+
refitToolbar = fit;
|
|
1261
1371
|
|
|
1262
1372
|
fit();
|
|
1263
1373
|
|
|
@@ -1288,6 +1398,9 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1288
1398
|
|
|
1289
1399
|
/** Back on the line, then the last ones off it until the rest fit. */
|
|
1290
1400
|
function fit() {
|
|
1401
|
+
// Only the chosen category's, with toolbar_groups: the others
|
|
1402
|
+
// wait in their stash
|
|
1403
|
+
var homes = shownAddButtons();
|
|
1291
1404
|
homes.forEach(function(entry) { entry.home.appendChild(entry.button); });
|
|
1292
1405
|
dom.removeClass(more, 'ge-needed');
|
|
1293
1406
|
|
|
@@ -1298,7 +1411,8 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1298
1411
|
|
|
1299
1412
|
dom.addClass(more, 'ge-needed');
|
|
1300
1413
|
for (var i = homes.length - 1; i >= 0 && start.scrollWidth > start.clientWidth; i--) {
|
|
1301
|
-
|
|
1414
|
+
var into = spareOf(homes[i].home);
|
|
1415
|
+
into.insertBefore(homes[i].button, into.firstChild);
|
|
1302
1416
|
}
|
|
1303
1417
|
}
|
|
1304
1418
|
}
|
|
@@ -3330,6 +3444,127 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
3330
3444
|
return createTool(drawer, t('tool.move'), 'ge-move', 'bi bi-arrows-move');
|
|
3331
3445
|
}
|
|
3332
3446
|
|
|
3447
|
+
/**
|
|
3448
|
+
* The drawers that span their node - a row's, a column's, a
|
|
3449
|
+
* container's, an element's, a section's - keep their tools to one
|
|
3450
|
+
* line. The tools that don't fit are hidden from the end, and a more
|
|
3451
|
+
* tool at the drawer's end unfolds it to show them all, wrapping as
|
|
3452
|
+
* it would otherwise. They stay where they are, so whatever finds a
|
|
3453
|
+
* tool in its drawer, or hangs a picker off it, still does.
|
|
3454
|
+
*
|
|
3455
|
+
* A text's drawer sits over the text, as wide as its tools, and a
|
|
3456
|
+
* pane's sits by its label: neither is one of them.
|
|
3457
|
+
*/
|
|
3458
|
+
var FITTED_DRAWERS = '.ge-tools-drawer:not(.ge-text-drawer):not(.ge-pane-drawer):not(.ge-code-inline)';
|
|
3459
|
+
|
|
3460
|
+
/**
|
|
3461
|
+
* Fit every drawer as it comes onto the canvas, and again when it
|
|
3462
|
+
* changes width or a tool is added to it, shown or hidden. Plugins
|
|
3463
|
+
* add tools at their own moments, so this watches rather than
|
|
3464
|
+
* waiting to be told.
|
|
3465
|
+
*/
|
|
3466
|
+
function watchDrawers() {
|
|
3467
|
+
if (settings.drawer_overflow === 'wrap' || !window.ResizeObserver || !window.MutationObserver) { return; }
|
|
3468
|
+
|
|
3469
|
+
var due = new Set();
|
|
3470
|
+
var frame = null;
|
|
3471
|
+
|
|
3472
|
+
// Once a frame, after the layout: moving tools in the observers'
|
|
3473
|
+
// callbacks would resize what they are watching
|
|
3474
|
+
function schedule(drawer) {
|
|
3475
|
+
due.add(drawer);
|
|
3476
|
+
if (frame === null) { frame = window.requestAnimationFrame(flush); }
|
|
3477
|
+
}
|
|
3478
|
+
|
|
3479
|
+
function flush() {
|
|
3480
|
+
frame = null;
|
|
3481
|
+
var drawers = Array.from(due);
|
|
3482
|
+
due.clear();
|
|
3483
|
+
drawers.forEach(function(drawer) {
|
|
3484
|
+
if (!drawer.isConnected) {
|
|
3485
|
+
drawerResizes.unobserve(drawer);
|
|
3486
|
+
return;
|
|
3487
|
+
}
|
|
3488
|
+
fitDrawer(drawer);
|
|
3489
|
+
});
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3492
|
+
var drawerResizes = new window.ResizeObserver(function(entries) {
|
|
3493
|
+
entries.forEach(function(entry) { schedule(entry.target); });
|
|
3494
|
+
});
|
|
3495
|
+
|
|
3496
|
+
var mutations = new window.MutationObserver(function(records) {
|
|
3497
|
+
records.forEach(function(record) {
|
|
3498
|
+
var target = record.target;
|
|
3499
|
+
|
|
3500
|
+
// A tool shown or hidden
|
|
3501
|
+
if (record.type === 'attributes') {
|
|
3502
|
+
var parent = target.parentNode;
|
|
3503
|
+
if (parent && parent.nodeType === 1 && parent.matches(FITTED_DRAWERS)) { schedule(parent); }
|
|
3504
|
+
return;
|
|
3505
|
+
}
|
|
3506
|
+
|
|
3507
|
+
// A tool added
|
|
3508
|
+
if (target.nodeType === 1 && target.matches(FITTED_DRAWERS)) {
|
|
3509
|
+
schedule(target);
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3512
|
+
|
|
3513
|
+
record.addedNodes.forEach(function(node) {
|
|
3514
|
+
if (node.nodeType !== 1) { return; }
|
|
3515
|
+
dom.selfAndAll(node, FITTED_DRAWERS).forEach(function(drawer) {
|
|
3516
|
+
dom.addClass(drawer, 'ge-drawer-fit');
|
|
3517
|
+
drawerResizes.observe(drawer);
|
|
3518
|
+
schedule(drawer);
|
|
3519
|
+
});
|
|
3520
|
+
});
|
|
3521
|
+
});
|
|
3522
|
+
});
|
|
3523
|
+
mutations.observe(canvas, { childList: true, subtree: true, attributes: true, attributeFilter: ['style'] });
|
|
3524
|
+
|
|
3525
|
+
lifetime.signal.addEventListener('abort', function() {
|
|
3526
|
+
mutations.disconnect();
|
|
3527
|
+
drawerResizes.disconnect();
|
|
3528
|
+
if (frame !== null) { window.cancelAnimationFrame(frame); }
|
|
3529
|
+
});
|
|
3530
|
+
}
|
|
3531
|
+
|
|
3532
|
+
/** Hide the tools that don't fit on the drawer's line, from the end, behind its more tool. */
|
|
3533
|
+
function fitDrawer(drawer) {
|
|
3534
|
+
var tools = dom.children(drawer, 'a').filter(function(tool) { return !dom.hasClass(tool, 'ge-drawer-more'); });
|
|
3535
|
+
var expanded = dom.hasClass(drawer, 'ge-drawer-expanded');
|
|
3536
|
+
|
|
3537
|
+
// Measured on one line, with every tool back on it
|
|
3538
|
+
dom.removeClass(drawer, 'ge-drawer-overflow ge-drawer-expanded');
|
|
3539
|
+
tools.forEach(function(tool) { dom.removeClass(tool, 'ge-tool-overflow'); });
|
|
3540
|
+
|
|
3541
|
+
if (!drawerOverflows(drawer, tools)) { return; }
|
|
3542
|
+
|
|
3543
|
+
dom.addClass(drawer, 'ge-drawer-overflow');
|
|
3544
|
+
if (!dom.child(drawer, '.ge-drawer-more')) {
|
|
3545
|
+
createTool(drawer, t('tool.more'), 'ge-drawer-more', 'bi bi-three-dots', function() {
|
|
3546
|
+
dom.toggleClass(drawer, 'ge-drawer-expanded');
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
for (var i = tools.length - 1; i >= 0 && drawerOverflows(drawer, tools); i--) {
|
|
3551
|
+
dom.addClass(tools[i], 'ge-tool-overflow');
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3554
|
+
dom.toggleClass(drawer, 'ge-drawer-expanded', expanded);
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
function drawerOverflows(drawer, tools) {
|
|
3558
|
+
var style = window.getComputedStyle(drawer);
|
|
3559
|
+
var limit = drawer.getBoundingClientRect().right -
|
|
3560
|
+
parseFloat(style.borderRightWidth) - parseFloat(style.paddingRight);
|
|
3561
|
+
|
|
3562
|
+
return tools.some(function(tool) {
|
|
3563
|
+
var rects = tool.getClientRects();
|
|
3564
|
+
return rects.length > 0 && rects[0].right > limit + 0.5;
|
|
3565
|
+
});
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3333
3568
|
/**
|
|
3334
3569
|
* A tool in a drawer: a link with an icon, and what it does. The
|
|
3335
3570
|
* handlers are a click handler, or { eventName: handler }; each gets
|
|
@@ -5533,6 +5768,9 @@ GridEditor.locales = {
|
|
|
5533
5768
|
'tool.edit_source': 'Edit Source Code',
|
|
5534
5769
|
'tool.preview': 'Preview',
|
|
5535
5770
|
'tool.more': 'More',
|
|
5771
|
+
'group.rows': 'Rows',
|
|
5772
|
+
'group.content': 'Content',
|
|
5773
|
+
'group.select': 'Add',
|
|
5536
5774
|
'panel.title': '{kind} settings',
|
|
5537
5775
|
'panel.close': 'Close',
|
|
5538
5776
|
'panel.done': 'Done',
|
|
@@ -52,6 +52,9 @@ GridEditor.locales.es = {
|
|
|
52
52
|
'tool.edit_source': 'Editar el código fuente',
|
|
53
53
|
'tool.preview': 'Vista previa',
|
|
54
54
|
'tool.more': 'Más',
|
|
55
|
+
'group.rows': 'Filas',
|
|
56
|
+
'group.content': 'Contenido',
|
|
57
|
+
'group.select': 'Añadir',
|
|
55
58
|
'panel.title': 'Ajustes: {kind}',
|
|
56
59
|
'panel.close': 'Cerrar',
|
|
57
60
|
'panel.done': 'Hecho',
|
package/src/less/grideditor.less
CHANGED
|
@@ -67,6 +67,18 @@
|
|
|
67
67
|
margin-left: 5px;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/* toolbar_groups: the tabs choosing which category of add buttons
|
|
71
|
+
shows, at the start of the line. Never squeezed, and never behind the
|
|
72
|
+
more button */
|
|
73
|
+
.ge-toolbar-groups {
|
|
74
|
+
flex: none;
|
|
75
|
+
margin-right: 8px;
|
|
76
|
+
|
|
77
|
+
> .btn {
|
|
78
|
+
white-space: nowrap;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
70
82
|
/* toolbar_overflow: 'menu'. The add buttons keep to one line, and the
|
|
71
83
|
ones that don't fit go behind a button at its end. The right-hand
|
|
72
84
|
buttons come before in the markup, so they are ordered back to how
|
|
@@ -94,6 +106,15 @@
|
|
|
94
106
|
flex: 1 1 auto;
|
|
95
107
|
min-width: 0;
|
|
96
108
|
overflow: hidden;
|
|
109
|
+
|
|
110
|
+
/* A group as wide as its buttons and a button as wide as its label:
|
|
111
|
+
squeezed, they would wrap their labels rather than overflow */
|
|
112
|
+
> .btn-group {
|
|
113
|
+
flex: none;
|
|
114
|
+
}
|
|
115
|
+
.btn {
|
|
116
|
+
white-space: nowrap;
|
|
117
|
+
}
|
|
97
118
|
}
|
|
98
119
|
|
|
99
120
|
.ge-toolbar-more {
|
|
@@ -1114,6 +1135,43 @@
|
|
|
1114
1135
|
}
|
|
1115
1136
|
}
|
|
1116
1137
|
|
|
1138
|
+
/* drawer_overflow: 'menu'. A drawer keeps its tools to one line; the ones
|
|
1139
|
+
that don't fit are hidden behind a more tool at its end, which unfolds it
|
|
1140
|
+
to show them all */
|
|
1141
|
+
.ge-canvas.ge-editing .ge-tools-drawer.ge-drawer-fit {
|
|
1142
|
+
white-space: nowrap;
|
|
1143
|
+
|
|
1144
|
+
> .ge-details {
|
|
1145
|
+
white-space: normal;
|
|
1146
|
+
}
|
|
1147
|
+
> a.ge-tool-overflow,
|
|
1148
|
+
> a.ge-drawer-more {
|
|
1149
|
+
display: none;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
&.ge-drawer-overflow {
|
|
1153
|
+
padding-right: 26px;
|
|
1154
|
+
|
|
1155
|
+
> a.ge-drawer-more {
|
|
1156
|
+
display: inline-block;
|
|
1157
|
+
position: absolute;
|
|
1158
|
+
top: 0;
|
|
1159
|
+
right: 0;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
&.ge-drawer-expanded {
|
|
1164
|
+
white-space: normal;
|
|
1165
|
+
|
|
1166
|
+
> a.ge-tool-overflow {
|
|
1167
|
+
display: inline-block;
|
|
1168
|
+
}
|
|
1169
|
+
> a.ge-drawer-more {
|
|
1170
|
+
background: rgba(0, 0, 0, 0.08);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1117
1175
|
/* The handle belongs to editing, and never to the output */
|
|
1118
1176
|
.ge-canvas:not(.ge-editing) .ge-resize-handle {
|
|
1119
1177
|
display: none;
|
package/types/grideditor.d.ts
CHANGED
|
@@ -109,6 +109,10 @@ export interface GridEditorOptions {
|
|
|
109
109
|
toolbar_drag?: 'auto' | boolean;
|
|
110
110
|
/** The add buttons that don't fit on the toolbar's line: behind a more button, or onto another line. Default 'menu'. */
|
|
111
111
|
toolbar_overflow?: 'menu' | 'wrap';
|
|
112
|
+
/** The drawers' tools that don't fit on one line: behind a more tool, or onto more lines. Default 'menu'. */
|
|
113
|
+
drawer_overflow?: 'menu' | 'wrap';
|
|
114
|
+
/** The add buttons in categories - rows, content, and a plugin's own - one shown at a time, chosen with tabs. Default false. */
|
|
115
|
+
toolbar_groups?: boolean;
|
|
112
116
|
/** A click in a column or a section makes it where the toolbar's buttons add. Default false. */
|
|
113
117
|
active_target?: boolean;
|
|
114
118
|
/** The plugins to use, of any kind; null is every one loaded. */
|