@themarioga/grid-editor 8.0.0-beta.2 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.md +16 -9
- package/UPGRADING.md +21 -11
- package/dist/grideditor.bundle.min.js +3 -3
- package/dist/grideditor.css +77 -35
- package/dist/grideditor.d.ts +29 -8
- package/dist/grideditor.esm.js +7 -1
- package/dist/grideditor.js +7 -1
- 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 +86 -68
- package/dist/locales/grideditor.es.js +86 -68
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +2 -2
- package/dist/plugins/grideditor.alignment.min.js.map +1 -1
- package/dist/plugins/{grideditor.style.esm.js → grideditor.inline-style.esm.js} +184 -184
- package/dist/plugins/{grideditor.style.js → grideditor.inline-style.js} +182 -182
- package/dist/plugins/grideditor.inline-style.min.js +4 -0
- package/dist/plugins/grideditor.inline-style.min.js.map +7 -0
- package/dist/plugins/grideditor.tabs.esm.js +274 -6
- package/dist/plugins/grideditor.tabs.js +274 -6
- package/dist/plugins/grideditor.tabs.min.js +1 -1
- package/dist/plugins/grideditor.tabs.min.js.map +3 -3
- package/docs/locale-keys.md +97 -79
- package/docs/plugins.md +5 -5
- package/example/containers.html +64 -2
- package/example/index.html +6 -6
- package/example/{style.html → inline-style.html} +5 -5
- package/example/utilities.html +3 -3
- package/package.json +1 -1
- package/src/js/grideditor.js +8 -0
- package/src/js/{style → inline-style}/accordion.js +9 -9
- package/src/js/{style → inline-style}/catalog.js +6 -6
- package/src/js/{style → inline-style}/custom.js +4 -4
- package/src/js/{style → inline-style}/display.js +2 -2
- package/src/js/{style → inline-style}/drawerflow.js +1 -1
- package/src/js/{style → inline-style}/fields.js +25 -25
- package/src/js/{style → inline-style}/flex.js +2 -2
- package/src/js/{style → inline-style}/float.js +2 -2
- package/src/js/{style → inline-style}/options.js +5 -5
- package/src/js/{style → inline-style}/sections.js +50 -50
- package/src/js/{style → inline-style}/spacing.js +2 -2
- package/src/js/{style → inline-style}/sticky.js +2 -2
- package/src/js/{style → inline-style}/textalign.js +2 -2
- package/src/js/locales/grideditor.es.js +86 -68
- package/src/js/plugins/grideditor.alignment.js +1 -1
- package/src/js/plugins/grideditor.inline-style.js +185 -0
- package/src/js/plugins/grideditor.tabs.js +311 -5
- package/src/less/grideditor.less +71 -25
- package/types/grideditor.d.ts +29 -8
- package/dist/plugins/grideditor.style.min.js +0 -4
- package/dist/plugins/grideditor.style.min.js.map +0 -7
- package/src/js/plugins/grideditor.style.js +0 -185
|
@@ -8,6 +8,16 @@ function all(root, selector) {
|
|
|
8
8
|
function one(root, selector) {
|
|
9
9
|
return root ? root.querySelector(selector) : null;
|
|
10
10
|
}
|
|
11
|
+
function selfAndAll(root, selector) {
|
|
12
|
+
if (!root) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
var found = all(root, selector);
|
|
16
|
+
if (root.nodeType === 1 && root.matches(selector)) {
|
|
17
|
+
found.unshift(root);
|
|
18
|
+
}
|
|
19
|
+
return found;
|
|
20
|
+
}
|
|
11
21
|
function children(node, selector) {
|
|
12
22
|
if (!node) {
|
|
13
23
|
return [];
|
|
@@ -60,6 +70,12 @@ function hasClass(node, name) {
|
|
|
60
70
|
function split(names) {
|
|
61
71
|
return String(names || "").split(/\s+/).filter(Boolean);
|
|
62
72
|
}
|
|
73
|
+
function dropEmptyClass(node) {
|
|
74
|
+
if (!node.getAttribute("class")) {
|
|
75
|
+
node.removeAttribute("class");
|
|
76
|
+
}
|
|
77
|
+
return node;
|
|
78
|
+
}
|
|
63
79
|
function hide(node) {
|
|
64
80
|
node.style.display = "none";
|
|
65
81
|
return node;
|
|
@@ -106,12 +122,238 @@ Object.assign(GridEditor.locales.en, {
|
|
|
106
122
|
"container.add_tabs": "Tabs",
|
|
107
123
|
"container.add_tab": "Add tab",
|
|
108
124
|
"container.tab_label": "Tab {number}",
|
|
109
|
-
"confirm.delete_tab": "Delete this tab and everything in it?"
|
|
125
|
+
"confirm.delete_tab": "Delete this tab and everything in it?",
|
|
126
|
+
"container.tabs_section": "Tabs",
|
|
127
|
+
"container.tabs_style": "Style",
|
|
128
|
+
"container.tabs_style_tabs": "Tabs",
|
|
129
|
+
"container.tabs_style_pills": "Pills",
|
|
130
|
+
"container.tabs_style_underline": "Underline",
|
|
131
|
+
"container.tabs_width": "Width",
|
|
132
|
+
"container.tabs_width_natural": "Natural",
|
|
133
|
+
"container.tabs_width_fill": "Fill",
|
|
134
|
+
"container.tabs_width_justified": "Justified",
|
|
135
|
+
"container.tabs_align": "Alignment",
|
|
136
|
+
"container.tabs_align_start": "Start",
|
|
137
|
+
"container.tabs_align_center": "Center",
|
|
138
|
+
"container.tabs_align_end": "End",
|
|
139
|
+
"container.tabs_layout": "Layout",
|
|
140
|
+
"container.tabs_layout_horizontal": "Horizontal",
|
|
141
|
+
"container.tabs_layout_vertical": "Vertical",
|
|
142
|
+
"container.tabs_layout_vertical_from": "Vertical from {breakpoint}"
|
|
110
143
|
});
|
|
144
|
+
var STYLES = { tabs: "nav-tabs", pills: "nav-pills", underline: "nav-underline" };
|
|
145
|
+
var WIDTHS = { natural: null, fill: "nav-fill", justified: "nav-justified" };
|
|
146
|
+
var ALIGNS = { start: null, center: "justify-content-center", end: "justify-content-end" };
|
|
147
|
+
var DEFAULTS = { variant: "tabs", width: "natural", align: "start", vertical: false };
|
|
148
|
+
var FIELDS = {
|
|
149
|
+
variant: { labelKey: "container.tabs_style", choices: [
|
|
150
|
+
{ value: "tabs", labelKey: "container.tabs_style_tabs" },
|
|
151
|
+
{ value: "pills", labelKey: "container.tabs_style_pills" },
|
|
152
|
+
{ value: "underline", labelKey: "container.tabs_style_underline" }
|
|
153
|
+
] },
|
|
154
|
+
width: { labelKey: "container.tabs_width", choices: [
|
|
155
|
+
{ value: "natural", labelKey: "container.tabs_width_natural" },
|
|
156
|
+
{ value: "fill", labelKey: "container.tabs_width_fill" },
|
|
157
|
+
{ value: "justified", labelKey: "container.tabs_width_justified" }
|
|
158
|
+
] },
|
|
159
|
+
align: { labelKey: "container.tabs_align", choices: [
|
|
160
|
+
{ value: "start", labelKey: "container.tabs_align_start" },
|
|
161
|
+
{ value: "center", labelKey: "container.tabs_align_center" },
|
|
162
|
+
{ value: "end", labelKey: "container.tabs_align_end" }
|
|
163
|
+
] },
|
|
164
|
+
vertical: { labelKey: "container.tabs_layout" }
|
|
165
|
+
};
|
|
166
|
+
var fieldCounter = 0;
|
|
167
|
+
var LAYOUT_ATTR = "data-ge-tabs-layout";
|
|
168
|
+
function classValues(map) {
|
|
169
|
+
return Object.keys(map).map(function(key) {
|
|
170
|
+
return map[key];
|
|
171
|
+
}).filter(Boolean);
|
|
172
|
+
}
|
|
111
173
|
GridEditor.containers.tabs = function(ge) {
|
|
174
|
+
var sections = [];
|
|
175
|
+
function stripOf(container) {
|
|
176
|
+
return child(container, ".nav");
|
|
177
|
+
}
|
|
178
|
+
function fromBreakpoints() {
|
|
179
|
+
return ge.breakpoints.slice(1);
|
|
180
|
+
}
|
|
181
|
+
function infix(vertical) {
|
|
182
|
+
return vertical === true ? "" : "-" + vertical;
|
|
183
|
+
}
|
|
184
|
+
function verticalClasses(vertical) {
|
|
185
|
+
var at = infix(vertical);
|
|
186
|
+
return {
|
|
187
|
+
container: ["d" + at + "-flex", "align-items" + at + "-start"],
|
|
188
|
+
strip: ["flex" + at + "-column", "me" + at + "-3"]
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function verticals() {
|
|
192
|
+
return [true].concat(fromBreakpoints());
|
|
193
|
+
}
|
|
194
|
+
function read(container) {
|
|
195
|
+
var strip = stripOf(container);
|
|
196
|
+
var has = function(node, name) {
|
|
197
|
+
return !!node && hasClass(node, name);
|
|
198
|
+
};
|
|
199
|
+
var found = function(map, fallback) {
|
|
200
|
+
return Object.keys(map).filter(function(key) {
|
|
201
|
+
return map[key] && has(strip, map[key]);
|
|
202
|
+
})[0] || fallback;
|
|
203
|
+
};
|
|
204
|
+
var vertical = verticals().filter(function(each) {
|
|
205
|
+
var classes = verticalClasses(each);
|
|
206
|
+
return has(container, classes.container[0]) && has(strip, classes.strip[0]);
|
|
207
|
+
})[0];
|
|
208
|
+
return {
|
|
209
|
+
variant: found(STYLES, "tabs"),
|
|
210
|
+
width: found(WIDTHS, "natural"),
|
|
211
|
+
align: found(ALIGNS, "start"),
|
|
212
|
+
vertical: vertical === void 0 ? false : vertical
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function write(container, key, value) {
|
|
216
|
+
var strip = stripOf(container);
|
|
217
|
+
if (!strip) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (key === "variant") {
|
|
221
|
+
removeClass(strip, classValues(STYLES).join(" "));
|
|
222
|
+
addClass(strip, STYLES[value]);
|
|
223
|
+
}
|
|
224
|
+
if (key === "width" || key === "vertical") {
|
|
225
|
+
removeClass(strip, classValues(WIDTHS).join(" "));
|
|
226
|
+
if (key === "width" && WIDTHS[value]) {
|
|
227
|
+
addClass(strip, WIDTHS[value]);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (key === "align" || key === "vertical" || key === "width" && value !== "natural") {
|
|
231
|
+
removeClass(strip, classValues(ALIGNS).join(" "));
|
|
232
|
+
if (key === "align" && ALIGNS[value]) {
|
|
233
|
+
addClass(strip, ALIGNS[value]);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (key === "vertical") {
|
|
237
|
+
verticals().forEach(function(each) {
|
|
238
|
+
var classes = verticalClasses(each);
|
|
239
|
+
removeClass(container, classes.container.join(" "));
|
|
240
|
+
removeClass(strip, classes.strip.join(" "));
|
|
241
|
+
});
|
|
242
|
+
strip.removeAttribute("aria-orientation");
|
|
243
|
+
if (value !== false) {
|
|
244
|
+
var layout = verticalClasses(value);
|
|
245
|
+
addClass(container, layout.container.join(" "));
|
|
246
|
+
addClass(strip, layout.strip.join(" "));
|
|
247
|
+
strip.setAttribute("aria-orientation", "vertical");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
dropEmptyClass(container);
|
|
251
|
+
}
|
|
252
|
+
function valuesOf(key) {
|
|
253
|
+
if (key === "variant") {
|
|
254
|
+
return Object.keys(STYLES);
|
|
255
|
+
}
|
|
256
|
+
if (key === "width") {
|
|
257
|
+
return Object.keys(WIDTHS);
|
|
258
|
+
}
|
|
259
|
+
if (key === "align") {
|
|
260
|
+
return Object.keys(ALIGNS);
|
|
261
|
+
}
|
|
262
|
+
return [false].concat(verticals());
|
|
263
|
+
}
|
|
264
|
+
function chosen(options, key) {
|
|
265
|
+
var setting = ge.settings.tabs || {};
|
|
266
|
+
var value = options[key] !== void 0 ? options[key] : setting[key];
|
|
267
|
+
if (value === void 0) {
|
|
268
|
+
return DEFAULTS[key];
|
|
269
|
+
}
|
|
270
|
+
if (valuesOf(key).indexOf(value) !== -1) {
|
|
271
|
+
return value;
|
|
272
|
+
}
|
|
273
|
+
ge.warn("tabs: " + JSON.stringify(value) + " is not a " + key + ", which takes " + JSON.stringify(valuesOf(key)) + ": " + JSON.stringify(DEFAULTS[key]) + " is used");
|
|
274
|
+
return DEFAULTS[key];
|
|
275
|
+
}
|
|
276
|
+
function layoutHere(container) {
|
|
277
|
+
var vertical = read(container).vertical;
|
|
278
|
+
if (vertical === false) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
if (ge.view() === "all") {
|
|
282
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
283
|
+
return /flex$/.test(getComputedStyle(container).display) ? "vertical" : "horizontal";
|
|
284
|
+
}
|
|
285
|
+
if (vertical === true) {
|
|
286
|
+
return "vertical";
|
|
287
|
+
}
|
|
288
|
+
return ge.breakpoints.indexOf(ge.view()) >= ge.breakpoints.indexOf(vertical) ? "vertical" : "horizontal";
|
|
289
|
+
}
|
|
290
|
+
function markLayout(container) {
|
|
291
|
+
var layout = layoutHere(container);
|
|
292
|
+
if (layout) {
|
|
293
|
+
container.setAttribute(LAYOUT_ATTR, layout);
|
|
294
|
+
} else {
|
|
295
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function select(labelKey, options, onChange) {
|
|
299
|
+
var box = element("div", { "class": "ge-tabs-variant" });
|
|
300
|
+
var id = "ge-tabs-variant-" + ++fieldCounter;
|
|
301
|
+
box.appendChild(element("label", { "class": "form-label", "for": id }, ge.t(labelKey)));
|
|
302
|
+
var field = box.appendChild(element("select", { "class": "form-select form-select-sm", id }));
|
|
303
|
+
options.forEach(function(option) {
|
|
304
|
+
field.appendChild(element("option", { value: option.value }, option.label));
|
|
305
|
+
});
|
|
306
|
+
field.addEventListener("change", function() {
|
|
307
|
+
onChange(field.value);
|
|
308
|
+
});
|
|
309
|
+
return { box, field };
|
|
310
|
+
}
|
|
311
|
+
function createSection(container) {
|
|
312
|
+
var body = element("div", { "class": "ge-tabs-variants" });
|
|
313
|
+
var fields = {};
|
|
314
|
+
function change(key, value) {
|
|
315
|
+
write(container, key, value);
|
|
316
|
+
markLayout(container);
|
|
317
|
+
render();
|
|
318
|
+
}
|
|
319
|
+
function options(key) {
|
|
320
|
+
return FIELDS[key].choices.map(function(choice) {
|
|
321
|
+
return { value: choice.value, label: ge.t(choice.labelKey) };
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
["variant", "width", "align"].forEach(function(key) {
|
|
325
|
+
fields[key] = select(FIELDS[key].labelKey, options(key), function(value) {
|
|
326
|
+
change(key, value);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
fields.vertical = select(FIELDS.vertical.labelKey, [
|
|
330
|
+
{ value: "false", label: ge.t("container.tabs_layout_horizontal") },
|
|
331
|
+
{ value: "true", label: ge.t("container.tabs_layout_vertical") }
|
|
332
|
+
].concat(fromBreakpoints().map(function(key) {
|
|
333
|
+
return { value: key, label: ge.t("container.tabs_layout_vertical_from", { breakpoint: key }) };
|
|
334
|
+
})), function(value) {
|
|
335
|
+
change("vertical", value === "true" ? true : value === "false" ? false : value);
|
|
336
|
+
});
|
|
337
|
+
["variant", "width", "align", "vertical"].forEach(function(key) {
|
|
338
|
+
fields[key].box.setAttribute("data-ge-tabs-variant", key);
|
|
339
|
+
body.appendChild(fields[key].box);
|
|
340
|
+
});
|
|
341
|
+
function render() {
|
|
342
|
+
var values = read(container);
|
|
343
|
+
fields.variant.field.value = values.variant;
|
|
344
|
+
fields.width.field.value = values.width;
|
|
345
|
+
fields.align.field.value = values.align;
|
|
346
|
+
fields.vertical.field.value = String(values.vertical);
|
|
347
|
+
fields.width.field.disabled = values.vertical !== false;
|
|
348
|
+
fields.align.field.disabled = values.vertical !== false || values.width !== "natural";
|
|
349
|
+
}
|
|
350
|
+
render();
|
|
351
|
+
sections.push({ container, element: body, render });
|
|
352
|
+
return body;
|
|
353
|
+
}
|
|
112
354
|
function addTabTo(container, options) {
|
|
113
355
|
options = options || {};
|
|
114
|
-
var strip =
|
|
356
|
+
var strip = stripOf(container);
|
|
115
357
|
var content = one(container, ":scope > .tab-content");
|
|
116
358
|
var id = ge.containerId("tab");
|
|
117
359
|
var number = children(strip, ".nav-item").length + 1;
|
|
@@ -147,7 +389,7 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
147
389
|
removeClass(each, "show active");
|
|
148
390
|
});
|
|
149
391
|
addClass(pane, "show active");
|
|
150
|
-
all(container, "
|
|
392
|
+
all(stripOf(container) || container, ".nav-link").forEach(function(button) {
|
|
151
393
|
var active = button.getAttribute("data-bs-target") === "#" + id;
|
|
152
394
|
toggleClass(button, "active", active);
|
|
153
395
|
button.setAttribute("aria-selected", active ? "true" : "false");
|
|
@@ -163,7 +405,7 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
163
405
|
// A tab strip sorts its own tabs, and the panes follow them. No
|
|
164
406
|
// group: a tab belongs to the strip it was made in.
|
|
165
407
|
onSortable: function(sortable) {
|
|
166
|
-
sortable(all(ge.canvas, ".ge-container-tabs
|
|
408
|
+
sortable(all(ge.canvas, ".ge-container-tabs").map(stripOf).filter(Boolean), {
|
|
167
409
|
draggable: ".ge-tab"
|
|
168
410
|
});
|
|
169
411
|
},
|
|
@@ -175,6 +417,9 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
175
417
|
var count = options.tabs || labels.length || 2;
|
|
176
418
|
container.appendChild(element("ul", { "class": "nav nav-tabs", role: "tablist" }));
|
|
177
419
|
container.appendChild(element("div", { "class": "tab-content" }));
|
|
420
|
+
["variant", "width", "align", "vertical"].forEach(function(key) {
|
|
421
|
+
write(container, key, chosen(options, key));
|
|
422
|
+
});
|
|
178
423
|
for (var i = 0; i < count; i++) {
|
|
179
424
|
addTabTo(container, { label: labels[i] });
|
|
180
425
|
}
|
|
@@ -185,7 +430,7 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
185
430
|
all(container, ":scope > .tab-content > .tab-pane").forEach(function(pane) {
|
|
186
431
|
addClass(pane, "ge-tab-pane");
|
|
187
432
|
});
|
|
188
|
-
|
|
433
|
+
children(stripOf(container) || container, ".nav-item").forEach(function(tab) {
|
|
189
434
|
addClass(tab, "ge-tab");
|
|
190
435
|
var link = one(tab, ".nav-link");
|
|
191
436
|
if (link) {
|
|
@@ -218,15 +463,38 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
218
463
|
},
|
|
219
464
|
unmark: function(container) {
|
|
220
465
|
ge.resumeToggles(container);
|
|
466
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
221
467
|
all(container, ".ge-tab-pane").forEach(function(pane) {
|
|
222
468
|
removeClass(pane, "ge-tab-pane");
|
|
223
469
|
});
|
|
224
470
|
ge.unwrapLabels(container);
|
|
225
471
|
},
|
|
472
|
+
panelSection: function(node, kind) {
|
|
473
|
+
if (kind !== "tabs" || !stripOf(node)) {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
return { labelKey: "container.tabs_section", body: createSection(node) };
|
|
477
|
+
},
|
|
478
|
+
// After a view change or a change of classes: the layout marks and the
|
|
479
|
+
// sections follow
|
|
480
|
+
onRefresh: function(scope) {
|
|
481
|
+
selfAndAll(scope, '[data-ge-container="tabs"]').forEach(markLayout);
|
|
482
|
+
sections = sections.filter(function(entry) {
|
|
483
|
+
return entry.element.isConnected;
|
|
484
|
+
});
|
|
485
|
+
sections.forEach(function(entry) {
|
|
486
|
+
if (entry.container === scope || scope.contains(entry.container)) {
|
|
487
|
+
entry.render();
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
},
|
|
491
|
+
onDeinit: function() {
|
|
492
|
+
sections = [];
|
|
493
|
+
},
|
|
226
494
|
/** Panes read in tab order, whatever order they were dropped in. */
|
|
227
495
|
afterPaneMove: function(container) {
|
|
228
496
|
var content = one(container, ":scope > .tab-content");
|
|
229
|
-
|
|
497
|
+
children(stripOf(container) || container, ".nav-item").forEach(function(tab) {
|
|
230
498
|
var pane = paneOf(container, tab);
|
|
231
499
|
if (pane) {
|
|
232
500
|
content.appendChild(pane);
|
|
@@ -12,6 +12,16 @@
|
|
|
12
12
|
function one(root, selector) {
|
|
13
13
|
return root ? root.querySelector(selector) : null;
|
|
14
14
|
}
|
|
15
|
+
function selfAndAll(root, selector) {
|
|
16
|
+
if (!root) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
var found = all(root, selector);
|
|
20
|
+
if (root.nodeType === 1 && root.matches(selector)) {
|
|
21
|
+
found.unshift(root);
|
|
22
|
+
}
|
|
23
|
+
return found;
|
|
24
|
+
}
|
|
15
25
|
function children(node, selector) {
|
|
16
26
|
if (!node) {
|
|
17
27
|
return [];
|
|
@@ -64,6 +74,12 @@
|
|
|
64
74
|
function split(names) {
|
|
65
75
|
return String(names || "").split(/\s+/).filter(Boolean);
|
|
66
76
|
}
|
|
77
|
+
function dropEmptyClass(node) {
|
|
78
|
+
if (!node.getAttribute("class")) {
|
|
79
|
+
node.removeAttribute("class");
|
|
80
|
+
}
|
|
81
|
+
return node;
|
|
82
|
+
}
|
|
67
83
|
function hide(node) {
|
|
68
84
|
node.style.display = "none";
|
|
69
85
|
return node;
|
|
@@ -110,12 +126,238 @@
|
|
|
110
126
|
"container.add_tabs": "Tabs",
|
|
111
127
|
"container.add_tab": "Add tab",
|
|
112
128
|
"container.tab_label": "Tab {number}",
|
|
113
|
-
"confirm.delete_tab": "Delete this tab and everything in it?"
|
|
129
|
+
"confirm.delete_tab": "Delete this tab and everything in it?",
|
|
130
|
+
"container.tabs_section": "Tabs",
|
|
131
|
+
"container.tabs_style": "Style",
|
|
132
|
+
"container.tabs_style_tabs": "Tabs",
|
|
133
|
+
"container.tabs_style_pills": "Pills",
|
|
134
|
+
"container.tabs_style_underline": "Underline",
|
|
135
|
+
"container.tabs_width": "Width",
|
|
136
|
+
"container.tabs_width_natural": "Natural",
|
|
137
|
+
"container.tabs_width_fill": "Fill",
|
|
138
|
+
"container.tabs_width_justified": "Justified",
|
|
139
|
+
"container.tabs_align": "Alignment",
|
|
140
|
+
"container.tabs_align_start": "Start",
|
|
141
|
+
"container.tabs_align_center": "Center",
|
|
142
|
+
"container.tabs_align_end": "End",
|
|
143
|
+
"container.tabs_layout": "Layout",
|
|
144
|
+
"container.tabs_layout_horizontal": "Horizontal",
|
|
145
|
+
"container.tabs_layout_vertical": "Vertical",
|
|
146
|
+
"container.tabs_layout_vertical_from": "Vertical from {breakpoint}"
|
|
114
147
|
});
|
|
148
|
+
var STYLES = { tabs: "nav-tabs", pills: "nav-pills", underline: "nav-underline" };
|
|
149
|
+
var WIDTHS = { natural: null, fill: "nav-fill", justified: "nav-justified" };
|
|
150
|
+
var ALIGNS = { start: null, center: "justify-content-center", end: "justify-content-end" };
|
|
151
|
+
var DEFAULTS = { variant: "tabs", width: "natural", align: "start", vertical: false };
|
|
152
|
+
var FIELDS = {
|
|
153
|
+
variant: { labelKey: "container.tabs_style", choices: [
|
|
154
|
+
{ value: "tabs", labelKey: "container.tabs_style_tabs" },
|
|
155
|
+
{ value: "pills", labelKey: "container.tabs_style_pills" },
|
|
156
|
+
{ value: "underline", labelKey: "container.tabs_style_underline" }
|
|
157
|
+
] },
|
|
158
|
+
width: { labelKey: "container.tabs_width", choices: [
|
|
159
|
+
{ value: "natural", labelKey: "container.tabs_width_natural" },
|
|
160
|
+
{ value: "fill", labelKey: "container.tabs_width_fill" },
|
|
161
|
+
{ value: "justified", labelKey: "container.tabs_width_justified" }
|
|
162
|
+
] },
|
|
163
|
+
align: { labelKey: "container.tabs_align", choices: [
|
|
164
|
+
{ value: "start", labelKey: "container.tabs_align_start" },
|
|
165
|
+
{ value: "center", labelKey: "container.tabs_align_center" },
|
|
166
|
+
{ value: "end", labelKey: "container.tabs_align_end" }
|
|
167
|
+
] },
|
|
168
|
+
vertical: { labelKey: "container.tabs_layout" }
|
|
169
|
+
};
|
|
170
|
+
var fieldCounter = 0;
|
|
171
|
+
var LAYOUT_ATTR = "data-ge-tabs-layout";
|
|
172
|
+
function classValues(map) {
|
|
173
|
+
return Object.keys(map).map(function(key) {
|
|
174
|
+
return map[key];
|
|
175
|
+
}).filter(Boolean);
|
|
176
|
+
}
|
|
115
177
|
GridEditor.containers.tabs = function(ge) {
|
|
178
|
+
var sections = [];
|
|
179
|
+
function stripOf(container) {
|
|
180
|
+
return child(container, ".nav");
|
|
181
|
+
}
|
|
182
|
+
function fromBreakpoints() {
|
|
183
|
+
return ge.breakpoints.slice(1);
|
|
184
|
+
}
|
|
185
|
+
function infix(vertical) {
|
|
186
|
+
return vertical === true ? "" : "-" + vertical;
|
|
187
|
+
}
|
|
188
|
+
function verticalClasses(vertical) {
|
|
189
|
+
var at = infix(vertical);
|
|
190
|
+
return {
|
|
191
|
+
container: ["d" + at + "-flex", "align-items" + at + "-start"],
|
|
192
|
+
strip: ["flex" + at + "-column", "me" + at + "-3"]
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function verticals() {
|
|
196
|
+
return [true].concat(fromBreakpoints());
|
|
197
|
+
}
|
|
198
|
+
function read(container) {
|
|
199
|
+
var strip = stripOf(container);
|
|
200
|
+
var has = function(node, name) {
|
|
201
|
+
return !!node && hasClass(node, name);
|
|
202
|
+
};
|
|
203
|
+
var found = function(map, fallback) {
|
|
204
|
+
return Object.keys(map).filter(function(key) {
|
|
205
|
+
return map[key] && has(strip, map[key]);
|
|
206
|
+
})[0] || fallback;
|
|
207
|
+
};
|
|
208
|
+
var vertical = verticals().filter(function(each) {
|
|
209
|
+
var classes = verticalClasses(each);
|
|
210
|
+
return has(container, classes.container[0]) && has(strip, classes.strip[0]);
|
|
211
|
+
})[0];
|
|
212
|
+
return {
|
|
213
|
+
variant: found(STYLES, "tabs"),
|
|
214
|
+
width: found(WIDTHS, "natural"),
|
|
215
|
+
align: found(ALIGNS, "start"),
|
|
216
|
+
vertical: vertical === void 0 ? false : vertical
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function write(container, key, value) {
|
|
220
|
+
var strip = stripOf(container);
|
|
221
|
+
if (!strip) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (key === "variant") {
|
|
225
|
+
removeClass(strip, classValues(STYLES).join(" "));
|
|
226
|
+
addClass(strip, STYLES[value]);
|
|
227
|
+
}
|
|
228
|
+
if (key === "width" || key === "vertical") {
|
|
229
|
+
removeClass(strip, classValues(WIDTHS).join(" "));
|
|
230
|
+
if (key === "width" && WIDTHS[value]) {
|
|
231
|
+
addClass(strip, WIDTHS[value]);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (key === "align" || key === "vertical" || key === "width" && value !== "natural") {
|
|
235
|
+
removeClass(strip, classValues(ALIGNS).join(" "));
|
|
236
|
+
if (key === "align" && ALIGNS[value]) {
|
|
237
|
+
addClass(strip, ALIGNS[value]);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (key === "vertical") {
|
|
241
|
+
verticals().forEach(function(each) {
|
|
242
|
+
var classes = verticalClasses(each);
|
|
243
|
+
removeClass(container, classes.container.join(" "));
|
|
244
|
+
removeClass(strip, classes.strip.join(" "));
|
|
245
|
+
});
|
|
246
|
+
strip.removeAttribute("aria-orientation");
|
|
247
|
+
if (value !== false) {
|
|
248
|
+
var layout = verticalClasses(value);
|
|
249
|
+
addClass(container, layout.container.join(" "));
|
|
250
|
+
addClass(strip, layout.strip.join(" "));
|
|
251
|
+
strip.setAttribute("aria-orientation", "vertical");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
dropEmptyClass(container);
|
|
255
|
+
}
|
|
256
|
+
function valuesOf(key) {
|
|
257
|
+
if (key === "variant") {
|
|
258
|
+
return Object.keys(STYLES);
|
|
259
|
+
}
|
|
260
|
+
if (key === "width") {
|
|
261
|
+
return Object.keys(WIDTHS);
|
|
262
|
+
}
|
|
263
|
+
if (key === "align") {
|
|
264
|
+
return Object.keys(ALIGNS);
|
|
265
|
+
}
|
|
266
|
+
return [false].concat(verticals());
|
|
267
|
+
}
|
|
268
|
+
function chosen(options, key) {
|
|
269
|
+
var setting = ge.settings.tabs || {};
|
|
270
|
+
var value = options[key] !== void 0 ? options[key] : setting[key];
|
|
271
|
+
if (value === void 0) {
|
|
272
|
+
return DEFAULTS[key];
|
|
273
|
+
}
|
|
274
|
+
if (valuesOf(key).indexOf(value) !== -1) {
|
|
275
|
+
return value;
|
|
276
|
+
}
|
|
277
|
+
ge.warn("tabs: " + JSON.stringify(value) + " is not a " + key + ", which takes " + JSON.stringify(valuesOf(key)) + ": " + JSON.stringify(DEFAULTS[key]) + " is used");
|
|
278
|
+
return DEFAULTS[key];
|
|
279
|
+
}
|
|
280
|
+
function layoutHere(container) {
|
|
281
|
+
var vertical = read(container).vertical;
|
|
282
|
+
if (vertical === false) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
if (ge.view() === "all") {
|
|
286
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
287
|
+
return /flex$/.test(getComputedStyle(container).display) ? "vertical" : "horizontal";
|
|
288
|
+
}
|
|
289
|
+
if (vertical === true) {
|
|
290
|
+
return "vertical";
|
|
291
|
+
}
|
|
292
|
+
return ge.breakpoints.indexOf(ge.view()) >= ge.breakpoints.indexOf(vertical) ? "vertical" : "horizontal";
|
|
293
|
+
}
|
|
294
|
+
function markLayout(container) {
|
|
295
|
+
var layout = layoutHere(container);
|
|
296
|
+
if (layout) {
|
|
297
|
+
container.setAttribute(LAYOUT_ATTR, layout);
|
|
298
|
+
} else {
|
|
299
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function select(labelKey, options, onChange) {
|
|
303
|
+
var box = element("div", { "class": "ge-tabs-variant" });
|
|
304
|
+
var id = "ge-tabs-variant-" + ++fieldCounter;
|
|
305
|
+
box.appendChild(element("label", { "class": "form-label", "for": id }, ge.t(labelKey)));
|
|
306
|
+
var field = box.appendChild(element("select", { "class": "form-select form-select-sm", id }));
|
|
307
|
+
options.forEach(function(option) {
|
|
308
|
+
field.appendChild(element("option", { value: option.value }, option.label));
|
|
309
|
+
});
|
|
310
|
+
field.addEventListener("change", function() {
|
|
311
|
+
onChange(field.value);
|
|
312
|
+
});
|
|
313
|
+
return { box, field };
|
|
314
|
+
}
|
|
315
|
+
function createSection(container) {
|
|
316
|
+
var body = element("div", { "class": "ge-tabs-variants" });
|
|
317
|
+
var fields = {};
|
|
318
|
+
function change(key, value) {
|
|
319
|
+
write(container, key, value);
|
|
320
|
+
markLayout(container);
|
|
321
|
+
render();
|
|
322
|
+
}
|
|
323
|
+
function options(key) {
|
|
324
|
+
return FIELDS[key].choices.map(function(choice) {
|
|
325
|
+
return { value: choice.value, label: ge.t(choice.labelKey) };
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
["variant", "width", "align"].forEach(function(key) {
|
|
329
|
+
fields[key] = select(FIELDS[key].labelKey, options(key), function(value) {
|
|
330
|
+
change(key, value);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
fields.vertical = select(FIELDS.vertical.labelKey, [
|
|
334
|
+
{ value: "false", label: ge.t("container.tabs_layout_horizontal") },
|
|
335
|
+
{ value: "true", label: ge.t("container.tabs_layout_vertical") }
|
|
336
|
+
].concat(fromBreakpoints().map(function(key) {
|
|
337
|
+
return { value: key, label: ge.t("container.tabs_layout_vertical_from", { breakpoint: key }) };
|
|
338
|
+
})), function(value) {
|
|
339
|
+
change("vertical", value === "true" ? true : value === "false" ? false : value);
|
|
340
|
+
});
|
|
341
|
+
["variant", "width", "align", "vertical"].forEach(function(key) {
|
|
342
|
+
fields[key].box.setAttribute("data-ge-tabs-variant", key);
|
|
343
|
+
body.appendChild(fields[key].box);
|
|
344
|
+
});
|
|
345
|
+
function render() {
|
|
346
|
+
var values = read(container);
|
|
347
|
+
fields.variant.field.value = values.variant;
|
|
348
|
+
fields.width.field.value = values.width;
|
|
349
|
+
fields.align.field.value = values.align;
|
|
350
|
+
fields.vertical.field.value = String(values.vertical);
|
|
351
|
+
fields.width.field.disabled = values.vertical !== false;
|
|
352
|
+
fields.align.field.disabled = values.vertical !== false || values.width !== "natural";
|
|
353
|
+
}
|
|
354
|
+
render();
|
|
355
|
+
sections.push({ container, element: body, render });
|
|
356
|
+
return body;
|
|
357
|
+
}
|
|
116
358
|
function addTabTo(container, options) {
|
|
117
359
|
options = options || {};
|
|
118
|
-
var strip =
|
|
360
|
+
var strip = stripOf(container);
|
|
119
361
|
var content = one(container, ":scope > .tab-content");
|
|
120
362
|
var id = ge.containerId("tab");
|
|
121
363
|
var number = children(strip, ".nav-item").length + 1;
|
|
@@ -151,7 +393,7 @@
|
|
|
151
393
|
removeClass(each, "show active");
|
|
152
394
|
});
|
|
153
395
|
addClass(pane, "show active");
|
|
154
|
-
all(container, "
|
|
396
|
+
all(stripOf(container) || container, ".nav-link").forEach(function(button) {
|
|
155
397
|
var active = button.getAttribute("data-bs-target") === "#" + id;
|
|
156
398
|
toggleClass(button, "active", active);
|
|
157
399
|
button.setAttribute("aria-selected", active ? "true" : "false");
|
|
@@ -167,7 +409,7 @@
|
|
|
167
409
|
// A tab strip sorts its own tabs, and the panes follow them. No
|
|
168
410
|
// group: a tab belongs to the strip it was made in.
|
|
169
411
|
onSortable: function(sortable) {
|
|
170
|
-
sortable(all(ge.canvas, ".ge-container-tabs
|
|
412
|
+
sortable(all(ge.canvas, ".ge-container-tabs").map(stripOf).filter(Boolean), {
|
|
171
413
|
draggable: ".ge-tab"
|
|
172
414
|
});
|
|
173
415
|
},
|
|
@@ -179,6 +421,9 @@
|
|
|
179
421
|
var count = options.tabs || labels.length || 2;
|
|
180
422
|
container.appendChild(element("ul", { "class": "nav nav-tabs", role: "tablist" }));
|
|
181
423
|
container.appendChild(element("div", { "class": "tab-content" }));
|
|
424
|
+
["variant", "width", "align", "vertical"].forEach(function(key) {
|
|
425
|
+
write(container, key, chosen(options, key));
|
|
426
|
+
});
|
|
182
427
|
for (var i = 0; i < count; i++) {
|
|
183
428
|
addTabTo(container, { label: labels[i] });
|
|
184
429
|
}
|
|
@@ -189,7 +434,7 @@
|
|
|
189
434
|
all(container, ":scope > .tab-content > .tab-pane").forEach(function(pane) {
|
|
190
435
|
addClass(pane, "ge-tab-pane");
|
|
191
436
|
});
|
|
192
|
-
|
|
437
|
+
children(stripOf(container) || container, ".nav-item").forEach(function(tab) {
|
|
193
438
|
addClass(tab, "ge-tab");
|
|
194
439
|
var link = one(tab, ".nav-link");
|
|
195
440
|
if (link) {
|
|
@@ -222,15 +467,38 @@
|
|
|
222
467
|
},
|
|
223
468
|
unmark: function(container) {
|
|
224
469
|
ge.resumeToggles(container);
|
|
470
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
225
471
|
all(container, ".ge-tab-pane").forEach(function(pane) {
|
|
226
472
|
removeClass(pane, "ge-tab-pane");
|
|
227
473
|
});
|
|
228
474
|
ge.unwrapLabels(container);
|
|
229
475
|
},
|
|
476
|
+
panelSection: function(node, kind) {
|
|
477
|
+
if (kind !== "tabs" || !stripOf(node)) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
return { labelKey: "container.tabs_section", body: createSection(node) };
|
|
481
|
+
},
|
|
482
|
+
// After a view change or a change of classes: the layout marks and the
|
|
483
|
+
// sections follow
|
|
484
|
+
onRefresh: function(scope) {
|
|
485
|
+
selfAndAll(scope, '[data-ge-container="tabs"]').forEach(markLayout);
|
|
486
|
+
sections = sections.filter(function(entry) {
|
|
487
|
+
return entry.element.isConnected;
|
|
488
|
+
});
|
|
489
|
+
sections.forEach(function(entry) {
|
|
490
|
+
if (entry.container === scope || scope.contains(entry.container)) {
|
|
491
|
+
entry.render();
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
},
|
|
495
|
+
onDeinit: function() {
|
|
496
|
+
sections = [];
|
|
497
|
+
},
|
|
230
498
|
/** Panes read in tab order, whatever order they were dropped in. */
|
|
231
499
|
afterPaneMove: function(container) {
|
|
232
500
|
var content = one(container, ":scope > .tab-content");
|
|
233
|
-
|
|
501
|
+
children(stripOf(container) || container, ".nav-item").forEach(function(tab) {
|
|
234
502
|
var pane = paneOf(container, tab);
|
|
235
503
|
if (pane) {
|
|
236
504
|
content.appendChild(pane);
|