@themarioga/grid-editor 7.3.0 → 8.0.0-beta.3
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 +76 -0
- package/README.md +34 -30
- package/UPGRADING.md +55 -0
- package/dist/grideditor.bundle.min.js +3 -3
- package/dist/grideditor.css +72 -6
- package/dist/grideditor.d.ts +24 -3
- package/dist/grideditor.esm.js +7 -58
- package/dist/grideditor.jquery.js +0 -13
- package/dist/grideditor.jquery.min.js +1 -1
- package/dist/grideditor.jquery.min.js.map +3 -3
- package/dist/grideditor.js +7 -58
- 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 +30 -6
- package/dist/locales/grideditor.es.js +30 -6
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +2 -2
- package/dist/plugins/grideditor.accordion.min.js.map +2 -2
- package/dist/plugins/grideditor.alignment.esm.js +11 -38
- package/dist/plugins/grideditor.alignment.js +11 -38
- package/dist/plugins/grideditor.alignment.min.js +1 -1
- package/dist/plugins/grideditor.alignment.min.js.map +3 -3
- package/dist/plugins/grideditor.card.min.js.map +1 -1
- package/dist/plugins/grideditor.ckeditor.esm.js +0 -5
- package/dist/plugins/grideditor.ckeditor.js +0 -5
- package/dist/plugins/grideditor.ckeditor.min.js +1 -1
- package/dist/plugins/grideditor.ckeditor.min.js.map +3 -3
- package/dist/plugins/grideditor.clipboard.min.js.map +1 -1
- package/dist/plugins/grideditor.codemirror-inline.min.js.map +1 -1
- package/dist/plugins/grideditor.codemirror.min.js.map +1 -1
- package/dist/plugins/grideditor.elements.min.js.map +2 -2
- package/dist/plugins/grideditor.gutters.min.js.map +1 -1
- package/dist/plugins/grideditor.order.min.js.map +1 -1
- package/dist/plugins/grideditor.popup.min.js.map +1 -1
- package/dist/plugins/grideditor.sections.min.js.map +2 -2
- package/dist/plugins/grideditor.style.esm.js +393 -60
- package/dist/plugins/grideditor.style.js +387 -56
- package/dist/plugins/grideditor.style.min.js +4 -2
- package/dist/plugins/grideditor.style.min.js.map +4 -4
- package/dist/plugins/grideditor.summernote.min.js.map +2 -2
- 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/dist/plugins/grideditor.tinymce.esm.js +1 -8
- package/dist/plugins/grideditor.tinymce.js +1 -8
- package/dist/plugins/grideditor.tinymce.min.js +1 -1
- package/dist/plugins/grideditor.tinymce.min.js.map +3 -3
- package/docs/events.md +4 -6
- package/docs/locale-keys.md +35 -13
- package/docs/plugins.md +15 -35
- package/example/ckeditor.html +0 -5
- package/example/containers.html +64 -2
- package/example/index.html +5 -4
- package/example/style.html +16 -4
- package/example/utilities.html +12 -11
- package/package.json +1 -1
- package/src/js/dom.js +1 -2
- package/src/js/grideditor.jquery.js +7 -28
- package/src/js/grideditor.js +12 -81
- package/src/js/locales/grideditor.es.js +30 -6
- package/src/js/plugins/grideditor.alignment.js +21 -50
- package/src/js/plugins/grideditor.ckeditor.js +10 -23
- package/src/js/plugins/grideditor.style.js +18 -12
- package/src/js/plugins/grideditor.summernote.js +4 -5
- package/src/js/plugins/grideditor.tabs.js +311 -5
- package/src/js/plugins/grideditor.tinymce.js +4 -17
- package/src/js/style/accordion.js +14 -3
- package/src/js/style/display.js +229 -0
- package/src/js/style/drawerflow.js +118 -0
- package/src/js/style/flex.js +156 -0
- package/src/js/style/float.js +2 -4
- package/src/js/style/options.js +5 -20
- package/src/js/style/sections.js +42 -15
- package/src/js/style/spacing.js +2 -4
- package/src/js/style/sticky.js +39 -0
- package/src/js/style/textalign.js +2 -4
- package/src/js/text/grideditor.text.js +1 -1
- package/src/less/grideditor.less +68 -10
- package/types/grideditor.d.ts +24 -3
- package/dist/plugins/grideditor.float.esm.js +0 -43
- package/dist/plugins/grideditor.float.js +0 -47
- package/dist/plugins/grideditor.float.min.js +0 -1
- package/dist/plugins/grideditor.float.min.js.map +0 -7
- package/dist/plugins/grideditor.spacing.esm.js +0 -327
- package/dist/plugins/grideditor.spacing.js +0 -329
- package/dist/plugins/grideditor.spacing.min.js +0 -1
- package/dist/plugins/grideditor.spacing.min.js.map +0 -7
- package/dist/plugins/grideditor.textalign.esm.js +0 -49
- package/dist/plugins/grideditor.textalign.js +0 -53
- package/dist/plugins/grideditor.textalign.min.js +0 -1
- package/dist/plugins/grideditor.textalign.min.js.map +0 -7
- package/dist/plugins/grideditor.visibility.esm.js +0 -167
- package/dist/plugins/grideditor.visibility.js +0 -169
- package/dist/plugins/grideditor.visibility.min.js +0 -1
- package/dist/plugins/grideditor.visibility.min.js.map +0 -7
- package/src/js/plugins/grideditor.float.js +0 -29
- package/src/js/plugins/grideditor.spacing.js +0 -31
- package/src/js/plugins/grideditor.textalign.js +0 -27
- package/src/js/plugins/grideditor.visibility.js +0 -32
- package/src/js/style/visibility.js +0 -160
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Alignment for grid-editor.
|
|
3
3
|
*
|
|
4
|
-
* A utility plugin: load this file after the editor and a
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* handle its factory is called with, described in docs/plugins.md.
|
|
4
|
+
* A utility plugin: load this file after the editor and a column can align
|
|
5
|
+
* itself in its row, per breakpoint, with Bootstrap's align-self-{breakpoint}-*
|
|
6
|
+
* classes. What it can ask the editor for is the handle its factory is called
|
|
7
|
+
* with, described in docs/plugins.md.
|
|
9
8
|
*
|
|
10
9
|
* <script src="dist/grideditor.min.js"></script>
|
|
11
10
|
* <script src="dist/plugins/grideditor.alignment.min.js"></script>
|
|
12
11
|
*
|
|
13
|
-
*
|
|
12
|
+
* How a row justifies and aligns its columns - justify-content-* and
|
|
13
|
+
* align-items-* - is a flex container's, and the style plugin's Flex section
|
|
14
|
+
* edits it, on a row and on anything else made flex.
|
|
15
|
+
*
|
|
16
|
+
* A field only, in the settings panel: alignment is set now and then, not
|
|
14
17
|
* clicked through, and a drawer is short of room.
|
|
15
18
|
*/
|
|
16
19
|
import { GridEditor } from '../grideditor.js';
|
|
17
20
|
|
|
18
21
|
Object.assign(GridEditor.locales.en, {
|
|
19
|
-
'utility.justify_content': 'Justify columns',
|
|
20
|
-
'utility.align_items': 'Align columns',
|
|
21
22
|
'utility.align_self': 'Align self',
|
|
22
23
|
});
|
|
23
24
|
|
|
@@ -26,54 +27,24 @@ var FLEX = {
|
|
|
26
27
|
start: 'flex-start',
|
|
27
28
|
end: 'flex-end',
|
|
28
29
|
center: 'center',
|
|
29
|
-
between: 'space-between',
|
|
30
|
-
around: 'space-around',
|
|
31
|
-
evenly: 'space-evenly',
|
|
32
30
|
baseline: 'baseline',
|
|
33
31
|
stretch: 'stretch',
|
|
34
32
|
auto: 'auto',
|
|
35
33
|
};
|
|
36
34
|
|
|
37
|
-
/**
|
|
38
|
-
* A family whose preview is its one css property. `none` is what the
|
|
39
|
-
* property is when no class says anything, which a view has to show over a
|
|
40
|
-
* wider breakpoint's class that is live in a wide window.
|
|
41
|
-
*/
|
|
42
|
-
function family(definition) {
|
|
43
|
-
return Object.assign({
|
|
44
|
-
prefix: definition.name,
|
|
45
|
-
preview: function(value) {
|
|
46
|
-
var styles = {};
|
|
47
|
-
styles[definition.name] = value === null ? definition.none : FLEX[value];
|
|
48
|
-
return styles;
|
|
49
|
-
},
|
|
50
|
-
}, definition);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
35
|
GridEditor.utilities.alignment = function() {
|
|
54
36
|
return {
|
|
55
|
-
families: [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
appliesTo: ['row'],
|
|
68
|
-
none: 'normal',
|
|
69
|
-
}),
|
|
70
|
-
family({
|
|
71
|
-
name: 'align-self',
|
|
72
|
-
labelKey: 'utility.align_self',
|
|
73
|
-
values: ['auto', 'start', 'center', 'end', 'baseline', 'stretch'],
|
|
74
|
-
appliesTo: ['column'],
|
|
75
|
-
none: 'auto',
|
|
76
|
-
}),
|
|
77
|
-
],
|
|
37
|
+
families: [{
|
|
38
|
+
name: 'align-self',
|
|
39
|
+
prefix: 'align-self',
|
|
40
|
+
labelKey: 'utility.align_self',
|
|
41
|
+
values: ['auto', 'start', 'center', 'end', 'baseline', 'stretch'],
|
|
42
|
+
appliesTo: ['column'],
|
|
43
|
+
|
|
44
|
+
/** Without a class, auto: what the row's align-items says. */
|
|
45
|
+
preview: function(value) {
|
|
46
|
+
return { 'align-self': value === null ? 'auto' : FLEX[value] };
|
|
47
|
+
},
|
|
48
|
+
}],
|
|
78
49
|
};
|
|
79
50
|
};
|
|
@@ -11,15 +11,13 @@
|
|
|
11
11
|
* <script src="dist/grideditor.min.js"></script>
|
|
12
12
|
* <script src="dist/plugins/grideditor.ckeditor.min.js"></script>
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* 'GPL', or a commercial key, is the host's to pass in ckeditor.config.
|
|
14
|
+
* CKEditor 5 asks for a license key, GPL or a commercial one, which is the
|
|
15
|
+
* host's to pass in ckeditor.config.
|
|
17
16
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* in its classic script, installed once however many editors a page loads.
|
|
17
|
+
* It imports what every text editor shares - text blocks, the Text button,
|
|
18
|
+
* createText, making the host's plain content a text - from
|
|
19
|
+
* src/js/text/grideditor.text.js, which the build puts in its classic
|
|
20
|
+
* script, installed once however many editors a page loads.
|
|
23
21
|
*/
|
|
24
22
|
import { GridEditor } from '../grideditor.js';
|
|
25
23
|
import * as dom from '../dom.js';
|
|
@@ -34,8 +32,8 @@ Object.assign(GridEditor.locales.en, {
|
|
|
34
32
|
var INITIAL_CONTENT = '<p>Lorem initius... </p>';
|
|
35
33
|
|
|
36
34
|
// What CKEditor 5 is started with when the host's config does not say. It
|
|
37
|
-
// has no plugins of its own, so these are what a text can do
|
|
38
|
-
//
|
|
35
|
+
// has no plugins of its own, so these are what a text can do. Names, looked
|
|
36
|
+
// up on window.CKEDITOR.
|
|
39
37
|
var PLUGINS = [
|
|
40
38
|
'Essentials', 'Autoformat', 'Paragraph', 'Heading', 'Bold', 'Italic', 'Underline', 'Strikethrough',
|
|
41
39
|
'Link', 'AutoLink', 'List', 'BlockQuote', 'Indent', 'HorizontalLine', 'Table', 'TableToolbar',
|
|
@@ -122,9 +120,6 @@ GridEditor.texts.ckeditor = function(ge) {
|
|
|
122
120
|
|
|
123
121
|
var configuration = Object.assign({}, DEFAULTS, userConfig);
|
|
124
122
|
configuration.plugins = pluginsFor(ge, userConfig.plugins || PLUGINS);
|
|
125
|
-
// on.instanceReady is CKEditor 4's, and CKEditor 5 has no
|
|
126
|
-
// such option: this file calls it, as it did in 7.1
|
|
127
|
-
delete configuration.on;
|
|
128
123
|
|
|
129
124
|
var ticket = {};
|
|
130
125
|
starting.set(contentArea, ticket);
|
|
@@ -144,13 +139,6 @@ GridEditor.texts.ckeditor = function(ge) {
|
|
|
144
139
|
starting.delete(contentArea);
|
|
145
140
|
editors.set(contentArea, editor);
|
|
146
141
|
|
|
147
|
-
// Call the original instanceReady function, if one was
|
|
148
|
-
// passed in the config: 7.1's, with CKEditor 4's event
|
|
149
|
-
var callback = userConfig.on && userConfig.on.instanceReady;
|
|
150
|
-
if (callback) {
|
|
151
|
-
callback.call(editor, { editor: editor });
|
|
152
|
-
}
|
|
153
|
-
|
|
154
142
|
// The editor owns what is inside the content area now,
|
|
155
143
|
// so the grid editor is told to put its own furniture back
|
|
156
144
|
ge.textReady(contentArea);
|
|
@@ -173,9 +161,8 @@ GridEditor.texts.ckeditor = function(ge) {
|
|
|
173
161
|
contentAreas.filter(function(contentArea) {
|
|
174
162
|
return dom.hasClass(contentArea, 'active');
|
|
175
163
|
}).forEach(function(contentArea) {
|
|
176
|
-
// This content area's editor, and no other:
|
|
177
|
-
//
|
|
178
|
-
// the page, other editors' and the host's own included
|
|
164
|
+
// This content area's editor, and no other: the other
|
|
165
|
+
// CKEditors on the page, the host's own included, stay
|
|
179
166
|
var editor = editors.get(contentArea);
|
|
180
167
|
editors.delete(contentArea);
|
|
181
168
|
// One still starting sees this and goes as it is ready
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* A utility plugin: load this file after the editor and every row, column,
|
|
5
5
|
* container, pane, element and section gets a Style accordion in its
|
|
6
6
|
* settings panel - size, spacing, border, background, text, typography,
|
|
7
|
-
* display, position and free css - written to the node's own style
|
|
7
|
+
* display, flex, position and free css - written to the node's own style
|
|
8
8
|
* attribute, with Bootstrap's classes for each section as chips that put
|
|
9
9
|
* them in the classes field. What it can ask the editor for is the handle
|
|
10
10
|
* its factory is called with, described in docs/plugins.md.
|
|
@@ -12,23 +12,26 @@
|
|
|
12
12
|
* <script src="dist/grideditor.min.js"></script>
|
|
13
13
|
* <script src="dist/plugins/grideditor.style.min.js"></script>
|
|
14
14
|
*
|
|
15
|
-
* It
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* It also edits spacing, text alignment, display, flex, sticky and float,
|
|
16
|
+
* Bootstrap's responsive classes, per breakpoint in its sections. On a node
|
|
17
|
+
* that is flex or grid, the drawer leaves the flow, so the canvas lays the
|
|
18
|
+
* content out as the page will.
|
|
19
19
|
*
|
|
20
20
|
* Where the settings panel has no room for it - a popover, inline in the
|
|
21
21
|
* drawer - the accordion opens in a dialog, from a Style button.
|
|
22
22
|
*
|
|
23
23
|
* style.sections chooses the sections, and in each the properties and
|
|
24
|
-
* whether it has a catalog; style.spacing
|
|
25
|
-
*
|
|
24
|
+
* whether it has a catalog; style.spacing is the options of spacing, whose
|
|
25
|
+
* scale the gaps share, and style.visibility those of the eye.
|
|
26
26
|
*/
|
|
27
27
|
import { GridEditor } from '../grideditor.js';
|
|
28
28
|
import { spacingPart } from '../style/spacing.js';
|
|
29
29
|
import { textalignPart } from '../style/textalign.js';
|
|
30
|
-
import {
|
|
30
|
+
import { displayPart } from '../style/display.js';
|
|
31
|
+
import { flexPart } from '../style/flex.js';
|
|
31
32
|
import { floatPart } from '../style/float.js';
|
|
33
|
+
import { stickyPart } from '../style/sticky.js';
|
|
34
|
+
import { drawerflowPart } from '../style/drawerflow.js';
|
|
32
35
|
import { resolveOptions } from '../style/options.js';
|
|
33
36
|
import { createAccordion } from '../style/accordion.js';
|
|
34
37
|
|
|
@@ -42,6 +45,7 @@ Object.assign(GridEditor.locales.en, {
|
|
|
42
45
|
'style.section_text': 'Text',
|
|
43
46
|
'style.section_typography': 'Typography',
|
|
44
47
|
'style.section_display': 'Display',
|
|
48
|
+
'style.section_flex': 'Flex',
|
|
45
49
|
'style.section_position': 'Position',
|
|
46
50
|
'style.section_custom': 'Custom css',
|
|
47
51
|
'style.all_sizes': 'Applies to every size',
|
|
@@ -102,7 +106,8 @@ Object.assign(GridEditor.locales.en, {
|
|
|
102
106
|
'style.prop_z_index': 'Z-index',
|
|
103
107
|
});
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
// The drawer's part last: it asks the browser how the others left the node
|
|
110
|
+
var PARTS = ['spacing', 'textalign', 'display', 'flex', 'float', 'sticky', 'drawerflow'];
|
|
106
111
|
|
|
107
112
|
GridEditor.utilities.style = function(ge) {
|
|
108
113
|
|
|
@@ -110,8 +115,11 @@ GridEditor.utilities.style = function(ge) {
|
|
|
110
115
|
var parts = {
|
|
111
116
|
spacing: spacingPart(ge, options.spacing),
|
|
112
117
|
textalign: textalignPart(ge),
|
|
113
|
-
|
|
118
|
+
display: displayPart(ge, options.visibility),
|
|
119
|
+
flex: flexPart(ge, options.spacing),
|
|
114
120
|
float: floatPart(ge),
|
|
121
|
+
sticky: stickyPart(ge),
|
|
122
|
+
drawerflow: drawerflowPart(ge),
|
|
115
123
|
};
|
|
116
124
|
var accordions = []; // { node, accordion } for every panel built since the last init
|
|
117
125
|
var context = {
|
|
@@ -175,5 +183,3 @@ GridEditor.utilities.style = function(ge) {
|
|
|
175
183
|
},
|
|
176
184
|
};
|
|
177
185
|
};
|
|
178
|
-
|
|
179
|
-
GridEditor.utilities.style.replaces = PARTS;
|
|
@@ -16,11 +16,10 @@
|
|
|
16
16
|
* nothing else. Towards the editor it is plain DOM, like every plugin, and
|
|
17
17
|
* it needs no jQuery adapter.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* in its classic script, installed once however many editors a page loads.
|
|
19
|
+
* It imports what every text editor shares - text blocks, the Text button,
|
|
20
|
+
* createText, making the host's plain content a text - from
|
|
21
|
+
* src/js/text/grideditor.text.js, which the build puts in its classic
|
|
22
|
+
* script, installed once however many editors a page loads.
|
|
24
23
|
*/
|
|
25
24
|
import { GridEditor } from '../grideditor.js';
|
|
26
25
|
import * as dom from '../dom.js';
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
*
|
|
8
8
|
* <script src="dist/grideditor.min.js"></script>
|
|
9
9
|
* <script src="dist/plugins/grideditor.tabs.min.js"></script>
|
|
10
|
+
*
|
|
11
|
+
* A container's variant - its style, width, alignment and whether it is laid
|
|
12
|
+
* out vertically, from a breakpoint up - is Bootstrap's classes on its strip
|
|
13
|
+
* and on itself, and nothing else: it is read from the markup, chosen in the
|
|
14
|
+
* container's settings panel, or given to createContainer and the tabs
|
|
15
|
+
* setting for the ones made new.
|
|
10
16
|
*/
|
|
11
17
|
import { GridEditor } from '../grideditor.js';
|
|
12
18
|
import * as dom from '../dom.js';
|
|
@@ -16,14 +22,287 @@ Object.assign(GridEditor.locales.en, {
|
|
|
16
22
|
'container.add_tab': 'Add tab',
|
|
17
23
|
'container.tab_label': 'Tab {number}',
|
|
18
24
|
'confirm.delete_tab': 'Delete this tab and everything in it?',
|
|
25
|
+
'container.tabs_section': 'Tabs',
|
|
26
|
+
'container.tabs_style': 'Style',
|
|
27
|
+
'container.tabs_style_tabs': 'Tabs',
|
|
28
|
+
'container.tabs_style_pills': 'Pills',
|
|
29
|
+
'container.tabs_style_underline': 'Underline',
|
|
30
|
+
'container.tabs_width': 'Width',
|
|
31
|
+
'container.tabs_width_natural': 'Natural',
|
|
32
|
+
'container.tabs_width_fill': 'Fill',
|
|
33
|
+
'container.tabs_width_justified': 'Justified',
|
|
34
|
+
'container.tabs_align': 'Alignment',
|
|
35
|
+
'container.tabs_align_start': 'Start',
|
|
36
|
+
'container.tabs_align_center': 'Center',
|
|
37
|
+
'container.tabs_align_end': 'End',
|
|
38
|
+
'container.tabs_layout': 'Layout',
|
|
39
|
+
'container.tabs_layout_horizontal': 'Horizontal',
|
|
40
|
+
'container.tabs_layout_vertical': 'Vertical',
|
|
41
|
+
'container.tabs_layout_vertical_from': 'Vertical from {breakpoint}',
|
|
19
42
|
});
|
|
20
43
|
|
|
44
|
+
/** Each variant's values, the first its default, and the class each puts on the strip. */
|
|
45
|
+
var STYLES = { tabs: 'nav-tabs', pills: 'nav-pills', underline: 'nav-underline' };
|
|
46
|
+
var WIDTHS = { natural: null, fill: 'nav-fill', justified: 'nav-justified' };
|
|
47
|
+
var ALIGNS = { start: null, center: 'justify-content-center', end: 'justify-content-end' };
|
|
48
|
+
var DEFAULTS = { variant: 'tabs', width: 'natural', align: 'start', vertical: false };
|
|
49
|
+
|
|
50
|
+
/** Each variant's select in the panel: its label, and its choices'. */
|
|
51
|
+
var FIELDS = {
|
|
52
|
+
variant: { labelKey: 'container.tabs_style', choices: [
|
|
53
|
+
{ value: 'tabs', labelKey: 'container.tabs_style_tabs' },
|
|
54
|
+
{ value: 'pills', labelKey: 'container.tabs_style_pills' },
|
|
55
|
+
{ value: 'underline', labelKey: 'container.tabs_style_underline' },
|
|
56
|
+
] },
|
|
57
|
+
width: { labelKey: 'container.tabs_width', choices: [
|
|
58
|
+
{ value: 'natural', labelKey: 'container.tabs_width_natural' },
|
|
59
|
+
{ value: 'fill', labelKey: 'container.tabs_width_fill' },
|
|
60
|
+
{ value: 'justified', labelKey: 'container.tabs_width_justified' },
|
|
61
|
+
] },
|
|
62
|
+
align: { labelKey: 'container.tabs_align', choices: [
|
|
63
|
+
{ value: 'start', labelKey: 'container.tabs_align_start' },
|
|
64
|
+
{ value: 'center', labelKey: 'container.tabs_align_center' },
|
|
65
|
+
{ value: 'end', labelKey: 'container.tabs_align_end' },
|
|
66
|
+
] },
|
|
67
|
+
vertical: { labelKey: 'container.tabs_layout' },
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
var fieldCounter = 0;
|
|
71
|
+
|
|
72
|
+
/** Where the layout marks what the view being edited lays the tabs out as. */
|
|
73
|
+
var LAYOUT_ATTR = 'data-ge-tabs-layout';
|
|
74
|
+
|
|
75
|
+
function classValues(map) {
|
|
76
|
+
return Object.keys(map).map(function(key) { return map[key]; }).filter(Boolean);
|
|
77
|
+
}
|
|
78
|
+
|
|
21
79
|
GridEditor.containers.tabs = function(ge) {
|
|
22
80
|
|
|
81
|
+
var sections = []; // { container, render } for every panel section built
|
|
82
|
+
|
|
83
|
+
/** The strip: the container's first .nav, whatever its style. */
|
|
84
|
+
function stripOf(container) {
|
|
85
|
+
return dom.child(container, '.nav');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** The breakpoints a layout can go vertical from; xs is always. */
|
|
89
|
+
function fromBreakpoints() {
|
|
90
|
+
return ge.breakpoints.slice(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** The infix of a vertical layout's classes: none for always. */
|
|
94
|
+
function infix(vertical) {
|
|
95
|
+
return vertical === true ? '' : '-' + vertical;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function verticalClasses(vertical) {
|
|
99
|
+
var at = infix(vertical);
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
container: ['d' + at + '-flex', 'align-items' + at + '-start'],
|
|
103
|
+
strip: ['flex' + at + '-column', 'me' + at + '-3'],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Every vertical value: always, and from each breakpoint. */
|
|
108
|
+
function verticals() {
|
|
109
|
+
return [true].concat(fromBreakpoints());
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* What a container's classes say it is. Vertical is read only when the
|
|
114
|
+
* container's flex and the strip's column are of the same breakpoint;
|
|
115
|
+
* anything else is horizontal, and is left as it is.
|
|
116
|
+
*/
|
|
117
|
+
function read(container) {
|
|
118
|
+
var strip = stripOf(container);
|
|
119
|
+
var has = function(node, name) { return !!node && dom.hasClass(node, name); };
|
|
120
|
+
var found = function(map, fallback) {
|
|
121
|
+
return Object.keys(map).filter(function(key) { return map[key] && has(strip, map[key]); })[0] || fallback;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
var vertical = verticals().filter(function(each) {
|
|
125
|
+
var classes = verticalClasses(each);
|
|
126
|
+
return has(container, classes.container[0]) && has(strip, classes.strip[0]);
|
|
127
|
+
})[0];
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
variant: found(STYLES, 'tabs'),
|
|
131
|
+
width: found(WIDTHS, 'natural'),
|
|
132
|
+
align: found(ALIGNS, 'start'),
|
|
133
|
+
vertical: vertical === undefined ? false : vertical,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Write one variant, and take off what it makes meaningless: a vertical
|
|
139
|
+
* layout has no width or alignment, and a full width no alignment.
|
|
140
|
+
* Choosing a layout clears every layout class, at any breakpoint, the
|
|
141
|
+
* user's own included.
|
|
142
|
+
*/
|
|
143
|
+
function write(container, key, value) {
|
|
144
|
+
var strip = stripOf(container);
|
|
145
|
+
if (!strip) { return; }
|
|
146
|
+
|
|
147
|
+
if (key === 'variant') {
|
|
148
|
+
dom.removeClass(strip, classValues(STYLES).join(' '));
|
|
149
|
+
dom.addClass(strip, STYLES[value]);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (key === 'width' || key === 'vertical') {
|
|
153
|
+
dom.removeClass(strip, classValues(WIDTHS).join(' '));
|
|
154
|
+
if (key === 'width' && WIDTHS[value]) { dom.addClass(strip, WIDTHS[value]); }
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (key === 'align' || key === 'vertical' || (key === 'width' && value !== 'natural')) {
|
|
158
|
+
dom.removeClass(strip, classValues(ALIGNS).join(' '));
|
|
159
|
+
if (key === 'align' && ALIGNS[value]) { dom.addClass(strip, ALIGNS[value]); }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (key === 'vertical') {
|
|
163
|
+
verticals().forEach(function(each) {
|
|
164
|
+
var classes = verticalClasses(each);
|
|
165
|
+
dom.removeClass(container, classes.container.join(' '));
|
|
166
|
+
dom.removeClass(strip, classes.strip.join(' '));
|
|
167
|
+
});
|
|
168
|
+
strip.removeAttribute('aria-orientation');
|
|
169
|
+
|
|
170
|
+
if (value !== false) {
|
|
171
|
+
var layout = verticalClasses(value);
|
|
172
|
+
dom.addClass(container, layout.container.join(' '));
|
|
173
|
+
dom.addClass(strip, layout.strip.join(' '));
|
|
174
|
+
strip.setAttribute('aria-orientation', 'vertical');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
dom.dropEmptyClass(container);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** The values a variant takes, as the warning lists them. */
|
|
182
|
+
function valuesOf(key) {
|
|
183
|
+
if (key === 'variant') { return Object.keys(STYLES); }
|
|
184
|
+
if (key === 'width') { return Object.keys(WIDTHS); }
|
|
185
|
+
if (key === 'align') { return Object.keys(ALIGNS); }
|
|
186
|
+
|
|
187
|
+
return [false].concat(verticals());
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A variant for a new container: the option, or the tabs setting, or the
|
|
192
|
+
* default. A value it does not take is warned about and the default used.
|
|
193
|
+
*/
|
|
194
|
+
function chosen(options, key) {
|
|
195
|
+
var setting = ge.settings.tabs || {};
|
|
196
|
+
var value = options[key] !== undefined ? options[key] : setting[key];
|
|
197
|
+
|
|
198
|
+
if (value === undefined) { return DEFAULTS[key]; }
|
|
199
|
+
if (valuesOf(key).indexOf(value) !== -1) { return value; }
|
|
200
|
+
|
|
201
|
+
ge.warn('tabs: ' + JSON.stringify(value) + ' is not a ' + key + ', which takes ' +
|
|
202
|
+
JSON.stringify(valuesOf(key)) + ': ' + JSON.stringify(DEFAULTS[key]) + ' is used');
|
|
203
|
+
return DEFAULTS[key];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* What the view being edited lays a container out as. A breakpoint view
|
|
208
|
+
* narrows the canvas, not the window, and Bootstrap's classes answer to
|
|
209
|
+
* the window: so the view says it, from the breakpoint the container
|
|
210
|
+
* goes vertical at. The all view shows what the window gives.
|
|
211
|
+
*/
|
|
212
|
+
function layoutHere(container) {
|
|
213
|
+
var vertical = read(container).vertical;
|
|
214
|
+
if (vertical === false) { return null; }
|
|
215
|
+
|
|
216
|
+
if (ge.view() === 'all') {
|
|
217
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
218
|
+
return /flex$/.test(getComputedStyle(container).display) ? 'vertical' : 'horizontal';
|
|
219
|
+
}
|
|
220
|
+
if (vertical === true) { return 'vertical'; }
|
|
221
|
+
|
|
222
|
+
return ge.breakpoints.indexOf(ge.view()) >= ge.breakpoints.indexOf(vertical) ? 'vertical' : 'horizontal';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function markLayout(container) {
|
|
226
|
+
var layout = layoutHere(container);
|
|
227
|
+
|
|
228
|
+
if (layout) {
|
|
229
|
+
container.setAttribute(LAYOUT_ATTR, layout);
|
|
230
|
+
} else {
|
|
231
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function select(labelKey, options, onChange) {
|
|
236
|
+
var box = dom.element('div', { 'class': 'ge-tabs-variant' });
|
|
237
|
+
var id = 'ge-tabs-variant-' + (++fieldCounter);
|
|
238
|
+
|
|
239
|
+
box.appendChild(dom.element('label', { 'class': 'form-label', 'for': id }, ge.t(labelKey)));
|
|
240
|
+
var field = box.appendChild(dom.element('select', { 'class': 'form-select form-select-sm', id: id }));
|
|
241
|
+
|
|
242
|
+
options.forEach(function(option) {
|
|
243
|
+
field.appendChild(dom.element('option', { value: option.value }, option.label));
|
|
244
|
+
});
|
|
245
|
+
field.addEventListener('change', function() { onChange(field.value); });
|
|
246
|
+
|
|
247
|
+
return { box: box, field: field };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** The Tabs section of a tabs container's settings panel: a select per variant. */
|
|
251
|
+
function createSection(container) {
|
|
252
|
+
var body = dom.element('div', { 'class': 'ge-tabs-variants' });
|
|
253
|
+
var fields = {};
|
|
254
|
+
|
|
255
|
+
function change(key, value) {
|
|
256
|
+
write(container, key, value);
|
|
257
|
+
markLayout(container);
|
|
258
|
+
render();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function options(key) {
|
|
262
|
+
return FIELDS[key].choices.map(function(choice) {
|
|
263
|
+
return { value: choice.value, label: ge.t(choice.labelKey) };
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
['variant', 'width', 'align'].forEach(function(key) {
|
|
268
|
+
fields[key] = select(FIELDS[key].labelKey, options(key), function(value) { change(key, value); });
|
|
269
|
+
});
|
|
270
|
+
fields.vertical = select(FIELDS.vertical.labelKey, [
|
|
271
|
+
{ value: 'false', label: ge.t('container.tabs_layout_horizontal') },
|
|
272
|
+
{ value: 'true', label: ge.t('container.tabs_layout_vertical') },
|
|
273
|
+
].concat(fromBreakpoints().map(function(key) {
|
|
274
|
+
return { value: key, label: ge.t('container.tabs_layout_vertical_from', { breakpoint: key }) };
|
|
275
|
+
})), function(value) {
|
|
276
|
+
change('vertical', value === 'true' ? true : value === 'false' ? false : value);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
['variant', 'width', 'align', 'vertical'].forEach(function(key) {
|
|
280
|
+
fields[key].box.setAttribute('data-ge-tabs-variant', key);
|
|
281
|
+
body.appendChild(fields[key].box);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
/** Fill the selects from the classes, and turn off what does not apply. */
|
|
285
|
+
function render() {
|
|
286
|
+
var values = read(container);
|
|
287
|
+
|
|
288
|
+
fields.variant.field.value = values.variant;
|
|
289
|
+
fields.width.field.value = values.width;
|
|
290
|
+
fields.align.field.value = values.align;
|
|
291
|
+
fields.vertical.field.value = String(values.vertical);
|
|
292
|
+
fields.width.field.disabled = values.vertical !== false;
|
|
293
|
+
fields.align.field.disabled = values.vertical !== false || values.width !== 'natural';
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
render();
|
|
297
|
+
sections.push({ container: container, element: body, render: render });
|
|
298
|
+
|
|
299
|
+
return body;
|
|
300
|
+
}
|
|
301
|
+
|
|
23
302
|
function addTabTo(container, options) {
|
|
24
303
|
options = options || {};
|
|
25
304
|
|
|
26
|
-
var strip =
|
|
305
|
+
var strip = stripOf(container);
|
|
27
306
|
var content = dom.one(container, ':scope > .tab-content');
|
|
28
307
|
var id = ge.containerId('tab');
|
|
29
308
|
var number = dom.children(strip, '.nav-item').length + 1;
|
|
@@ -61,7 +340,7 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
61
340
|
});
|
|
62
341
|
dom.addClass(pane, 'show active');
|
|
63
342
|
|
|
64
|
-
dom.all(container, '
|
|
343
|
+
dom.all(stripOf(container) || container, '.nav-link').forEach(function(button) {
|
|
65
344
|
var active = button.getAttribute('data-bs-target') === '#' + id;
|
|
66
345
|
|
|
67
346
|
dom.toggleClass(button, 'active', active);
|
|
@@ -82,7 +361,7 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
82
361
|
// A tab strip sorts its own tabs, and the panes follow them. No
|
|
83
362
|
// group: a tab belongs to the strip it was made in.
|
|
84
363
|
onSortable: function(sortable) {
|
|
85
|
-
sortable(dom.all(ge.canvas, '.ge-container-tabs
|
|
364
|
+
sortable(dom.all(ge.canvas, '.ge-container-tabs').map(stripOf).filter(Boolean), {
|
|
86
365
|
draggable: '.ge-tab',
|
|
87
366
|
});
|
|
88
367
|
},
|
|
@@ -97,6 +376,11 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
97
376
|
container.appendChild(dom.element('ul', { 'class': 'nav nav-tabs', role: 'tablist' }));
|
|
98
377
|
container.appendChild(dom.element('div', { 'class': 'tab-content' }));
|
|
99
378
|
|
|
379
|
+
// The layout last: it takes off what a vertical strip has no use for
|
|
380
|
+
['variant', 'width', 'align', 'vertical'].forEach(function(key) {
|
|
381
|
+
write(container, key, chosen(options, key));
|
|
382
|
+
});
|
|
383
|
+
|
|
100
384
|
for (var i = 0; i < count; i++) {
|
|
101
385
|
addTabTo(container, { label: labels[i] });
|
|
102
386
|
}
|
|
@@ -111,7 +395,7 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
111
395
|
dom.addClass(pane, 'ge-tab-pane');
|
|
112
396
|
});
|
|
113
397
|
|
|
114
|
-
dom.
|
|
398
|
+
dom.children(stripOf(container) || container, '.nav-item').forEach(function(tab) {
|
|
115
399
|
dom.addClass(tab, 'ge-tab');
|
|
116
400
|
|
|
117
401
|
var link = dom.one(tab, '.nav-link');
|
|
@@ -137,17 +421,39 @@ GridEditor.containers.tabs = function(ge) {
|
|
|
137
421
|
|
|
138
422
|
unmark: function(container) {
|
|
139
423
|
ge.resumeToggles(container);
|
|
424
|
+
container.removeAttribute(LAYOUT_ATTR);
|
|
140
425
|
dom.all(container, '.ge-tab-pane').forEach(function(pane) {
|
|
141
426
|
dom.removeClass(pane, 'ge-tab-pane');
|
|
142
427
|
});
|
|
143
428
|
ge.unwrapLabels(container);
|
|
144
429
|
},
|
|
145
430
|
|
|
431
|
+
panelSection: function(node, kind) {
|
|
432
|
+
if (kind !== 'tabs' || !stripOf(node)) { return null; }
|
|
433
|
+
|
|
434
|
+
return { labelKey: 'container.tabs_section', body: createSection(node) };
|
|
435
|
+
},
|
|
436
|
+
|
|
437
|
+
// After a view change or a change of classes: the layout marks and the
|
|
438
|
+
// sections follow
|
|
439
|
+
onRefresh: function(scope) {
|
|
440
|
+
dom.selfAndAll(scope, '[data-ge-container="tabs"]').forEach(markLayout);
|
|
441
|
+
|
|
442
|
+
sections = sections.filter(function(entry) { return entry.element.isConnected; });
|
|
443
|
+
sections.forEach(function(entry) {
|
|
444
|
+
if (entry.container === scope || scope.contains(entry.container)) { entry.render(); }
|
|
445
|
+
});
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
onDeinit: function() {
|
|
449
|
+
sections = [];
|
|
450
|
+
},
|
|
451
|
+
|
|
146
452
|
/** Panes read in tab order, whatever order they were dropped in. */
|
|
147
453
|
afterPaneMove: function(container) {
|
|
148
454
|
var content = dom.one(container, ':scope > .tab-content');
|
|
149
455
|
|
|
150
|
-
dom.
|
|
456
|
+
dom.children(stripOf(container) || container, '.nav-item').forEach(function(tab) {
|
|
151
457
|
var pane = paneOf(container, tab);
|
|
152
458
|
if (pane) { content.appendChild(pane); }
|
|
153
459
|
});
|