@themarioga/grid-editor 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +53 -1
- package/dist/grideditor.css +148 -0
- package/dist/grideditor.min.css +1 -1
- package/dist/grideditor.min.css.map +1 -1
- package/dist/jquery.grideditor.bundle.min.js +2 -2
- package/dist/jquery.grideditor.js +555 -9
- package/dist/jquery.grideditor.min.js +1 -1
- package/dist/jquery.grideditor.min.js.map +1 -1
- package/dist/locales/grideditor.es.js +32 -0
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +1 -1
- package/dist/plugins/grideditor.alignment.js +81 -0
- package/dist/plugins/grideditor.alignment.min.js +2 -0
- package/dist/plugins/grideditor.alignment.min.js.map +1 -0
- package/dist/plugins/grideditor.gutters.js +145 -0
- package/dist/plugins/grideditor.gutters.min.js +2 -0
- package/dist/plugins/grideditor.gutters.min.js.map +1 -0
- package/dist/plugins/grideditor.order.js +206 -0
- package/dist/plugins/grideditor.order.min.js +2 -0
- package/dist/plugins/grideditor.order.min.js.map +1 -0
- package/dist/plugins/grideditor.spacing.js +299 -0
- package/dist/plugins/grideditor.spacing.min.js +2 -0
- package/dist/plugins/grideditor.spacing.min.js.map +1 -0
- package/dist/plugins/grideditor.visibility.js +172 -0
- package/dist/plugins/grideditor.visibility.min.js +2 -0
- package/dist/plugins/grideditor.visibility.min.js.map +1 -0
- package/docs/events.md +20 -1
- package/docs/locale-keys.md +52 -0
- package/docs/plugins.md +108 -3
- package/example/autosave.html +5 -0
- package/example/basic.html +5 -0
- package/example/breakpoints.html +5 -0
- package/example/ckeditor.html +5 -0
- package/example/containers.html +4 -0
- package/example/elements.html +5 -0
- package/example/index.html +24 -1
- package/example/locale.html +5 -0
- package/example/plugins.html +5 -0
- package/example/summernote.html +5 -0
- package/example/utilities.html +145 -0
- package/example/wrap_content.html +5 -0
- package/package.json +1 -1
- package/src/js/jquery.grideditor.js +555 -9
- package/src/js/locales/grideditor.es.js +32 -0
- package/src/js/plugins/grideditor.alignment.js +81 -0
- package/src/js/plugins/grideditor.gutters.js +145 -0
- package/src/js/plugins/grideditor.order.js +206 -0
- package/src/js/plugins/grideditor.spacing.js +299 -0
- package/src/js/plugins/grideditor.visibility.js +172 -0
- package/src/less/grideditor.less +167 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spacing for grid-editor.
|
|
3
|
+
*
|
|
4
|
+
* A utility plugin: load this file after the editor and every row, column,
|
|
5
|
+
* element and container can have its padding and margin set per breakpoint,
|
|
6
|
+
* with Bootstrap's p-{breakpoint}-*, pt-, px- … and m-{breakpoint}-*, mt-, mx-
|
|
7
|
+
* … classes. What it can ask the editor for is the handle its factory is
|
|
8
|
+
* called with, described in docs/plugins.md.
|
|
9
|
+
*
|
|
10
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
11
|
+
* <script src="dist/plugins/grideditor.spacing.min.js"></script>
|
|
12
|
+
*
|
|
13
|
+
* Fourteen families would be fourteen fields, so the panel has two, padding
|
|
14
|
+
* and margin, each a choice of side and a value for that side.
|
|
15
|
+
*
|
|
16
|
+
* utilities.spacing.values narrows the values offered, and
|
|
17
|
+
* utilities.spacing.scale is what 0 to 5 come to, for a page that changed
|
|
18
|
+
* Bootstrap's $spacers.
|
|
19
|
+
*/
|
|
20
|
+
(function($) {
|
|
21
|
+
|
|
22
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
23
|
+
'utility.padding': 'Padding',
|
|
24
|
+
'utility.margin': 'Margin',
|
|
25
|
+
'utility.side_all': 'All sides',
|
|
26
|
+
'utility.side_x': 'Left and right',
|
|
27
|
+
'utility.side_y': 'Top and bottom',
|
|
28
|
+
'utility.side_t': 'Top',
|
|
29
|
+
'utility.side_b': 'Bottom',
|
|
30
|
+
'utility.side_s': 'Start',
|
|
31
|
+
'utility.side_e': 'End',
|
|
32
|
+
'utility.spacing_gutter': 'A column\'s side padding is its gutter: changing it changes the gutter',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
var VALUES = ['0', '1', '2', '3', '4', '5'];
|
|
36
|
+
|
|
37
|
+
/** Bootstrap's $spacers. */
|
|
38
|
+
var SCALE = ['0', '.25rem', '.5rem', '1rem', '1.5rem', '3rem'];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The sides, in the order Bootstrap's css writes their rules: within one
|
|
42
|
+
* breakpoint a later rule wins, so p-3 pt-1 has a top of .25rem.
|
|
43
|
+
*/
|
|
44
|
+
var SIDES = ['', 'x', 'y', 't', 'e', 'b', 's'];
|
|
45
|
+
|
|
46
|
+
/** What each side sets. Start and end are left and right: Bootstrap's css is left to right. */
|
|
47
|
+
var SET = {
|
|
48
|
+
'': ['top', 'right', 'bottom', 'left'],
|
|
49
|
+
x: ['left', 'right'],
|
|
50
|
+
y: ['top', 'bottom'],
|
|
51
|
+
t: ['top'],
|
|
52
|
+
e: ['right'],
|
|
53
|
+
b: ['bottom'],
|
|
54
|
+
s: ['left'],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
var INFIXES = ['', 'sm', 'md', 'lg', 'xl', 'xxl'];
|
|
58
|
+
|
|
59
|
+
var PROPERTIES = { p: 'padding', m: 'margin' };
|
|
60
|
+
|
|
61
|
+
/** Every class of the plugin's, padding or margin. */
|
|
62
|
+
function pattern(key) {
|
|
63
|
+
return new RegExp('^' + key + '[xytbse]?-(?:(?:sm|md|lg|xl|xxl)-)?(?:[0-5]|auto)$');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
$.fn.gridEditor.utilities.spacing = function(ge) {
|
|
67
|
+
|
|
68
|
+
var options = $.extend({ values: VALUES, scale: SCALE }, ge.settings.utilities.spacing);
|
|
69
|
+
var patterns = { p: pattern('p'), m: pattern('m') };
|
|
70
|
+
|
|
71
|
+
function applies(node, kind) {
|
|
72
|
+
return kind === 'row' || kind === 'column' || kind === 'element' ||
|
|
73
|
+
node.is('[data-ge-container]');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function classes(node) {
|
|
77
|
+
return (node.attr('class') || '').split(/\s+/);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function carries(node, key) {
|
|
81
|
+
return classes(node).some(function(name) { return patterns[key].test(name); });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The class of one family that decides a side at a breakpoint: the
|
|
86
|
+
* widest breakpoint up to it that has one, as { tier, value }.
|
|
87
|
+
*/
|
|
88
|
+
function source(node, family, tier) {
|
|
89
|
+
var names = classes(node);
|
|
90
|
+
var values = family.charAt(0) === 'm' ? VALUES.concat(['auto']) : VALUES;
|
|
91
|
+
|
|
92
|
+
for (var i = tier; i >= 0; i--) {
|
|
93
|
+
for (var v = 0; v < values.length; v++) {
|
|
94
|
+
var name = family + (INFIXES[i] ? '-' + INFIXES[i] : '') + '-' + values[v];
|
|
95
|
+
if (names.indexOf(name) !== -1) { return { tier: i, value: values[v] }; }
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* What padding or margin is on each side with none of the plugin's
|
|
104
|
+
* classes: the editor's frame for a row or a column, the host's css
|
|
105
|
+
* for anything else. Read by taking the classes off for a moment,
|
|
106
|
+
* since that is the only way to ask the browser.
|
|
107
|
+
*/
|
|
108
|
+
function without(node, key) {
|
|
109
|
+
var original = node.attr('class');
|
|
110
|
+
var style;
|
|
111
|
+
var bare = {};
|
|
112
|
+
|
|
113
|
+
node.attr('class', classes(node).filter(function(name) { return !patterns[key].test(name); }).join(' '));
|
|
114
|
+
style = getComputedStyle(node[0]);
|
|
115
|
+
['top', 'right', 'bottom', 'left'].forEach(function(side) {
|
|
116
|
+
bare[side] = style.getPropertyValue(PROPERTIES[key] + '-' + side);
|
|
117
|
+
});
|
|
118
|
+
node.attr('class', original);
|
|
119
|
+
|
|
120
|
+
return bare;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Each side the way Bootstrap's css settles it: the class from the
|
|
125
|
+
* widest breakpoint wins, and within one breakpoint the side written
|
|
126
|
+
* later in the css. A side no class reaches shows what it is without
|
|
127
|
+
* any, over a wider breakpoint's class that is live in a wide window.
|
|
128
|
+
*/
|
|
129
|
+
function sides(node, key, breakpoint) {
|
|
130
|
+
var tier = ge.breakpoints.indexOf(breakpoint);
|
|
131
|
+
var winners = {};
|
|
132
|
+
var styles = {};
|
|
133
|
+
var neutral = null;
|
|
134
|
+
|
|
135
|
+
SIDES.forEach(function(side, order) {
|
|
136
|
+
var found = source(node, key + side, tier);
|
|
137
|
+
if (!found) { return; }
|
|
138
|
+
|
|
139
|
+
SET[side].forEach(function(set) {
|
|
140
|
+
var current = winners[set];
|
|
141
|
+
if (!current || found.tier > current.tier || (found.tier === current.tier && order > current.order)) {
|
|
142
|
+
winners[set] = { tier: found.tier, order: order, value: found.value };
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
['top', 'right', 'bottom', 'left'].forEach(function(set) {
|
|
148
|
+
var winner = winners[set];
|
|
149
|
+
|
|
150
|
+
if (!winner) {
|
|
151
|
+
neutral = neutral || without(node, key);
|
|
152
|
+
styles[PROPERTIES[key] + '-' + set] = neutral[set];
|
|
153
|
+
} else {
|
|
154
|
+
styles[PROPERTIES[key] + '-' + set] = winner.value === 'auto' ? 'auto' : options.scale[winner.value];
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return styles;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** The side a group's select starts on: the first that has a class, or all. */
|
|
162
|
+
function startingSide(node, key) {
|
|
163
|
+
var names = classes(node).filter(function(name) { return patterns[key].test(name); });
|
|
164
|
+
var found = SIDES.filter(function(side) {
|
|
165
|
+
return names.some(function(name) { return name.indexOf(key + side + '-') === 0; });
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
return found.length ? found[0] : '';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function sideLabel(side) {
|
|
172
|
+
switch (side) {
|
|
173
|
+
case 'x': return ge.t('utility.side_x');
|
|
174
|
+
case 'y': return ge.t('utility.side_y');
|
|
175
|
+
case 't': return ge.t('utility.side_t');
|
|
176
|
+
case 'b': return ge.t('utility.side_b');
|
|
177
|
+
case 's': return ge.t('utility.side_s');
|
|
178
|
+
case 'e': return ge.t('utility.side_e');
|
|
179
|
+
default: return ge.t('utility.side_all');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** A padding or margin group: its name, the side, and the field of that side's family. */
|
|
184
|
+
function group(node, key, labelText) {
|
|
185
|
+
var box = $('<div class="ge-spacing-group" />').attr('data-ge-spacing', key);
|
|
186
|
+
var side = $('<select class="ge-spacing-side" />');
|
|
187
|
+
|
|
188
|
+
$('<span class="ge-utility-label" />').text(labelText).appendTo(box);
|
|
189
|
+
|
|
190
|
+
SIDES.forEach(function(value) {
|
|
191
|
+
$('<option />').attr('value', value).text(sideLabel(value)).appendTo(side);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
var field = ge.utilityField(node, key + startingSide(node, key));
|
|
195
|
+
|
|
196
|
+
side.val(field.attr('data-ge-family').slice(1))
|
|
197
|
+
.on('change', function() {
|
|
198
|
+
var next = ge.utilityField(node, key + this.value);
|
|
199
|
+
field.replaceWith(next);
|
|
200
|
+
field = next;
|
|
201
|
+
})
|
|
202
|
+
.appendTo(box)
|
|
203
|
+
;
|
|
204
|
+
field.appendTo(box);
|
|
205
|
+
|
|
206
|
+
return box;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
var NODES = '.row, .column, .ge-element, [data-ge-container]';
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Keep each drawer on its node's edges. A drawer is pulled out over the
|
|
213
|
+
* editor's frame by as much as the frame pads the node, and a padding
|
|
214
|
+
* class replaces the frame, so a padded node's drawer is pulled out by
|
|
215
|
+
* its real padding instead. And a column padded at the sides gets a word
|
|
216
|
+
* about what that does to its gutter.
|
|
217
|
+
*/
|
|
218
|
+
function mark(scope) {
|
|
219
|
+
scope.find(NODES).addBack(NODES).each(function() {
|
|
220
|
+
var node = $(this);
|
|
221
|
+
var drawer = node.children('.ge-tools-drawer');
|
|
222
|
+
|
|
223
|
+
if (!drawer.length || !applies(node, ge.kindOf(node))) { return; }
|
|
224
|
+
|
|
225
|
+
if (carries(node, 'p')) {
|
|
226
|
+
var style = getComputedStyle(node[0]);
|
|
227
|
+
|
|
228
|
+
drawer.css({
|
|
229
|
+
marginTop: '-' + style.paddingTop,
|
|
230
|
+
marginLeft: '-' + style.paddingLeft,
|
|
231
|
+
marginRight: '-' + style.paddingRight,
|
|
232
|
+
width: 'calc(100% + ' + style.paddingLeft + ' + ' + style.paddingRight + ')',
|
|
233
|
+
});
|
|
234
|
+
} else {
|
|
235
|
+
drawer.css({ marginTop: '', marginLeft: '', marginRight: '', width: '' });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (node.hasClass('column')) {
|
|
239
|
+
drawer.find('.ge-spacing-gutter').toggle(classes(node).some(function(name) {
|
|
240
|
+
return /^p[xse]?-/.test(name) && patterns.p.test(name);
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function families(key, labelKey) {
|
|
247
|
+
var values = key === 'm' ? VALUES.concat(['auto']) : VALUES;
|
|
248
|
+
var offered = options.values.concat(key === 'm' ? ['auto'] : []);
|
|
249
|
+
|
|
250
|
+
return SIDES.map(function(side) {
|
|
251
|
+
return {
|
|
252
|
+
name: key + side,
|
|
253
|
+
prefix: key + side,
|
|
254
|
+
values: values,
|
|
255
|
+
appliesTo: ['row', 'column', 'element', 'container'],
|
|
256
|
+
labelKey: labelKey,
|
|
257
|
+
panel: false,
|
|
258
|
+
choices: function() {
|
|
259
|
+
return values.filter(function(value) { return offered.indexOf(value) !== -1; });
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
families: families('p', 'utility.padding').concat(families('m', 'utility.margin')),
|
|
267
|
+
|
|
268
|
+
panel: function(node, kind) {
|
|
269
|
+
if (!applies(node, kind)) { return null; }
|
|
270
|
+
|
|
271
|
+
var box = $('<div class="ge-spacing" />')
|
|
272
|
+
.append(group(node, 'p', ge.t('utility.padding')))
|
|
273
|
+
.append(group(node, 'm', ge.t('utility.margin')))
|
|
274
|
+
;
|
|
275
|
+
|
|
276
|
+
if (kind === 'column') {
|
|
277
|
+
$('<small class="ge-spacing-gutter" />').text(ge.t('utility.spacing_gutter')).appendTo(box);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return box;
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
preview: function(node, kind, breakpoint) {
|
|
284
|
+
if (!applies(node, kind)) { return {}; }
|
|
285
|
+
|
|
286
|
+
var styles = {};
|
|
287
|
+
|
|
288
|
+
['p', 'm'].forEach(function(key) {
|
|
289
|
+
if (carries(node, key)) { $.extend(styles, sides(node, key, breakpoint)); }
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
return styles;
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
onRefresh: mark,
|
|
296
|
+
};
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
})(jQuery);
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visibility for grid-editor.
|
|
3
|
+
*
|
|
4
|
+
* A utility plugin: load this file after the editor and every row, column,
|
|
5
|
+
* element and container can be hidden at some breakpoints and shown at
|
|
6
|
+
* others, with Bootstrap's d-{breakpoint}-none and d-{breakpoint}-block (or
|
|
7
|
+
* -flex, for a row, which is a flex container and stops being a grid as a
|
|
8
|
+
* block). What it can ask the editor for is the handle its factory is called
|
|
9
|
+
* with, described in docs/plugins.md.
|
|
10
|
+
*
|
|
11
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
12
|
+
* <script src="dist/plugins/grideditor.visibility.min.js"></script>
|
|
13
|
+
*
|
|
14
|
+
* A hidden node is never hidden from the editor, which would leave nothing to
|
|
15
|
+
* click to show it again. It stays on the canvas, faded and striped in a view
|
|
16
|
+
* where it is hidden, and in the all view says at which breakpoints it is.
|
|
17
|
+
*
|
|
18
|
+
* utilities.visibility.drawer: false leaves the eye out of the drawers, and
|
|
19
|
+
* the panel field is the only control.
|
|
20
|
+
*/
|
|
21
|
+
(function($) {
|
|
22
|
+
|
|
23
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
24
|
+
'utility.visibility': 'Visibility',
|
|
25
|
+
'utility.visibility_hidden': 'Hidden',
|
|
26
|
+
'utility.visibility_shown': 'Shown',
|
|
27
|
+
'tool.hide_in_view': 'Hide in this view',
|
|
28
|
+
'tool.show_in_view': 'Show in this view',
|
|
29
|
+
'badge.hidden_in': 'Hidden at {breakpoints}',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/** A node that carries any class of the family, at any breakpoint. */
|
|
33
|
+
var CLASS_PATTERN = /(?:^|\s)d-(?:(?:sm|md|lg|xl|xxl)-)?(?:none|block|flex)(?:\s|$)/;
|
|
34
|
+
|
|
35
|
+
var NODES = '.row, .column, .ge-element, [data-ge-container]';
|
|
36
|
+
|
|
37
|
+
$.fn.gridEditor.utilities.visibility = function(ge) {
|
|
38
|
+
|
|
39
|
+
var options = $.extend({ drawer: true }, ge.settings.utilities.visibility);
|
|
40
|
+
|
|
41
|
+
/** What "shown" is written as on this kind of node. */
|
|
42
|
+
function shown(kind) {
|
|
43
|
+
return kind === 'row' ? 'flex' : 'block';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function applies(node, kind) {
|
|
47
|
+
return kind === 'row' || kind === 'column' || kind === 'element' ||
|
|
48
|
+
node.is('[data-ge-container]');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function hiddenAt(node, view) {
|
|
52
|
+
return ge.getUtility(node, 'visibility', view) === 'none';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The breakpoints at which the node is hidden, smallest first. */
|
|
56
|
+
function hiddenTiers(node) {
|
|
57
|
+
return ge.breakpoints.filter(function(key) { return hiddenAt(node, key); });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether the node is hidden in the view being edited. In the all view
|
|
62
|
+
* that means hidden at every breakpoint, since "hidden at some" is what
|
|
63
|
+
* the badge is for.
|
|
64
|
+
*/
|
|
65
|
+
function hiddenHere(node) {
|
|
66
|
+
return ge.view() === 'all'
|
|
67
|
+
? hiddenTiers(node).length === ge.breakpoints.length
|
|
68
|
+
: hiddenAt(node, ge.view());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** What the breakpoint below the view shows, which an inherit falls back to. */
|
|
72
|
+
function hiddenBelow(node) {
|
|
73
|
+
var index = ge.breakpoints.indexOf(ge.view());
|
|
74
|
+
|
|
75
|
+
return index > 0 && hiddenAt(node, ge.breakpoints[index - 1]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Hide or show the node in the view being edited, with as few classes as
|
|
80
|
+
* that takes. In a breakpoint view that is often none at all: showing a
|
|
81
|
+
* node the breakpoint below shows removes this breakpoint's d-*-none
|
|
82
|
+
* rather than writing a d-*-block on top of it. In the all view a node
|
|
83
|
+
* is hidden everywhere or shown everywhere, and shown is no class.
|
|
84
|
+
*/
|
|
85
|
+
function toggle(node, kind) {
|
|
86
|
+
var hide = !hiddenHere(node);
|
|
87
|
+
var value;
|
|
88
|
+
|
|
89
|
+
if (ge.view() === 'all') {
|
|
90
|
+
value = hide ? 'none' : null;
|
|
91
|
+
} else if (hide) {
|
|
92
|
+
value = hiddenBelow(node) ? null : 'none';
|
|
93
|
+
} else {
|
|
94
|
+
value = hiddenBelow(node) ? shown(kind) : null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
ge.setUtility(node, 'visibility', value, { source: 'tool' });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The canvas shows each node as the view sees it. ge-visibility keeps a
|
|
102
|
+
* node Bootstrap would hide on the canvas, ge-hidden-in-view fades it,
|
|
103
|
+
* and data-ge-hidden-in carries the badge text for the all view.
|
|
104
|
+
*/
|
|
105
|
+
function mark(scope) {
|
|
106
|
+
scope.find(NODES).addBack(NODES).each(function() {
|
|
107
|
+
var node = $(this);
|
|
108
|
+
var kind = ge.kindOf(node);
|
|
109
|
+
var carries = applies(node, kind) && CLASS_PATTERN.test(node.attr('class') || '');
|
|
110
|
+
var tiers = carries ? hiddenTiers(node) : [];
|
|
111
|
+
var here = carries && hiddenHere(node);
|
|
112
|
+
var partly = carries && ge.view() === 'all' && tiers.length > 0 && !here;
|
|
113
|
+
|
|
114
|
+
node.toggleClass('ge-visibility', carries).toggleClass('ge-hidden-in-view', here);
|
|
115
|
+
|
|
116
|
+
if (partly) {
|
|
117
|
+
node.attr('data-ge-hidden-in', ge.t('badge.hidden_in', { breakpoints: tiers.join(', ') }));
|
|
118
|
+
} else {
|
|
119
|
+
node.removeAttr('data-ge-hidden-in');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
node.children('.ge-tools-drawer').children('.ge-visibility-tool').each(function() {
|
|
123
|
+
$(this)
|
|
124
|
+
.attr('title', here ? ge.t('tool.show_in_view') : ge.t('tool.hide_in_view'))
|
|
125
|
+
.find('i').attr('class', here ? 'bi bi-eye-slash' : 'bi bi-eye');
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function unmark() {
|
|
131
|
+
ge.canvas.find('.ge-visibility, .ge-hidden-in-view, [data-ge-hidden-in]').each(function() {
|
|
132
|
+
var node = $(this)
|
|
133
|
+
.removeClass('ge-visibility ge-hidden-in-view')
|
|
134
|
+
.removeAttr('data-ge-hidden-in')
|
|
135
|
+
;
|
|
136
|
+
|
|
137
|
+
if (!node.attr('class')) { node.removeAttr('class'); }
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
families: [{
|
|
143
|
+
name: 'visibility',
|
|
144
|
+
prefix: 'd',
|
|
145
|
+
values: ['none', 'block', 'flex'],
|
|
146
|
+
appliesTo: ['row', 'column', 'element', 'container'],
|
|
147
|
+
labelKey: 'utility.visibility',
|
|
148
|
+
|
|
149
|
+
/** Hidden, or shown the way this kind of node is shown. */
|
|
150
|
+
choices: function(node, kind) {
|
|
151
|
+
return ['none', shown(kind)];
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
label: function(value) {
|
|
155
|
+
return value === 'none' ? ge.t('utility.visibility_hidden') : ge.t('utility.visibility_shown');
|
|
156
|
+
},
|
|
157
|
+
}],
|
|
158
|
+
|
|
159
|
+
drawerTools: function(drawer, node, kind) {
|
|
160
|
+
if (!options.drawer || !applies(node, kind)) { return; }
|
|
161
|
+
|
|
162
|
+
ge.createTool(drawer, ge.t('tool.hide_in_view'), 'ge-visibility-tool', 'bi bi-eye', function() {
|
|
163
|
+
toggle(node, kind);
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
onRefresh: mark,
|
|
168
|
+
onDeinit: unmark,
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
})(jQuery);
|
package/src/less/grideditor.less
CHANGED
|
@@ -207,6 +207,83 @@
|
|
|
207
207
|
input.ge-classes {
|
|
208
208
|
width: 200px;
|
|
209
209
|
}
|
|
210
|
+
|
|
211
|
+
/* The utility plugins' fields, folded under one toggle */
|
|
212
|
+
.ge-utilities {
|
|
213
|
+
margin-top: 5px;
|
|
214
|
+
font-size: 11px;
|
|
215
|
+
|
|
216
|
+
> .ge-utilities-toggle {
|
|
217
|
+
color: #333;
|
|
218
|
+
cursor: pointer;
|
|
219
|
+
text-decoration: none;
|
|
220
|
+
|
|
221
|
+
&::before {
|
|
222
|
+
content: '\25B8';
|
|
223
|
+
display: inline-block;
|
|
224
|
+
width: 1em;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
&.ge-open > .ge-utilities-toggle::before {
|
|
228
|
+
content: '\25BE';
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
> .ge-utilities-body {
|
|
232
|
+
display: none;
|
|
233
|
+
flex-wrap: wrap;
|
|
234
|
+
gap: 4px 10px;
|
|
235
|
+
margin-top: 4px;
|
|
236
|
+
}
|
|
237
|
+
&.ge-open > .ge-utilities-body {
|
|
238
|
+
display: flex;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.ge-utility {
|
|
242
|
+
display: inline-flex;
|
|
243
|
+
flex-direction: column;
|
|
244
|
+
margin: 0;
|
|
245
|
+
|
|
246
|
+
select {
|
|
247
|
+
border: 1px solid #7F7F7F;
|
|
248
|
+
border-radius: 4px;
|
|
249
|
+
font-size: 11px;
|
|
250
|
+
padding: 1px 2px;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
.ge-utility-note {
|
|
254
|
+
color: #666;
|
|
255
|
+
font-size: 10px;
|
|
256
|
+
max-width: 160px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* The spacing plugin: a side and a value per group */
|
|
260
|
+
.ge-spacing {
|
|
261
|
+
display: flex;
|
|
262
|
+
flex-wrap: wrap;
|
|
263
|
+
gap: 4px 10px;
|
|
264
|
+
}
|
|
265
|
+
.ge-spacing-group {
|
|
266
|
+
display: inline-flex;
|
|
267
|
+
flex-direction: column;
|
|
268
|
+
|
|
269
|
+
> .ge-spacing-side {
|
|
270
|
+
border: 1px solid #7F7F7F;
|
|
271
|
+
border-radius: 4px;
|
|
272
|
+
font-size: 11px;
|
|
273
|
+
padding: 1px 2px;
|
|
274
|
+
margin-bottom: 2px;
|
|
275
|
+
}
|
|
276
|
+
/* The group names the field once */
|
|
277
|
+
.ge-utility > .ge-utility-label {
|
|
278
|
+
display: none;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
.ge-spacing-gutter {
|
|
282
|
+
flex-basis: 100%;
|
|
283
|
+
color: #666;
|
|
284
|
+
font-size: 10px;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
210
287
|
}
|
|
211
288
|
}
|
|
212
289
|
.row {
|
|
@@ -617,3 +694,93 @@
|
|
|
617
694
|
}
|
|
618
695
|
|
|
619
696
|
.ge-layout-modes();
|
|
697
|
+
|
|
698
|
+
/*
|
|
699
|
+
* The visibility plugin. A node Bootstrap would hide is kept on the canvas -
|
|
700
|
+
* there would be nothing left to click to show it again - and shown the way
|
|
701
|
+
* the view sees it instead. The selectors outweigh Bootstrap's d-* classes,
|
|
702
|
+
* which are !important too.
|
|
703
|
+
*/
|
|
704
|
+
.ge-canvas.ge-editing {
|
|
705
|
+
.ge-visibility {
|
|
706
|
+
display: block !important;
|
|
707
|
+
}
|
|
708
|
+
.row.ge-visibility {
|
|
709
|
+
display: flex !important;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.ge-hidden-in-view {
|
|
713
|
+
opacity: .45;
|
|
714
|
+
background-image: repeating-linear-gradient(
|
|
715
|
+
-45deg, transparent 0, transparent 6px, rgba(0, 0, 0, .07) 6px, rgba(0, 0, 0, .07) 12px
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/* The all view: hidden at some breakpoints, said in a corner */
|
|
720
|
+
[data-ge-hidden-in] {
|
|
721
|
+
position: relative;
|
|
722
|
+
|
|
723
|
+
&::after {
|
|
724
|
+
content: attr(data-ge-hidden-in);
|
|
725
|
+
position: absolute;
|
|
726
|
+
right: 2px;
|
|
727
|
+
bottom: 2px;
|
|
728
|
+
z-index: 1;
|
|
729
|
+
padding: 0 4px;
|
|
730
|
+
border-radius: 3px;
|
|
731
|
+
background: rgba(0, 0, 0, .6);
|
|
732
|
+
color: #fff;
|
|
733
|
+
font-size: 10px;
|
|
734
|
+
line-height: 16px;
|
|
735
|
+
pointer-events: none;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/* The order plugin: a column ordered by class in this view says where */
|
|
741
|
+
.ge-canvas.ge-editing .column[data-ge-order]::before {
|
|
742
|
+
content: attr(data-ge-order);
|
|
743
|
+
position: absolute;
|
|
744
|
+
left: 2px;
|
|
745
|
+
bottom: 2px;
|
|
746
|
+
z-index: 1;
|
|
747
|
+
padding: 0 4px;
|
|
748
|
+
border-radius: 3px;
|
|
749
|
+
background: fade(@colTextColor, 85%);
|
|
750
|
+
color: #fff;
|
|
751
|
+
font-size: 10px;
|
|
752
|
+
line-height: 16px;
|
|
753
|
+
pointer-events: none;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/*
|
|
757
|
+
* The gutters plugin. A row with gutter classes is drawn with its real
|
|
758
|
+
* gutters rather than the editor's frame: each column padded by half the
|
|
759
|
+
* horizontal gutter, and the vertical gutter above each column. Bootstrap
|
|
760
|
+
* takes the first line's back with a negative top margin on the row, which
|
|
761
|
+
* here would pull it over the row above, so the row's drawer takes it back
|
|
762
|
+
* instead and the gap shows between lines of columns only.
|
|
763
|
+
*/
|
|
764
|
+
.ge-canvas.ge-editing .row.ge-gutters {
|
|
765
|
+
margin-top: 0;
|
|
766
|
+
|
|
767
|
+
> .ge-tools-drawer {
|
|
768
|
+
margin-top: 0;
|
|
769
|
+
margin-bottom: calc(@editGutter - var(--bs-gutter-y));
|
|
770
|
+
/* Bootstrap pads every child of a row by half its gutter, the drawer
|
|
771
|
+
too; it keeps the padding a row with no gutter class gives it */
|
|
772
|
+
padding-left: .75rem;
|
|
773
|
+
padding-right: .75rem;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
> .column {
|
|
777
|
+
padding-left: calc(var(--bs-gutter-x) * .5);
|
|
778
|
+
padding-right: calc(var(--bs-gutter-x) * .5);
|
|
779
|
+
|
|
780
|
+
> .ge-tools-drawer {
|
|
781
|
+
margin-left: calc(var(--bs-gutter-x) * -.5);
|
|
782
|
+
margin-right: calc(var(--bs-gutter-x) * -.5);
|
|
783
|
+
width: calc(100% + var(--bs-gutter-x));
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|