@themarioga/grid-editor 4.1.0 → 5.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 +80 -0
- package/README.md +131 -10
- package/UPGRADING.md +55 -0
- package/dist/grideditor.css +466 -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 +741 -126
- package/dist/jquery.grideditor.min.js +1 -1
- package/dist/jquery.grideditor.min.js.map +1 -1
- package/dist/locales/grideditor.es.js +30 -0
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +1 -1
- package/dist/plugins/grideditor.clipboard.js +274 -0
- package/dist/plugins/grideditor.clipboard.min.js +2 -0
- package/dist/plugins/grideditor.clipboard.min.js.map +1 -0
- package/dist/plugins/grideditor.float.js +56 -0
- package/dist/plugins/grideditor.float.min.js +2 -0
- package/dist/plugins/grideditor.float.min.js.map +1 -0
- package/dist/plugins/grideditor.sections.js +199 -0
- package/dist/plugins/grideditor.sections.min.js +2 -0
- package/dist/plugins/grideditor.sections.min.js.map +1 -0
- package/dist/plugins/grideditor.textalign.js +60 -0
- package/dist/plugins/grideditor.textalign.min.js +2 -0
- package/dist/plugins/grideditor.textalign.min.js.map +1 -0
- package/docs/events.md +17 -3
- package/docs/locale-keys.md +49 -1
- package/docs/plugins.md +45 -3
- package/example/autocols.html +137 -0
- package/example/breakpoints.html +7 -5
- package/example/clipboard.html +99 -0
- package/example/index.html +24 -2
- package/example/utilities.html +22 -1
- package/example/wrap_content.html +66 -16
- package/package.json +1 -1
- package/src/js/jquery.grideditor.js +742 -127
- package/src/js/locales/grideditor.es.js +30 -0
- package/src/js/plugins/grideditor.clipboard.js +274 -0
- package/src/js/plugins/grideditor.float.js +56 -0
- package/src/js/plugins/grideditor.sections.js +199 -0
- package/src/js/plugins/grideditor.textalign.js +60 -0
- package/src/less/grideditor.less +138 -0
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
'tool.add_row': 'Añadir fila',
|
|
22
22
|
'tool.add_column': 'Añadir columna\n(mantén pulsado para elegir el ancho)',
|
|
23
23
|
'tool.column_size': '{size} de 12',
|
|
24
|
+
'tool.column_equal': 'Igual: reparte lo que queda de la fila',
|
|
25
|
+
'tool.column_auto': 'Auto: tan ancha como su contenido',
|
|
24
26
|
'tool.delete_row': 'Borrar fila',
|
|
25
27
|
'tool.delete_column': 'Borrar columna',
|
|
26
28
|
'tool.delete_element': 'Borrar elemento',
|
|
@@ -41,6 +43,7 @@
|
|
|
41
43
|
'tool.classes_title': 'Clases css, separadas por espacios',
|
|
42
44
|
'tool.toggle_class': 'Aplicar o quitar el estilo "{label}"',
|
|
43
45
|
'row.add': 'Añadir fila {layout}',
|
|
46
|
+
'row.add_row_cols': 'Añadir una fila de {columns} columnas, {counts} por fila',
|
|
44
47
|
'container.add_tabs': 'Pestañas',
|
|
45
48
|
'container.add_tab': 'Añadir pestaña',
|
|
46
49
|
'container.tab_label': 'Pestaña {number}',
|
|
@@ -70,6 +73,25 @@
|
|
|
70
73
|
'view.xl': 'Escritorio grande',
|
|
71
74
|
'view.xxl': 'Pantalla panorámica',
|
|
72
75
|
'utility.section': 'Responsive: {view}',
|
|
76
|
+
'utility.col_width': 'Ancho',
|
|
77
|
+
'utility.col_equal': 'Igual',
|
|
78
|
+
'utility.col_auto': 'Auto',
|
|
79
|
+
'section.add': 'Sección',
|
|
80
|
+
'section.width': 'Ancho',
|
|
81
|
+
'section.fixed': 'Fijo',
|
|
82
|
+
'section.fluid': 'Ancho completo',
|
|
83
|
+
'section.from': 'Fijo desde {breakpoint}',
|
|
84
|
+
'tool.add_row_to_section': 'Añadir fila',
|
|
85
|
+
'tool.delete_section': 'Quitar sección',
|
|
86
|
+
'confirm.delete_section': '¿Seguro que quieres borrar esta sección y todo su contenido?',
|
|
87
|
+
'tool.copy': 'Copiar',
|
|
88
|
+
'tool.paste': 'Pegar',
|
|
89
|
+
'clipboard.paste_row': 'Pegar fila',
|
|
90
|
+
'clipboard.paste_section': 'Pegar sección',
|
|
91
|
+
'utility.col_from_row': 'De la fila: {count}',
|
|
92
|
+
'utility.row_cols': 'Columnas por fila',
|
|
93
|
+
'badge.row_cols': '{count} por fila',
|
|
94
|
+
'badge.row_cols_auto': 'Tan anchas como su contenido',
|
|
73
95
|
'utility.default': 'Por defecto',
|
|
74
96
|
'utility.inherit': 'Hereda: {value} (de {breakpoint})',
|
|
75
97
|
'utility.varies': 'Cambia en {breakpoints}; elegir aquí lo sustituye',
|
|
@@ -100,6 +122,14 @@
|
|
|
100
122
|
'utility.side_b': 'Abajo',
|
|
101
123
|
'utility.side_s': 'Inicio',
|
|
102
124
|
'utility.side_e': 'Fin',
|
|
125
|
+
'utility.text_align': 'Alineación del texto',
|
|
126
|
+
'utility.text_start': 'Inicio',
|
|
127
|
+
'utility.text_center': 'Centro',
|
|
128
|
+
'utility.text_end': 'Fin',
|
|
129
|
+
'utility.float': 'Flotar',
|
|
130
|
+
'utility.float_start': 'Inicio',
|
|
131
|
+
'utility.float_end': 'Fin',
|
|
132
|
+
'utility.float_none': 'Ninguno',
|
|
103
133
|
'utility.spacing_gutter': 'El relleno lateral de una columna es su espaciado: cambiarlo cambia el espacio entre columnas',
|
|
104
134
|
'error.sortable_missing': '¡SortableJS no está disponible! Asegúrate de haber cargado el archivo js de Sortable; sin él no se puede arrastrar.',
|
|
105
135
|
'warning.setting_removed': 'El ajuste {setting} se eliminó en la 4.0. Usa {replacement} en su lugar.',
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy and paste for grid-editor.
|
|
3
|
+
*
|
|
4
|
+
* A feature plugin: load this file after the editor and every row, column,
|
|
5
|
+
* section, container and element gets a copy tool, and every place one of
|
|
6
|
+
* them can go gets a paste tool while there is something copied that fits.
|
|
7
|
+
* What it can ask the editor for is the handle its factory is called with,
|
|
8
|
+
* described in docs/plugins.md.
|
|
9
|
+
*
|
|
10
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
11
|
+
* <script src="dist/plugins/grideditor.clipboard.min.js"></script>
|
|
12
|
+
*
|
|
13
|
+
* What is copied is kept in localStorage, so it survives a reload and can be
|
|
14
|
+
* pasted in another tab or another editor of the same site. A browser that
|
|
15
|
+
* will not give the page its storage keeps it in memory, for this page only.
|
|
16
|
+
*
|
|
17
|
+
* A paste is an add like any other - before-add-* and after-add-*, with
|
|
18
|
+
* `source: 'paste'` - so a host can turn one away.
|
|
19
|
+
*/
|
|
20
|
+
(function($) {
|
|
21
|
+
|
|
22
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
23
|
+
'tool.copy': 'Copy',
|
|
24
|
+
'tool.paste': 'Paste',
|
|
25
|
+
'clipboard.paste_row': 'Paste row',
|
|
26
|
+
'clipboard.paste_section': 'Paste section',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
var STORAGE_ITEM = 'grideditor.clipboard';
|
|
30
|
+
var CHANGE = 'grideditor-clipboard';
|
|
31
|
+
var VERSION = 1;
|
|
32
|
+
|
|
33
|
+
/** Where nothing can be stored, what was copied lives here, for this page. */
|
|
34
|
+
var memory = null;
|
|
35
|
+
var editors = 0;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* What each drawer takes when something is pasted into it, by the kind of the
|
|
39
|
+
* node the drawer belongs to. A category is what was copied: a row, a column,
|
|
40
|
+
* a section, a container of any type, an element.
|
|
41
|
+
*/
|
|
42
|
+
var TARGETS = {
|
|
43
|
+
column: ['row', 'container', 'element'],
|
|
44
|
+
row: ['column'],
|
|
45
|
+
section: ['row'],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The attributes that point at an id, as the id itself or as a #selector.
|
|
50
|
+
* A pasted copy that has to take new ids takes them here too, so its tabs,
|
|
51
|
+
* its accordion and its popups still point at their own panes.
|
|
52
|
+
*/
|
|
53
|
+
var REFERENCES = ['data-bs-target', 'data-bs-parent', 'href', 'aria-controls', 'aria-labelledby',
|
|
54
|
+
'aria-describedby', 'for', 'data-ge-popup-id', 'data-ge-popup-target'];
|
|
55
|
+
|
|
56
|
+
/** An id grid-editor generated: ge-{type}-{counter}-{random}. */
|
|
57
|
+
var GENERATED_ID = /^ge-([a-z][a-z-]*?)-\d+-[a-z0-9]+$/;
|
|
58
|
+
|
|
59
|
+
function read() {
|
|
60
|
+
var raw;
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
raw = window.localStorage.getItem(STORAGE_ITEM);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
return memory;
|
|
66
|
+
}
|
|
67
|
+
if (raw === null) { return memory; }
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
var clip = JSON.parse(raw);
|
|
71
|
+
return clip && clip.version === VERSION && clip.html ? clip : null;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function write(clip) {
|
|
78
|
+
try {
|
|
79
|
+
window.localStorage.setItem(STORAGE_ITEM, JSON.stringify(clip));
|
|
80
|
+
memory = null;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
memory = clip;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
$(document).trigger(CHANGE);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Another tab copied something: every editor here looks again
|
|
89
|
+
$(window).on('storage', function(e) {
|
|
90
|
+
if (e.originalEvent && e.originalEvent.key === STORAGE_ITEM) { $(document).trigger(CHANGE); }
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
$.fn.gridEditor.features.clipboard = function(ge) {
|
|
94
|
+
|
|
95
|
+
var namespace = '.ge-clipboard-' + (++editors);
|
|
96
|
+
var shown = null; // What the toolbar's paste buttons stand for
|
|
97
|
+
|
|
98
|
+
function used(name) {
|
|
99
|
+
return !ge.settings.plugins || ge.settings.plugins.indexOf(name) !== -1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A category this editor can take: the plugin that makes it is here. */
|
|
103
|
+
function available(clip) {
|
|
104
|
+
if (clip.category === 'container') {
|
|
105
|
+
return !!$.fn.gridEditor.containers[clip.kind] && used(clip.kind);
|
|
106
|
+
}
|
|
107
|
+
if (clip.category === 'section') { return !!$.fn.gridEditor.features.sections && used('sections'); }
|
|
108
|
+
if (clip.category === 'element') { return !!$.fn.gridEditor.features.elements && used('elements'); }
|
|
109
|
+
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function fits(clip, categories) {
|
|
114
|
+
return !!clip && categories.indexOf(clip.category) !== -1 && available(clip);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function categoryOf(kind) {
|
|
118
|
+
if ($.fn.gridEditor.containers[kind]) { return 'container'; }
|
|
119
|
+
|
|
120
|
+
return ['row', 'column', 'section', 'element'].indexOf(kind) !== -1 ? kind : null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function copy(node, kind) {
|
|
124
|
+
var html = ge.nodeHtml(node);
|
|
125
|
+
|
|
126
|
+
write({ version: VERSION, category: categoryOf(kind), kind: kind, html: html });
|
|
127
|
+
ge.emit('after-copy', ge.payloadFor(kind, node, { source: 'tool' }));
|
|
128
|
+
|
|
129
|
+
// The canvas came back with new drawers: the one to flash is the
|
|
130
|
+
// node's new copy tool
|
|
131
|
+
var tool = node.children('.ge-tools-drawer').find('> .ge-copy');
|
|
132
|
+
tool.addClass('ge-copied').find('i').attr('class', 'bi bi-check2');
|
|
133
|
+
setTimeout(function() {
|
|
134
|
+
tool.removeClass('ge-copied').find('i').attr('class', 'bi bi-copy');
|
|
135
|
+
}, 1200);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function paste(target, categories) {
|
|
139
|
+
var clip = read();
|
|
140
|
+
if (!fits(clip, categories)) { return; }
|
|
141
|
+
|
|
142
|
+
var node = fresh(clip.html);
|
|
143
|
+
var into = target;
|
|
144
|
+
|
|
145
|
+
// An element goes into the column's last content area. With none,
|
|
146
|
+
// the column's next init wraps it in one of its own
|
|
147
|
+
if (clip.category === 'element') {
|
|
148
|
+
var area = target.children('.ge-content').last();
|
|
149
|
+
if (area.length) { into = area; }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
ge.place(node, clip.kind, { appendTo: into, source: 'paste' });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The copied markup as a node, with new ids where the page already has
|
|
157
|
+
* them: two copies of a tab strip pointing at one set of panes is a tab
|
|
158
|
+
* strip that opens the other copy's tabs. An id the page does not have
|
|
159
|
+
* is kept, so pasting into another page changes nothing.
|
|
160
|
+
*/
|
|
161
|
+
function fresh(html) {
|
|
162
|
+
var node = $($.parseHTML(html.trim(), document, true)).first();
|
|
163
|
+
var renamed = {};
|
|
164
|
+
var taken = function(id) {
|
|
165
|
+
return !!document.getElementById(id) || Object.keys(renamed).some(function(old) {
|
|
166
|
+
return renamed[old] === id;
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
node.find('[id]').addBack('[id]').each(function() {
|
|
171
|
+
var id = this.id;
|
|
172
|
+
if (!document.getElementById(id)) { return; }
|
|
173
|
+
|
|
174
|
+
var generated = GENERATED_ID.exec(id);
|
|
175
|
+
var next;
|
|
176
|
+
|
|
177
|
+
if (generated) {
|
|
178
|
+
do { next = ge.containerId(generated[1]); } while (taken(next));
|
|
179
|
+
} else {
|
|
180
|
+
var n = 2;
|
|
181
|
+
while (taken(id + '-' + n)) { n++; }
|
|
182
|
+
next = id + '-' + n;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
renamed[id] = next;
|
|
186
|
+
this.id = next;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (!Object.keys(renamed).length) { return node; }
|
|
190
|
+
|
|
191
|
+
node.find('*').addBack().each(function() {
|
|
192
|
+
var element = this;
|
|
193
|
+
|
|
194
|
+
REFERENCES.forEach(function(name) {
|
|
195
|
+
var value = element.getAttribute(name);
|
|
196
|
+
if (value === null) { return; }
|
|
197
|
+
if (name === 'href' && value.charAt(0) !== '#') { return; }
|
|
198
|
+
|
|
199
|
+
var rewritten = value.split(/(\s+)/).map(function(token) {
|
|
200
|
+
if (renamed[token]) { return renamed[token]; }
|
|
201
|
+
if (token.charAt(0) === '#' && renamed[token.slice(1)]) { return '#' + renamed[token.slice(1)]; }
|
|
202
|
+
|
|
203
|
+
return token;
|
|
204
|
+
}).join('');
|
|
205
|
+
|
|
206
|
+
if (rewritten !== value) { element.setAttribute(name, rewritten); }
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
return node;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Show the paste tools, and the toolbar's paste buttons, that fit what is copied. */
|
|
214
|
+
function refresh() {
|
|
215
|
+
var clip = read();
|
|
216
|
+
|
|
217
|
+
ge.canvas.find('.ge-paste').each(function() {
|
|
218
|
+
$(this).toggle(fits(clip, $(this).attr('data-ge-paste').split(' ')));
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
ge.toolbarItems('clipboard').each(function() {
|
|
222
|
+
var item = TOOLBAR[parseInt($(this).attr('data-ge-item'), 10)];
|
|
223
|
+
$(this).toggle(fits(clip, [item.kind]));
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
shown = clip;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
var TOOLBAR = [
|
|
230
|
+
{ kind: 'row', labelKey: 'clipboard.paste_row' },
|
|
231
|
+
{ kind: 'section', labelKey: 'clipboard.paste_section' },
|
|
232
|
+
].map(function(item) {
|
|
233
|
+
return $.extend(item, {
|
|
234
|
+
iconClass: 'bi bi-clipboard-plus',
|
|
235
|
+
source: 'paste',
|
|
236
|
+
// What the button showed, even if another tab has copied
|
|
237
|
+
// something else since
|
|
238
|
+
create: function() { return fresh(shown.html); },
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
drawerTools: function(drawer, node, kind) {
|
|
244
|
+
if (categoryOf(kind)) {
|
|
245
|
+
ge.createTool(drawer, ge.t('tool.copy'), 'ge-copy', 'bi bi-copy', function() {
|
|
246
|
+
copy(node, kind);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
var categories = TARGETS[kind];
|
|
251
|
+
if (!categories) { return; }
|
|
252
|
+
|
|
253
|
+
ge.createTool(drawer, ge.t('tool.paste'), 'ge-paste', 'bi bi-clipboard-plus', function() {
|
|
254
|
+
paste(node, categories);
|
|
255
|
+
});
|
|
256
|
+
drawer.children('.ge-paste').last()
|
|
257
|
+
.attr('data-ge-paste', categories.join(' '))
|
|
258
|
+
.toggle(fits(read(), categories));
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
toolbar: TOOLBAR,
|
|
262
|
+
|
|
263
|
+
onInit: function() {
|
|
264
|
+
refresh();
|
|
265
|
+
$(document).off(CHANGE + namespace).on(CHANGE + namespace, refresh);
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
onDeinit: function() {
|
|
269
|
+
$(document).off(CHANGE + namespace);
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
})(jQuery);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Floating elements for grid-editor.
|
|
3
|
+
*
|
|
4
|
+
* A utility plugin: load this file after the editor and after the elements
|
|
5
|
+
* plugin, and an element can float to the start or the end of its content
|
|
6
|
+
* area per breakpoint, with the text around it, using Bootstrap's
|
|
7
|
+
* float-{breakpoint}-start, -end and -none classes. What it can ask the
|
|
8
|
+
* editor for is the handle its factory is called with, described in
|
|
9
|
+
* docs/plugins.md.
|
|
10
|
+
*
|
|
11
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
12
|
+
* <script src="dist/plugins/grideditor.elements.min.js"></script>
|
|
13
|
+
* <script src="dist/plugins/grideditor.float.min.js"></script>
|
|
14
|
+
*
|
|
15
|
+
* Elements only. A floated row or column stops being part of the grid, and a
|
|
16
|
+
* container sits beside the content areas rather than in their text.
|
|
17
|
+
*/
|
|
18
|
+
(function($) {
|
|
19
|
+
|
|
20
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
21
|
+
'utility.float': 'Float',
|
|
22
|
+
'utility.float_start': 'Start',
|
|
23
|
+
'utility.float_end': 'End',
|
|
24
|
+
'utility.float_none': 'None',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/** Start and end are left and right: Bootstrap's css is left to right. */
|
|
28
|
+
var CSS = { start: 'left', end: 'right', none: 'none' };
|
|
29
|
+
|
|
30
|
+
$.fn.gridEditor.utilities.float = function(ge) {
|
|
31
|
+
|
|
32
|
+
function label(value) {
|
|
33
|
+
if (value === 'start') { return ge.t('utility.float_start'); }
|
|
34
|
+
if (value === 'end') { return ge.t('utility.float_end'); }
|
|
35
|
+
|
|
36
|
+
return ge.t('utility.float_none');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
families: [{
|
|
41
|
+
name: 'float',
|
|
42
|
+
prefix: 'float',
|
|
43
|
+
values: ['start', 'end', 'none'],
|
|
44
|
+
appliesTo: ['element'],
|
|
45
|
+
labelKey: 'utility.float',
|
|
46
|
+
label: label,
|
|
47
|
+
|
|
48
|
+
/** With no class applying here, whatever the host's css floats it as. */
|
|
49
|
+
preview: function(value, node) {
|
|
50
|
+
return { float: value === null ? ge.bareStyle(node, 'float', 'float') : CSS[value] };
|
|
51
|
+
},
|
|
52
|
+
}],
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
})(jQuery);
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sections for grid-editor.
|
|
3
|
+
*
|
|
4
|
+
* A feature plugin: load this file after the editor and the canvas can hold
|
|
5
|
+
* sections - Bootstrap's .container, .container-fluid and .container-{bp} -
|
|
6
|
+
* each grouping rows at a width of its own. What it can ask the editor for is
|
|
7
|
+
* the handle its factory is called with, described in docs/plugins.md.
|
|
8
|
+
*
|
|
9
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
10
|
+
* <script src="dist/plugins/grideditor.sections.min.js"></script>
|
|
11
|
+
*
|
|
12
|
+
* Called sections, not containers, because a container is what the tabs,
|
|
13
|
+
* accordion, popup and card plugins make. A section is recognised by its
|
|
14
|
+
* Bootstrap class alone, and only as a child of the canvas: a .container
|
|
15
|
+
* somewhere inside an element's markup is that element's business.
|
|
16
|
+
*
|
|
17
|
+
* sections.widths narrows the widths the field offers.
|
|
18
|
+
*/
|
|
19
|
+
(function($) {
|
|
20
|
+
|
|
21
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
22
|
+
'section.add': 'Section',
|
|
23
|
+
'section.width': 'Width',
|
|
24
|
+
'section.fixed': 'Fixed',
|
|
25
|
+
'section.fluid': 'Full width',
|
|
26
|
+
'section.from': 'Fixed from {breakpoint}',
|
|
27
|
+
'tool.add_row_to_section': 'Add row',
|
|
28
|
+
'tool.delete_section': 'Remove section',
|
|
29
|
+
'confirm.delete_section': 'Delete this section and everything in it?',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/** Each width, and the class that gives it. */
|
|
33
|
+
var WIDTHS = {
|
|
34
|
+
fixed: 'container',
|
|
35
|
+
fluid: 'container-fluid',
|
|
36
|
+
sm: 'container-sm',
|
|
37
|
+
md: 'container-md',
|
|
38
|
+
lg: 'container-lg',
|
|
39
|
+
xl: 'container-xl',
|
|
40
|
+
xxl: 'container-xxl',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
var ORDER = ['fixed', 'sm', 'md', 'lg', 'xl', 'xxl', 'fluid'];
|
|
44
|
+
|
|
45
|
+
$.fn.gridEditor.features.sections = function(ge) {
|
|
46
|
+
|
|
47
|
+
var options = $.extend({ widths: ORDER }, ge.settings.sections);
|
|
48
|
+
|
|
49
|
+
function widthOf(section) {
|
|
50
|
+
var found = null;
|
|
51
|
+
|
|
52
|
+
$.each(WIDTHS, function(width, className) {
|
|
53
|
+
if (!found && section.hasClass(className)) { found = width; }
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return found;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isSection(node) {
|
|
60
|
+
return node.parent()[0] === ge.canvas[0] && widthOf(node) !== null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function sections() {
|
|
64
|
+
return ge.canvas.children().filter(function() { return isSection($(this)); });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function label(width) {
|
|
68
|
+
if (width === 'fixed') { return ge.t('section.fixed'); }
|
|
69
|
+
if (width === 'fluid') { return ge.t('section.fluid'); }
|
|
70
|
+
|
|
71
|
+
return ge.t('section.from', { breakpoint: width });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Change a section's width, announced like a utility: the width is its
|
|
76
|
+
* one container class, the same at every breakpoint.
|
|
77
|
+
*/
|
|
78
|
+
function setWidth(section, width, source) {
|
|
79
|
+
var from = widthOf(section);
|
|
80
|
+
if (from === width || !WIDTHS[width]) { return false; }
|
|
81
|
+
|
|
82
|
+
return ge.operate(function() {
|
|
83
|
+
var payload = ge.payloadFor('section', section, {
|
|
84
|
+
family: 'section',
|
|
85
|
+
breakpoint: 'all',
|
|
86
|
+
tiers: [],
|
|
87
|
+
from: from,
|
|
88
|
+
to: width,
|
|
89
|
+
source: source || 'api',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (!ge.emit('before-utility', payload)) {
|
|
93
|
+
section.find('> .ge-tools-drawer .ge-section-width select').val(from);
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
section.removeClass(WIDTHS[from]).addClass(WIDTHS[width]);
|
|
98
|
+
ge.emit('after-utility', payload);
|
|
99
|
+
|
|
100
|
+
return true;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function widthField(section) {
|
|
105
|
+
var select = $('<select />');
|
|
106
|
+
var current = widthOf(section);
|
|
107
|
+
var offered = options.widths.indexOf(current) === -1 ? options.widths.concat([current]) : options.widths;
|
|
108
|
+
|
|
109
|
+
ORDER.forEach(function(width) {
|
|
110
|
+
if (offered.indexOf(width) === -1) { return; }
|
|
111
|
+
$('<option />').attr('value', width).text(label(width)).appendTo(select);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
select.val(current).on('change', function() { setWidth(section, this.value, 'panel'); });
|
|
115
|
+
|
|
116
|
+
return $('<label class="ge-utility ge-section-width" />')
|
|
117
|
+
.append($('<span class="ge-utility-label" />').text(ge.t('section.width')))
|
|
118
|
+
.append(select);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function createControls(section) {
|
|
122
|
+
var drawer = $('<div class="ge-tools-drawer ge-section-drawer" />').prependTo(section);
|
|
123
|
+
|
|
124
|
+
ge.createMoveTool(drawer);
|
|
125
|
+
ge.addSettingsTool(drawer, section, ge.settings.section_classes || []).append(widthField(section));
|
|
126
|
+
|
|
127
|
+
ge.createTool(drawer, ge.t('tool.delete_section'), 'ge-delete-section', 'bi bi-trash', function() {
|
|
128
|
+
ge.deleteNode('section', section, ge.t('confirm.delete_section'), function(removed) {
|
|
129
|
+
section.slideUp(removed);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
ge.createTool(drawer, ge.t('tool.add_row_to_section'), 'ge-add-row', 'bi bi-plus-circle', function() {
|
|
134
|
+
ge.place(ge.rowFromLayout([12]), 'row', { appendTo: section });
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function mark() {
|
|
139
|
+
sections().each(function() {
|
|
140
|
+
var section = $(this).addClass('ge-section');
|
|
141
|
+
if (!section.children('.ge-tools-drawer').length) { createControls(section); }
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function unmark() {
|
|
146
|
+
ge.canvas.children('.ge-section').removeClass('ge-section');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** createSection(options): a section, detached unless a placement is given. */
|
|
150
|
+
function createSection(settings) {
|
|
151
|
+
settings = settings || {};
|
|
152
|
+
|
|
153
|
+
var section = $('<div />').addClass(WIDTHS[settings.width] || WIDTHS.fixed);
|
|
154
|
+
|
|
155
|
+
(settings.rows || [[12]]).forEach(function(layout) {
|
|
156
|
+
ge.rowFromLayout(layout).appendTo(section);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return ge.place(section, 'section', settings);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
methods: {
|
|
164
|
+
createSection: createSection,
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
kindOf: function(node) {
|
|
168
|
+
return node.hasClass('ge-section') ? 'section' : null;
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// A section is a block the canvas moves, and a region rows move in
|
|
172
|
+
blocks: '.ge-section',
|
|
173
|
+
regions: '.ge-section',
|
|
174
|
+
|
|
175
|
+
/** A section goes on the canvas and nowhere else, and holds rows and nothing else. */
|
|
176
|
+
accepts: function(region, node) {
|
|
177
|
+
if (node.hasClass('ge-section') || isSectionMade(node)) { return region[0] === ge.canvas[0]; }
|
|
178
|
+
if (region.hasClass('ge-section')) { return node.hasClass('row'); }
|
|
179
|
+
|
|
180
|
+
return true;
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
toolbar: [{
|
|
184
|
+
labelKey: 'section.add',
|
|
185
|
+
kind: 'section',
|
|
186
|
+
create: function() { return createSection(); },
|
|
187
|
+
}],
|
|
188
|
+
|
|
189
|
+
onInit: mark,
|
|
190
|
+
onDeinit: unmark,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/** A section the toolbar just made, before init has marked it. */
|
|
194
|
+
function isSectionMade(node) {
|
|
195
|
+
return !node.parent().length && widthOf(node) !== null;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
})(jQuery);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text alignment for grid-editor.
|
|
3
|
+
*
|
|
4
|
+
* A utility plugin: load this file after the editor and a row, column,
|
|
5
|
+
* element or container can align its text per breakpoint, with Bootstrap's
|
|
6
|
+
* text-{breakpoint}-start, -center and -end classes. What it can ask the
|
|
7
|
+
* editor for is the handle its factory is called with, described in
|
|
8
|
+
* docs/plugins.md.
|
|
9
|
+
*
|
|
10
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
11
|
+
* <script src="dist/plugins/grideditor.textalign.min.js"></script>
|
|
12
|
+
*
|
|
13
|
+
* The class aligns everything inside the node that does not align itself: a
|
|
14
|
+
* paragraph the rich text editor gave its own text-align keeps it.
|
|
15
|
+
*/
|
|
16
|
+
(function($) {
|
|
17
|
+
|
|
18
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
19
|
+
'utility.text_align': 'Text alignment',
|
|
20
|
+
'utility.text_start': 'Start',
|
|
21
|
+
'utility.text_center': 'Center',
|
|
22
|
+
'utility.text_end': 'End',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/** Start and end are left and right: Bootstrap's css is left to right. */
|
|
26
|
+
var CSS = { start: 'left', center: 'center', end: 'right' };
|
|
27
|
+
|
|
28
|
+
$.fn.gridEditor.utilities.textalign = function(ge) {
|
|
29
|
+
|
|
30
|
+
function label(value) {
|
|
31
|
+
if (value === 'start') { return ge.t('utility.text_start'); }
|
|
32
|
+
if (value === 'center') { return ge.t('utility.text_center'); }
|
|
33
|
+
|
|
34
|
+
return ge.t('utility.text_end');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
families: [{
|
|
39
|
+
name: 'text-align',
|
|
40
|
+
prefix: 'text',
|
|
41
|
+
values: ['start', 'center', 'end'],
|
|
42
|
+
appliesTo: ['row', 'column', 'element', 'container'],
|
|
43
|
+
labelKey: 'utility.text_align',
|
|
44
|
+
label: label,
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* With no class applying here, the node aligns as its parent
|
|
48
|
+
* does - or as the host's css says - which only the browser can
|
|
49
|
+
* tell, so it is asked with the classes out of the way. Parents
|
|
50
|
+
* are previewed before their children, so the parent's answer is
|
|
51
|
+
* already the view's.
|
|
52
|
+
*/
|
|
53
|
+
preview: function(value, node) {
|
|
54
|
+
return { 'text-align': value === null ? ge.bareStyle(node, 'text-align', 'text-align') : CSS[value] };
|
|
55
|
+
},
|
|
56
|
+
}],
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
})(jQuery);
|