@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
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
var METHODS = {
|
|
20
20
|
getHtml: { value: true, noInstance: function(element) { return element.html(); } },
|
|
21
|
+
getPlainHtml: { value: true, noInstance: function(element) { return plainHtml(element.html()); } },
|
|
21
22
|
init: {},
|
|
22
23
|
deinit: {},
|
|
23
24
|
reset: {},
|
|
@@ -28,6 +29,7 @@ var METHODS = {
|
|
|
28
29
|
createRow: { value: true },
|
|
29
30
|
createColumn: { value: true },
|
|
30
31
|
createElement: { value: true },
|
|
32
|
+
createSection: { value: true },
|
|
31
33
|
createContainer: { value: true },
|
|
32
34
|
addTab: { value: true },
|
|
33
35
|
addAccordionItem: { value: true },
|
|
@@ -62,8 +64,8 @@ var BREAKPOINTS = [
|
|
|
62
64
|
|
|
63
65
|
/**
|
|
64
66
|
* The view that edits every tier at once. It is the default, and the one most
|
|
65
|
-
* pages want: a layout that needs no per-device tuning is written once
|
|
66
|
-
*
|
|
67
|
+
* pages want: a layout that needs no per-device tuning is written once, as the
|
|
68
|
+
* class with no breakpoint, and applies at every size.
|
|
67
69
|
*/
|
|
68
70
|
var ALL_VIEW = 'all';
|
|
69
71
|
var ALL_VIEW_LABEL_KEY = 'view.all';
|
|
@@ -77,6 +79,31 @@ var LEGACY_VIEW_INDEXES = ['lg', 'sm', 'xs'];
|
|
|
77
79
|
var MAX_COL_SIZE = 12;
|
|
78
80
|
var MAX_COL_OFFSET = 11;
|
|
79
81
|
|
|
82
|
+
/**
|
|
83
|
+
* The two sizes that are not a number of units: `equal` is Bootstrap's col,
|
|
84
|
+
* which shares what the row has left with the other equal columns, and
|
|
85
|
+
* `auto` is col-auto, as wide as its content.
|
|
86
|
+
*/
|
|
87
|
+
var FLEX_SIZES = ['equal', 'auto'];
|
|
88
|
+
|
|
89
|
+
/** How many columns a row-cols class puts on a line. */
|
|
90
|
+
var ROW_COLS_VALUES = ['1', '2', '3', '4', '5', '6', 'auto'];
|
|
91
|
+
|
|
92
|
+
function rowColsClass(tier, value) {
|
|
93
|
+
return 'row-cols' + (tier.infix ? '-' + tier.infix : '') + '-' + value;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isUnits(size) {
|
|
97
|
+
return typeof size === 'number';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The class that gives a column `size` at one tier: col-md-4, col-md, col-md-auto. */
|
|
101
|
+
function sizeClass(tier, size) {
|
|
102
|
+
if (size === 'equal') { return tier.infix ? 'col-' + tier.infix : 'col'; }
|
|
103
|
+
|
|
104
|
+
return tier.colPrefix + size;
|
|
105
|
+
}
|
|
106
|
+
|
|
80
107
|
function breakpoint(key) {
|
|
81
108
|
for (var i = 0; i < BREAKPOINTS.length; i++) {
|
|
82
109
|
if (BREAKPOINTS[i].key === key) { return BREAKPOINTS[i]; }
|
|
@@ -84,9 +111,12 @@ function breakpoint(key) {
|
|
|
84
111
|
return null;
|
|
85
112
|
}
|
|
86
113
|
|
|
87
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* The tier a view writes to. The all view writes the base class, the one
|
|
116
|
+
* with no breakpoint, and takes the others off.
|
|
117
|
+
*/
|
|
88
118
|
function tiersFor(view) {
|
|
89
|
-
if (view === ALL_VIEW) { return BREAKPOINTS
|
|
119
|
+
if (view === ALL_VIEW) { return [BREAKPOINTS[0]]; }
|
|
90
120
|
|
|
91
121
|
var tier = breakpoint(view);
|
|
92
122
|
return tier ? [tier] : [];
|
|
@@ -218,6 +248,56 @@ function dispatch(set, name, args) {
|
|
|
218
248
|
return set;
|
|
219
249
|
}
|
|
220
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Html with grid-editor's own marking taken off: the ge-* classes, the
|
|
253
|
+
* column class and the data-ge-* attributes. A div that was only there for
|
|
254
|
+
* the editor - a content area, a bare element or container wrapper - is left
|
|
255
|
+
* with nothing on it, and goes, its children taking its place.
|
|
256
|
+
*
|
|
257
|
+
* The marking is what lets the editor read its markup back, so this is for
|
|
258
|
+
* publishing, not for saving something to edit again.
|
|
259
|
+
*/
|
|
260
|
+
function plainHtml(html) {
|
|
261
|
+
// Parsed in a document of its own, which is inert: no script in the
|
|
262
|
+
// markup runs and no image starts loading while it is being cleaned
|
|
263
|
+
var root = $(document.implementation.createHTMLDocument('').body);
|
|
264
|
+
root[0].innerHTML = html;
|
|
265
|
+
var emptied = [];
|
|
266
|
+
|
|
267
|
+
root.find('*').each(function() {
|
|
268
|
+
var node = $(this);
|
|
269
|
+
var marked = false;
|
|
270
|
+
|
|
271
|
+
$.each($.makeArray(this.attributes), function(i, attribute) {
|
|
272
|
+
if (attribute.name.indexOf('data-ge-') === 0) {
|
|
273
|
+
node.removeAttr(attribute.name);
|
|
274
|
+
marked = true;
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
var classes = (node.attr('class') || '').split(/\s+/).filter(Boolean);
|
|
279
|
+
var kept = classes.filter(function(name) {
|
|
280
|
+
return name !== 'column' && name.indexOf('ge-') !== 0;
|
|
281
|
+
});
|
|
282
|
+
if (kept.length !== classes.length) { marked = true; }
|
|
283
|
+
if (kept.length) {
|
|
284
|
+
node.attr('class', kept.join(' '));
|
|
285
|
+
} else {
|
|
286
|
+
node.removeAttr('class');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (marked && this.tagName === 'DIV' && !this.attributes.length) {
|
|
290
|
+
emptied.push(this);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
emptied.forEach(function(div) {
|
|
295
|
+
$(div).replaceWith($(div).contents());
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
return root[0].innerHTML;
|
|
299
|
+
}
|
|
300
|
+
|
|
221
301
|
$.fn.gridEditor = function( optionsOrMethod ) {
|
|
222
302
|
|
|
223
303
|
var self = this;
|
|
@@ -264,11 +344,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
264
344
|
'tab_tools' : [], // Host tools on tab drawers
|
|
265
345
|
'accordion_tools' : [], // Host tools on accordion item drawers
|
|
266
346
|
'plugins' : null, // Plugins to use, of any kind; null means every one loaded
|
|
347
|
+
'row_cols' : true, // A row's "columns per row" field, row-cols-*
|
|
267
348
|
'utilities' : {}, // Options for the utility plugins, by plugin name
|
|
268
349
|
'elements' : NESTED_SETTINGS.elements, // Element level controls, below the column
|
|
269
350
|
'custom_filter' : '',
|
|
270
351
|
'content_types' : ['tinymce'],
|
|
271
|
-
'valid_col_sizes' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
|
352
|
+
'valid_col_sizes' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'equal', 'auto'],
|
|
272
353
|
'valid_col_offsets' : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
273
354
|
'add_column' : NESTED_SETTINGS.add_column, // The add column tool
|
|
274
355
|
'layout_modes' : VIEW_KEYS.slice(), // Which views the dropdown offers
|
|
@@ -580,54 +661,91 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
580
661
|
}
|
|
581
662
|
|
|
582
663
|
/**
|
|
583
|
-
*
|
|
584
|
-
*
|
|
664
|
+
* What resizing this column to `size` in `view` would write, or null
|
|
665
|
+
* when the budget refuses it or there is nothing to change.
|
|
585
666
|
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* What resizing this column to `size` would write, or null when the
|
|
591
|
-
* budget refuses it or there is nothing to change.
|
|
667
|
+
* A breakpoint view writes its own tier. The all view writes the base
|
|
668
|
+
* class and takes the size off every other tier, so one size is what
|
|
669
|
+
* applies everywhere; the plan says what it took off.
|
|
592
670
|
*
|
|
593
671
|
* Refused rather than quietly clamped: the offset is something the
|
|
594
|
-
* user set, and a tool that rewrites it is a tool that lies.
|
|
595
|
-
*
|
|
672
|
+
* user set, and a tool that rewrites it is a tool that lies. In the
|
|
673
|
+
* all view the base size has to fit every tier's offset, since it is
|
|
674
|
+
* the size at every tier once the others are gone.
|
|
596
675
|
*/
|
|
597
|
-
function planSize(col, size) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
676
|
+
function planSize(col, size, view) {
|
|
677
|
+
view = view || curView;
|
|
678
|
+
|
|
679
|
+
if (view !== ALL_VIEW) {
|
|
680
|
+
var tier = breakpoint(view);
|
|
681
|
+
var wanted = clamp({ size: size, offset: getEffectiveOffset(col, tier) || 0 });
|
|
682
|
+
|
|
683
|
+
if (wanted.refused || getSize(col, tier) === wanted.size) { return null; }
|
|
684
|
+
|
|
685
|
+
return { writes: [{ tier: tier, size: wanted.size }], cleared: null, size: wanted.size };
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
var refused = BREAKPOINTS.some(function(each) {
|
|
689
|
+
return clamp({ size: size, offset: getEffectiveOffset(col, each) || 0 }).refused;
|
|
601
690
|
});
|
|
691
|
+
if (refused) { return null; }
|
|
602
692
|
|
|
603
|
-
|
|
693
|
+
var base = BREAKPOINTS[0];
|
|
694
|
+
var writes = [];
|
|
695
|
+
var cleared = [];
|
|
696
|
+
|
|
697
|
+
BREAKPOINTS.slice(1).forEach(function(each) {
|
|
698
|
+
var own = getSize(col, each);
|
|
699
|
+
if (own === null) { return; }
|
|
604
700
|
|
|
605
|
-
|
|
606
|
-
|
|
701
|
+
writes.push({ tier: each, size: null });
|
|
702
|
+
cleared.push({ breakpoint: each.key, value: own });
|
|
607
703
|
});
|
|
608
|
-
if (unchanged) { return null; }
|
|
609
704
|
|
|
610
|
-
|
|
705
|
+
if (getSize(col, base) !== size) { writes.unshift({ tier: base, size: size }); }
|
|
706
|
+
|
|
707
|
+
return writes.length ? { writes: writes, cleared: cleared, size: size } : null;
|
|
611
708
|
}
|
|
612
709
|
|
|
613
710
|
function writeSize(col, plan) {
|
|
614
|
-
plan.
|
|
711
|
+
plan.writes.forEach(function(write) { setSize(col, write.tier, write.size); });
|
|
615
712
|
stripPixelWidths(col);
|
|
616
713
|
}
|
|
617
714
|
|
|
618
|
-
/**
|
|
619
|
-
function
|
|
715
|
+
/** The all view's payloads say what the write took off the breakpoints. */
|
|
716
|
+
function withCleared(extra, cleared) {
|
|
717
|
+
if (cleared) { extra.cleared = cleared; }
|
|
718
|
+
return extra;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Resize a column, announcing it either side. `size` is units,
|
|
723
|
+
* `equal` or `auto`; `view` is the current one unless the size field
|
|
724
|
+
* of a plugin's panel says otherwise.
|
|
725
|
+
*/
|
|
726
|
+
function resizeColumn(col, size, source, view) {
|
|
727
|
+
view = view || curView;
|
|
728
|
+
|
|
620
729
|
var from = currentSize(col);
|
|
621
|
-
var plan = planSize(col, size);
|
|
730
|
+
var plan = planSize(col, size, view);
|
|
622
731
|
|
|
623
732
|
if (!plan) { return false; }
|
|
624
733
|
|
|
625
734
|
return operate(function() {
|
|
626
|
-
var payload = payloadFor('column', col, {
|
|
735
|
+
var payload = payloadFor('column', col, withCleared({
|
|
736
|
+
source: source,
|
|
737
|
+
breakpoint: view,
|
|
738
|
+
from: from,
|
|
739
|
+
to: plan.size,
|
|
740
|
+
}, plan.cleared));
|
|
627
741
|
|
|
628
|
-
if (!emit('before-resize', payload)) {
|
|
742
|
+
if (!emit('before-resize', payload)) {
|
|
743
|
+
refreshUtilities(col);
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
629
746
|
|
|
630
747
|
writeSize(col, plan);
|
|
748
|
+
refreshUtilities(col);
|
|
631
749
|
emit('after-resize', payload);
|
|
632
750
|
|
|
633
751
|
return true;
|
|
@@ -637,41 +755,49 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
637
755
|
/**
|
|
638
756
|
* Indent a column, shrinking it when the budget needs it: the offset
|
|
639
757
|
* is what the user asked for, so it is the one that gets its way.
|
|
758
|
+
*
|
|
759
|
+
* Like a size, an offset is written to the tier being edited, or in
|
|
760
|
+
* the all view as the base class with every other tier's taken off.
|
|
640
761
|
*/
|
|
641
762
|
function indentColumn(col, offset, source) {
|
|
642
|
-
var
|
|
763
|
+
var everywhere = curView === ALL_VIEW;
|
|
764
|
+
var tier = everywhere ? BREAKPOINTS[0] : breakpoint(curView);
|
|
643
765
|
var from = currentOffset(col);
|
|
644
766
|
|
|
645
767
|
offset = Math.min(Math.max(offset, 0), MAX_COL_OFFSET);
|
|
646
768
|
|
|
647
|
-
var
|
|
648
|
-
return
|
|
649
|
-
});
|
|
650
|
-
|
|
769
|
+
var others = everywhere ? BREAKPOINTS.slice(1).filter(function(each) {
|
|
770
|
+
return getOffset(col, each) !== null;
|
|
771
|
+
}) : [];
|
|
772
|
+
|
|
773
|
+
if ((getOffset(col, tier) || 0) === offset && !others.length) { return false; }
|
|
651
774
|
|
|
652
775
|
return operate(function() {
|
|
653
|
-
var payload = payloadFor('column', col, {
|
|
776
|
+
var payload = payloadFor('column', col, withCleared({
|
|
654
777
|
source: source,
|
|
655
778
|
from: from,
|
|
656
779
|
to: offset,
|
|
657
|
-
})
|
|
780
|
+
}, everywhere ? others.map(function(each) {
|
|
781
|
+
return { breakpoint: each.key, value: getOffset(col, each) };
|
|
782
|
+
}) : null));
|
|
658
783
|
|
|
659
784
|
if (!emit('before-indent', payload)) { return false; }
|
|
660
785
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
var wanted = clamp({ size: was, offset: offset, leading: 'offset' });
|
|
786
|
+
setOffset(col, tier, offset);
|
|
787
|
+
others.forEach(function(each) { setOffset(col, each, 0); });
|
|
664
788
|
|
|
665
|
-
|
|
789
|
+
// Wherever the column's size and the new offset no longer fit
|
|
790
|
+
// - one tier, or every tier in the all view - the size gives
|
|
791
|
+
// way, at that tier only. An equal or auto column fits anywhere.
|
|
792
|
+
(everywhere ? BREAKPOINTS : [tier]).forEach(function(each) {
|
|
793
|
+
var was = getEffectiveSize(col, each);
|
|
794
|
+
if (!isUnits(was)) { return; }
|
|
666
795
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
// tiers nobody asked it to touch
|
|
670
|
-
if (wanted.size !== null && wanted.size !== was) {
|
|
671
|
-
setSize(col, tier, wanted.size);
|
|
672
|
-
}
|
|
796
|
+
var wanted = clamp({ size: was, offset: offset, leading: 'offset' });
|
|
797
|
+
if (wanted.size !== was) { setSize(col, each, wanted.size); }
|
|
673
798
|
});
|
|
674
799
|
|
|
800
|
+
refreshUtilities(col);
|
|
675
801
|
emit('after-indent', payload);
|
|
676
802
|
|
|
677
803
|
return true;
|
|
@@ -770,17 +896,17 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
770
896
|
addRowGroup = $('<div class="ge-addRowGroup btn-group" />').appendTo(wrapper);
|
|
771
897
|
addContainerGroup = $('<div class="ge-addContainerGroup btn-group" />');
|
|
772
898
|
$.each(settings.new_row_layouts, function(j, layout) {
|
|
899
|
+
var grouped = !Array.isArray(layout);
|
|
773
900
|
var btn = $('<a class="btn btn-sm btn-primary" />')
|
|
774
|
-
.attr('title',
|
|
901
|
+
.attr('title', grouped
|
|
902
|
+
? t('row.add_row_cols', { columns: layout.columns, counts: rowColsText(layout.row_cols) })
|
|
903
|
+
: t('row.add', { layout: layout.join('-') }))
|
|
775
904
|
// What this button makes, in the markup rather than in
|
|
776
905
|
// jQuery data: a drag works on a clone of it
|
|
777
906
|
.attr('data-ge-toolbar', 'row')
|
|
778
|
-
.attr('data-ge-layout', layout.join(','))
|
|
907
|
+
.attr('data-ge-layout', grouped ? JSON.stringify(layout) : layout.join(','))
|
|
779
908
|
.on('click', function() {
|
|
780
|
-
var row =
|
|
781
|
-
layout.forEach(function(i) {
|
|
782
|
-
createColumn(i).appendTo(row);
|
|
783
|
-
});
|
|
909
|
+
var row = rowFromLayoutValue(layout);
|
|
784
910
|
|
|
785
911
|
var added = addNode('row', row, function() {
|
|
786
912
|
row.appendTo(canvas);
|
|
@@ -795,10 +921,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
795
921
|
|
|
796
922
|
btn.append('<i class="bi bi-plus"></i>');
|
|
797
923
|
|
|
798
|
-
|
|
924
|
+
// A row of columns shares out the icon as they share the row;
|
|
925
|
+
// a row with row-cols draws one line of its widest count
|
|
926
|
+
var sizes = grouped ? rowColsIcon(layout) : layout;
|
|
799
927
|
var icon = '<div class="row ge-row-icon">';
|
|
800
|
-
|
|
801
|
-
|
|
928
|
+
sizes.forEach(function(size) {
|
|
929
|
+
// Closed explicitly: jQuery 4 no longer expands <div/>, and
|
|
930
|
+
// each column would be parsed inside the one before
|
|
931
|
+
icon += '<div class="column ' + sizeClass(BREAKPOINTS[0], size) + '"></div>';
|
|
802
932
|
});
|
|
803
933
|
icon += '</div>';
|
|
804
934
|
btn.append(icon);
|
|
@@ -830,6 +960,29 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
830
960
|
;
|
|
831
961
|
});
|
|
832
962
|
|
|
963
|
+
// A feature plugin's own buttons, beside the containers': what
|
|
964
|
+
// one makes goes onto the canvas, where the plugin says it belongs
|
|
965
|
+
$.each(FEATURES, function(name, feature) {
|
|
966
|
+
(feature.toolbar || []).forEach(function(item, index) {
|
|
967
|
+
$('<a class="btn btn-sm btn-primary ge-add-container ge-add-feature" />')
|
|
968
|
+
.attr('title', t(item.labelKey))
|
|
969
|
+
.attr('data-ge-toolbar', 'feature')
|
|
970
|
+
.attr('data-ge-feature', name)
|
|
971
|
+
.attr('data-ge-item', index)
|
|
972
|
+
.append($('<i />').addClass(item.iconClass || 'bi bi-plus'))
|
|
973
|
+
.append($('<span />').text(t(item.labelKey)))
|
|
974
|
+
.on('click', function() {
|
|
975
|
+
var made = item.create();
|
|
976
|
+
|
|
977
|
+
addNode(item.kind, made, function() {
|
|
978
|
+
made.appendTo(canvas);
|
|
979
|
+
}, { parent: canvas, source: item.source || 'tool' });
|
|
980
|
+
})
|
|
981
|
+
.appendTo(addContainerGroup)
|
|
982
|
+
;
|
|
983
|
+
});
|
|
984
|
+
});
|
|
985
|
+
|
|
833
986
|
// Buttons on right
|
|
834
987
|
layoutDropdown = $('<div class="dropdown pull-right ge-layout-mode">' +
|
|
835
988
|
'<button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-bs-toggle="dropdown"></button>' +
|
|
@@ -1005,14 +1158,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1005
1158
|
|
|
1006
1159
|
if (!under) { return null; }
|
|
1007
1160
|
|
|
1008
|
-
var region = $(under).closest('.column, .ge-canvas');
|
|
1161
|
+
var region = $(under).closest(['.column', '.ge-canvas'].concat(pluginHooks('regions')).join(', '));
|
|
1009
1162
|
if (!region.length || (region[0] !== canvas[0] && !canvas[0].contains(region[0]))) {
|
|
1010
1163
|
return null;
|
|
1011
1164
|
}
|
|
1012
1165
|
|
|
1013
1166
|
var before = null;
|
|
1014
1167
|
|
|
1015
|
-
region.children(
|
|
1168
|
+
region.children(blockSelector()).each(function() {
|
|
1016
1169
|
if (before) { return; }
|
|
1017
1170
|
|
|
1018
1171
|
var box = this.getBoundingClientRect();
|
|
@@ -1022,6 +1175,30 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1022
1175
|
return { region: region, before: before };
|
|
1023
1176
|
}
|
|
1024
1177
|
|
|
1178
|
+
/**
|
|
1179
|
+
* A feature's toolbar button dropped on the canvas. A region that will
|
|
1180
|
+
* not have what it makes - a section dropped on a column - gives way
|
|
1181
|
+
* to the canvas, just after the top level block the pointer was in.
|
|
1182
|
+
*/
|
|
1183
|
+
function insertFeatureFromToolbar(button, where) {
|
|
1184
|
+
var item = FEATURES[button.attr('data-ge-feature')].toolbar[parseInt(button.attr('data-ge-item'), 10)];
|
|
1185
|
+
var made = item.create();
|
|
1186
|
+
|
|
1187
|
+
if (!acceptsBlock(where.region, made)) {
|
|
1188
|
+
var top = where.region.parentsUntil(canvas).addBack().first();
|
|
1189
|
+
where = { region: canvas, before: top.length ? top.next() : null };
|
|
1190
|
+
if (where.before && !where.before.length) { where.before = null; }
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
return addNode(item.kind, made, function() {
|
|
1194
|
+
if (where.before) {
|
|
1195
|
+
made.insertBefore(where.before);
|
|
1196
|
+
} else {
|
|
1197
|
+
made.appendTo(where.region);
|
|
1198
|
+
}
|
|
1199
|
+
}, { parent: where.region, source: item.source || 'dragdrop' });
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1025
1202
|
/** A line where the block would go, following the pointer. */
|
|
1026
1203
|
function showDropMarker(pageX, pageY) {
|
|
1027
1204
|
var where = dropPlaceAt(pageX, pageY);
|
|
@@ -1048,6 +1225,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1048
1225
|
* the pointer left it.
|
|
1049
1226
|
*/
|
|
1050
1227
|
function insertFromToolbar(button, where) {
|
|
1228
|
+
if (button.attr('data-ge-toolbar') === 'feature') {
|
|
1229
|
+
return insertFeatureFromToolbar(button, where);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1051
1232
|
var container = button.attr('data-ge-toolbar') === 'container';
|
|
1052
1233
|
var type = button.attr('data-ge-container-type');
|
|
1053
1234
|
var made = container
|
|
@@ -1072,16 +1253,94 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1072
1253
|
}, { parent: where.region, source: 'dragdrop' });
|
|
1073
1254
|
}
|
|
1074
1255
|
|
|
1256
|
+
/**
|
|
1257
|
+
* The column width as a utility family, so the Responsive section of
|
|
1258
|
+
* a column's panel has a field for it: every size, units or not, in
|
|
1259
|
+
* the view being edited. A write is a resize, through the resize
|
|
1260
|
+
* events, not a utility change.
|
|
1261
|
+
*/
|
|
1262
|
+
function widthFamily() {
|
|
1263
|
+
var values = [];
|
|
1264
|
+
for (var units = 1; units <= MAX_COL_SIZE; units++) { values.push(String(units)); }
|
|
1265
|
+
|
|
1266
|
+
return {
|
|
1267
|
+
name: 'col',
|
|
1268
|
+
values: values.concat(FLEX_SIZES),
|
|
1269
|
+
appliesTo: ['column'],
|
|
1270
|
+
labelKey: 'utility.col_width',
|
|
1271
|
+
className: function(key, value) { return sizeClass(breakpoint(key), parseSize(value)); },
|
|
1272
|
+
choices: function() { return settings.valid_col_sizes.map(String); },
|
|
1273
|
+
label: function(value) {
|
|
1274
|
+
if (value === 'equal') { return t('utility.col_equal'); }
|
|
1275
|
+
if (value === 'auto') { return t('utility.col_auto'); }
|
|
1276
|
+
|
|
1277
|
+
return value;
|
|
1278
|
+
},
|
|
1279
|
+
write: function(col, value, view, source) {
|
|
1280
|
+
return resizeColumn(col, value === null ? null : parseSize(value), source, view);
|
|
1281
|
+
},
|
|
1282
|
+
// With no size of its own, a column in a row with row-cols
|
|
1283
|
+
// takes its share from the row, which the field says
|
|
1284
|
+
blank: function(col, view) {
|
|
1285
|
+
var winner = view === ALL_VIEW ? null : rowColsWinner(col, breakpoint(view));
|
|
1286
|
+
return winner ? t('utility.col_from_row', { count: rowColsLabel(winner.value) }) : null;
|
|
1287
|
+
},
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
/** A size as markup or a select carries it: '4' is 4, 'equal' and 'auto' are themselves. */
|
|
1292
|
+
function parseSize(size) {
|
|
1293
|
+
return /^\d+$/.test(String(size)) ? parseInt(size, 10) : size;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/** A row from a toolbar button's data-ge-layout: sizes, or a row-cols layout as JSON. */
|
|
1075
1297
|
function rowFromLayout(layout) {
|
|
1298
|
+
if (/^\s*\{/.test(layout || '')) { return rowFromLayoutValue(JSON.parse(layout)); }
|
|
1299
|
+
|
|
1300
|
+
return rowFromLayoutValue((layout || '').split(',').filter(function(size) {
|
|
1301
|
+
return size !== '';
|
|
1302
|
+
}).map(parseSize));
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
/**
|
|
1306
|
+
* A row from a layout: an array of sizes, or { row_cols, columns } -
|
|
1307
|
+
* row-cols per breakpoint, and that many columns sized by the row.
|
|
1308
|
+
*/
|
|
1309
|
+
function rowFromLayoutValue(layout) {
|
|
1076
1310
|
var row = createRow();
|
|
1077
1311
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1312
|
+
if (Array.isArray(layout)) {
|
|
1313
|
+
layout.forEach(function(size) { createColumn(size).appendTo(row); });
|
|
1314
|
+
return row;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
$.each(layout.row_cols || {}, function(key, value) {
|
|
1318
|
+
var tier = breakpoint(key);
|
|
1319
|
+
if (tier && ROW_COLS_VALUES.indexOf(String(value)) !== -1) { row.addClass(rowColsClass(tier, value)); }
|
|
1080
1320
|
});
|
|
1081
1321
|
|
|
1322
|
+
for (var i = 0; i < (layout.columns || 0); i++) { createColumn(null).appendTo(row); }
|
|
1323
|
+
|
|
1082
1324
|
return row;
|
|
1083
1325
|
}
|
|
1084
1326
|
|
|
1327
|
+
/** "1, md: 3": a row-cols layout's counts, for its button's title. */
|
|
1328
|
+
function rowColsText(counts) {
|
|
1329
|
+
return BREAKPOINTS.filter(function(tier) { return counts && counts[tier.key] !== undefined; })
|
|
1330
|
+
.map(function(tier) { return (tier.infix ? tier.key + ': ' : '') + counts[tier.key]; })
|
|
1331
|
+
.join(', ');
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
/** The icon of a row-cols layout: one line of equal columns, as many as its widest count. */
|
|
1335
|
+
function rowColsIcon(layout) {
|
|
1336
|
+
var widest = 1;
|
|
1337
|
+
$.each(layout.row_cols || {}, function(key, value) {
|
|
1338
|
+
if (value !== 'auto') { widest = Math.max(widest, parseInt(value, 10) || 1); }
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
return Array.apply(null, Array(Math.min(widest, layout.columns || widest))).map(function() { return 'equal'; });
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1085
1344
|
function onScroll(e) {
|
|
1086
1345
|
var $window = $(window);
|
|
1087
1346
|
|
|
@@ -1168,6 +1427,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1168
1427
|
// one that rebuilt its area's DOM brought the preview styles back
|
|
1169
1428
|
// with it, and the attribute recording them came back too
|
|
1170
1429
|
clearPreviews(canvas);
|
|
1430
|
+
canvas.find('[data-ge-row-cols]').removeAttr('data-ge-row-cols');
|
|
1171
1431
|
unmarkContainers();
|
|
1172
1432
|
removeSortable();
|
|
1173
1433
|
removeResizable();
|
|
@@ -1186,6 +1446,23 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1186
1446
|
return html;
|
|
1187
1447
|
}
|
|
1188
1448
|
|
|
1449
|
+
/**
|
|
1450
|
+
* One node's markup, as getHtml would give it: the canvas goes out of
|
|
1451
|
+
* editing to read it and comes back, as it does for getHtml.
|
|
1452
|
+
*/
|
|
1453
|
+
function nodeHtml(node) {
|
|
1454
|
+
deinit();
|
|
1455
|
+
stripPixelWidths(node);
|
|
1456
|
+
var html = node[0].outerHTML;
|
|
1457
|
+
init();
|
|
1458
|
+
return html;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/** getHtml with grid-editor's own classes and attributes taken off. */
|
|
1462
|
+
function getPlainHtml() {
|
|
1463
|
+
return plainHtml(getHtml());
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1189
1466
|
function destroy() {
|
|
1190
1467
|
deinit();
|
|
1191
1468
|
removeConfirmModal();
|
|
@@ -1236,6 +1513,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1236
1513
|
*/
|
|
1237
1514
|
function loadPlugins() {
|
|
1238
1515
|
var api = pluginApi();
|
|
1516
|
+
|
|
1517
|
+
registerFamily('grid', {}, widthFamily());
|
|
1518
|
+
if (settings.row_cols !== false) { registerFamily('grid', {}, rowColsFamily()); }
|
|
1239
1519
|
var wanted = function(name) {
|
|
1240
1520
|
return !settings.plugins || settings.plugins.indexOf(name) !== -1;
|
|
1241
1521
|
};
|
|
@@ -1321,6 +1601,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1321
1601
|
getUtility: getUtility,
|
|
1322
1602
|
setUtility: setUtility,
|
|
1323
1603
|
utilityField: utilityField,
|
|
1604
|
+
bareStyle: bareStyle,
|
|
1605
|
+
rowFromLayout: rowFromLayoutValue,
|
|
1606
|
+
nodeHtml: nodeHtml,
|
|
1607
|
+
toolbarItems: function(name) {
|
|
1608
|
+
return mainControls
|
|
1609
|
+
? mainControls.find('[data-ge-toolbar="feature"][data-ge-feature="' + name + '"]')
|
|
1610
|
+
: $();
|
|
1611
|
+
},
|
|
1324
1612
|
};
|
|
1325
1613
|
}
|
|
1326
1614
|
|
|
@@ -1392,6 +1680,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1392
1680
|
}
|
|
1393
1681
|
|
|
1394
1682
|
function utilityClass(family, tier, value) {
|
|
1683
|
+
if (family.className) { return family.className(tier.key, value); }
|
|
1684
|
+
|
|
1395
1685
|
return family.prefix + (tier.infix ? '-' + tier.infix : '') + '-' + value;
|
|
1396
1686
|
}
|
|
1397
1687
|
|
|
@@ -1538,6 +1828,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1538
1828
|
return false;
|
|
1539
1829
|
}
|
|
1540
1830
|
|
|
1831
|
+
// A family whose writes are some other operation - the column
|
|
1832
|
+
// width, which is a resize - does them its own way
|
|
1833
|
+
if (family.write) { return family.write(node, value, view, options.source || 'api'); }
|
|
1834
|
+
|
|
1541
1835
|
var plan = planUtility(node, family, view, value);
|
|
1542
1836
|
if (!plan) { return false; }
|
|
1543
1837
|
|
|
@@ -1568,6 +1862,29 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1568
1862
|
});
|
|
1569
1863
|
}
|
|
1570
1864
|
|
|
1865
|
+
/**
|
|
1866
|
+
* ge.bareStyle(node, family, property): what a css property comes to
|
|
1867
|
+
* on a node with none of the family's classes, at any breakpoint. The
|
|
1868
|
+
* answer a preview needs for "no class applies here" when that is not
|
|
1869
|
+
* a constant: text-align inherits from the parent, and the host's own
|
|
1870
|
+
* css may float an element. The browser is the only one who knows, so
|
|
1871
|
+
* the classes come off for the moment it takes to ask.
|
|
1872
|
+
*/
|
|
1873
|
+
function bareStyle(node, name, property) {
|
|
1874
|
+
var family = familyNamed(name, 'bareStyle');
|
|
1875
|
+
node = $(node).first();
|
|
1876
|
+
if (!family || !node.length) { return null; }
|
|
1877
|
+
|
|
1878
|
+
var original = node.attr('class');
|
|
1879
|
+
BREAKPOINTS.forEach(function(tier) { writeUtility(node, family, tier, null); });
|
|
1880
|
+
|
|
1881
|
+
var value = getComputedStyle(node[0]).getPropertyValue(property);
|
|
1882
|
+
|
|
1883
|
+
if (original === undefined) { node.removeAttr('class'); } else { node.attr('class', original); }
|
|
1884
|
+
|
|
1885
|
+
return value;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1571
1888
|
/** Bring a node's panel and preview up to date with its classes. */
|
|
1572
1889
|
function refreshUtilities(node) {
|
|
1573
1890
|
var details = node.children('.ge-tools-drawer').children('.ge-details');
|
|
@@ -1598,6 +1915,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1598
1915
|
|
|
1599
1916
|
if (curView !== ALL_VIEW) { previewTier(scope, breakpoint(curView)); }
|
|
1600
1917
|
|
|
1918
|
+
markRowCols(scope);
|
|
1919
|
+
|
|
1601
1920
|
// Whatever a plugin marks the canvas with to show its utilities
|
|
1602
1921
|
// goes stale at the same moments the preview does
|
|
1603
1922
|
plugins('onRefresh', scope);
|
|
@@ -1615,6 +1934,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1615
1934
|
$.extend(styles, family.preview(effectiveUtility(node, family, tier), node, kind));
|
|
1616
1935
|
});
|
|
1617
1936
|
|
|
1937
|
+
if (kind === 'column') { $.extend(styles, rowColsPreview(node, tier)); }
|
|
1938
|
+
|
|
1618
1939
|
// A plugin whose families settle one property between them
|
|
1619
1940
|
// previews the node as a whole
|
|
1620
1941
|
$.each(UTILITIES, function(name, utility) {
|
|
@@ -1778,6 +2099,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1778
2099
|
blank = inherited
|
|
1779
2100
|
? t('utility.inherit', { value: labelOf(family, inherited.value), breakpoint: inherited.tier.key })
|
|
1780
2101
|
: t('utility.default');
|
|
2102
|
+
|
|
2103
|
+
// What the empty choice means is sometimes not the family's
|
|
2104
|
+
// own business: a column's width can come from its row
|
|
2105
|
+
var custom = family.blank ? family.blank(node, curView) : null;
|
|
2106
|
+
if (custom && own === null) { blank = custom; }
|
|
1781
2107
|
}
|
|
1782
2108
|
|
|
1783
2109
|
// A value the markup carries is shown even when the family
|
|
@@ -1876,17 +2202,6 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1876
2202
|
|
|
1877
2203
|
createMoveTool(drawer);
|
|
1878
2204
|
addSettingsTool(drawer, container, settings.container_classes);
|
|
1879
|
-
if (definition.addPane) {
|
|
1880
|
-
createTool(drawer, t(definition.addPaneKey), 'ge-add-pane', 'bi bi-plus-circle', function() {
|
|
1881
|
-
var pane = definition.addPane(container, {});
|
|
1882
|
-
|
|
1883
|
-
addNode(definition.paneKind, pane, function() {}, {
|
|
1884
|
-
parent: container,
|
|
1885
|
-
source: 'tool',
|
|
1886
|
-
container: container,
|
|
1887
|
-
});
|
|
1888
|
-
});
|
|
1889
|
-
}
|
|
1890
2205
|
|
|
1891
2206
|
settings.container_tools.forEach(function(hostTool) {
|
|
1892
2207
|
createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
@@ -1900,6 +2215,19 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1900
2215
|
container.slideUp(removed);
|
|
1901
2216
|
});
|
|
1902
2217
|
});
|
|
2218
|
+
|
|
2219
|
+
// Delete then add, the order rows and columns have
|
|
2220
|
+
if (definition.addPane) {
|
|
2221
|
+
createTool(drawer, t(definition.addPaneKey), 'ge-add-pane', 'bi bi-plus-circle', function() {
|
|
2222
|
+
var pane = definition.addPane(container, {});
|
|
2223
|
+
|
|
2224
|
+
addNode(definition.paneKind, pane, function() {}, {
|
|
2225
|
+
parent: container,
|
|
2226
|
+
source: 'tool',
|
|
2227
|
+
container: container,
|
|
2228
|
+
});
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
1903
2231
|
}
|
|
1904
2232
|
|
|
1905
2233
|
/**
|
|
@@ -2129,9 +2457,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2129
2457
|
settings.valid_col_sizes.forEach(function(size) {
|
|
2130
2458
|
$('<a class="ge-size" />')
|
|
2131
2459
|
.attr('data-ge-size', size)
|
|
2132
|
-
.attr('title',
|
|
2133
|
-
.toggleClass('ge-size-tight', size > room)
|
|
2134
|
-
.
|
|
2460
|
+
.attr('title', sizeTitle(size))
|
|
2461
|
+
.toggleClass('ge-size-tight', isUnits(size) && size > room)
|
|
2462
|
+
.toggleClass('ge-size-flex', !isUnits(size))
|
|
2463
|
+
.text(isUnits(size) ? size : sizeClass(BREAKPOINTS[0], size))
|
|
2135
2464
|
.on('click', function(e) {
|
|
2136
2465
|
e.preventDefault();
|
|
2137
2466
|
e.stopPropagation();
|
|
@@ -2152,6 +2481,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2152
2481
|
}
|
|
2153
2482
|
|
|
2154
2483
|
/** True when there was one to close, which is also a click's answer. */
|
|
2484
|
+
function sizeTitle(size) {
|
|
2485
|
+
if (size === 'equal') { return t('tool.column_equal'); }
|
|
2486
|
+
if (size === 'auto') { return t('tool.column_auto'); }
|
|
2487
|
+
|
|
2488
|
+
return t('tool.column_size', { size: size });
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2155
2491
|
function closeSizePicker() {
|
|
2156
2492
|
if (!sizePicker) { return false; }
|
|
2157
2493
|
|
|
@@ -2183,7 +2519,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2183
2519
|
createTool(drawer, t('tool.add_column'), 'ge-add-column', 'bi bi-plus-circle', function() {
|
|
2184
2520
|
if (closeSizePicker()) { return; } // The picker was open: that was the answer
|
|
2185
2521
|
|
|
2186
|
-
|
|
2522
|
+
// In a row with row-cols the new column takes its share
|
|
2523
|
+
addColumnTo(row, rowColsSource(row, leadingTier()) ? null : settings.add_column.size);
|
|
2187
2524
|
});
|
|
2188
2525
|
|
|
2189
2526
|
attachSizePicker(drawer.find('> .ge-add-column'), row);
|
|
@@ -2203,12 +2540,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2203
2540
|
createTool(drawer, t('tool.column_narrower'), 'ge-decrease-col-width', 'bi bi-dash-lg', function(e) {
|
|
2204
2541
|
resizeColumn(col, e.shiftKey
|
|
2205
2542
|
? smallest(settings.valid_col_sizes)
|
|
2206
|
-
: stepThrough(settings.valid_col_sizes,
|
|
2543
|
+
: stepThrough(settings.valid_col_sizes.filter(isUnits), currentUnits(col), -1),
|
|
2207
2544
|
'tool');
|
|
2208
2545
|
});
|
|
2209
2546
|
|
|
2210
2547
|
createTool(drawer, t('tool.column_wider'), 'ge-increase-col-width', 'bi bi-plus-lg', function(e) {
|
|
2211
|
-
resizeColumn(col, e.shiftKey
|
|
2548
|
+
resizeColumn(col, e.shiftKey
|
|
2549
|
+
? widestFor(col)
|
|
2550
|
+
: stepThrough(settings.valid_col_sizes.filter(isUnits), currentUnits(col), 1),
|
|
2551
|
+
'tool');
|
|
2212
2552
|
});
|
|
2213
2553
|
|
|
2214
2554
|
createTool(drawer, t('tool.indent_decrease'), 'ge-decrease-col-offset', 'bi bi-text-indent-right', function(e) {
|
|
@@ -2259,17 +2599,43 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2259
2599
|
* view it is the widest tier, because the canvas is not constrained
|
|
2260
2600
|
* there and the widest tier is what the user is looking at: clicking
|
|
2261
2601
|
* "narrower" on a column authored as col-lg-6 should take it to 5,
|
|
2262
|
-
* not to 11 because no
|
|
2602
|
+
* not to 11 because no base class was ever written. What the all view
|
|
2603
|
+
* writes is the base class all the same.
|
|
2263
2604
|
*/
|
|
2264
2605
|
function leadingTier() {
|
|
2265
2606
|
return curView === ALL_VIEW ? BREAKPOINTS[BREAKPOINTS.length - 1] : breakpoint(curView);
|
|
2266
2607
|
}
|
|
2267
2608
|
|
|
2609
|
+
/** The size that applies in the view: units, `equal` or `auto`. */
|
|
2268
2610
|
function currentSize(col) {
|
|
2269
|
-
var
|
|
2611
|
+
var tier = leadingTier();
|
|
2612
|
+
|
|
2613
|
+
// Sized by its row: it has no size of its own to report
|
|
2614
|
+
if (rowColsWinner(col, tier)) { return null; }
|
|
2615
|
+
|
|
2616
|
+
var size = getEffectiveSize(col, tier);
|
|
2270
2617
|
return size === null ? MAX_COL_SIZE : size;
|
|
2271
2618
|
}
|
|
2272
2619
|
|
|
2620
|
+
/**
|
|
2621
|
+
* The size in units, which is what the tools step through. An equal
|
|
2622
|
+
* or auto column has no number, so it is measured: the width it has
|
|
2623
|
+
* on the canvas, in twelfths of its row.
|
|
2624
|
+
*/
|
|
2625
|
+
function currentUnits(col) {
|
|
2626
|
+
var size = currentSize(col);
|
|
2627
|
+
if (isUnits(size)) { return size; }
|
|
2628
|
+
|
|
2629
|
+
var units = Math.round(col.outerWidth() / rowContentWidth(col.parent()) * MAX_COL_SIZE);
|
|
2630
|
+
return Math.min(Math.max(units, 1), MAX_COL_SIZE);
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
function rowContentWidth(row) {
|
|
2634
|
+
var style = window.getComputedStyle(row[0]);
|
|
2635
|
+
|
|
2636
|
+
return row[0].clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2273
2639
|
function currentOffset(col) {
|
|
2274
2640
|
return getEffectiveOffset(col, leadingTier()) || 0;
|
|
2275
2641
|
}
|
|
@@ -2289,11 +2655,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2289
2655
|
}
|
|
2290
2656
|
|
|
2291
2657
|
function smallest(values) {
|
|
2292
|
-
return values.reduce(function(a, b) { return Math.min(a, b); }, MAX_COL_SIZE);
|
|
2658
|
+
return values.filter(isUnits).reduce(function(a, b) { return Math.min(a, b); }, MAX_COL_SIZE);
|
|
2293
2659
|
}
|
|
2294
2660
|
|
|
2295
2661
|
function largest(values) {
|
|
2296
|
-
return values.reduce(function(a, b) { return Math.max(a, b); }, 0);
|
|
2662
|
+
return values.filter(isUnits).reduce(function(a, b) { return Math.max(a, b); }, 0);
|
|
2297
2663
|
}
|
|
2298
2664
|
|
|
2299
2665
|
/**
|
|
@@ -2311,7 +2677,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2311
2677
|
* itself left inside the row.
|
|
2312
2678
|
*/
|
|
2313
2679
|
function deepestFor(col) {
|
|
2314
|
-
var room = spare(col.parent(), leadingTier(), col) -
|
|
2680
|
+
var room = spare(col.parent(), leadingTier(), col) - currentUnits(col);
|
|
2315
2681
|
|
|
2316
2682
|
return Math.min(largest(settings.valid_col_offsets), Math.max(room, 0));
|
|
2317
2683
|
}
|
|
@@ -2354,6 +2720,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2354
2720
|
function isEditorClass(name) {
|
|
2355
2721
|
if (name === 'row' || name === 'column') { return true; }
|
|
2356
2722
|
if (/^(ge-|ui-)/.test(name)) { return true; }
|
|
2723
|
+
if (/^col(-(sm|md|lg|xl|xxl))?(-auto)?$/.test(name)) { return true; }
|
|
2357
2724
|
|
|
2358
2725
|
return BREAKPOINTS.some(function(tier) {
|
|
2359
2726
|
return new RegExp('^(' + tier.colPrefix + '|' + tier.offsetPrefix + ')\\d+$').test(name);
|
|
@@ -2382,11 +2749,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2382
2749
|
});
|
|
2383
2750
|
|
|
2384
2751
|
// Beside the gear, because every node that has one is a node a
|
|
2385
|
-
// utility may apply to, whichever plugin built its drawer
|
|
2752
|
+
// utility may apply to, whichever plugin built its drawer. A
|
|
2753
|
+
// feature plugin's tools go there too, for the same reason: the
|
|
2754
|
+
// gear is the one tool every drawer has.
|
|
2386
2755
|
var kind = kindOf(node);
|
|
2387
2756
|
$.each(UTILITIES, function(name, utility) {
|
|
2388
2757
|
if (utility.drawerTools) { utility.drawerTools(drawer, node, kind); }
|
|
2389
2758
|
});
|
|
2759
|
+
$.each(FEATURES, function(name, feature) {
|
|
2760
|
+
if (feature.drawerTools) { feature.drawerTools(drawer, node, kind); }
|
|
2761
|
+
});
|
|
2390
2762
|
|
|
2391
2763
|
return details.appendTo(drawer);
|
|
2392
2764
|
}
|
|
@@ -2452,15 +2824,137 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2452
2824
|
* column that had none.
|
|
2453
2825
|
*/
|
|
2454
2826
|
function addAllColClasses() {
|
|
2455
|
-
canvas.find('.column, div[class*="col-"]').each(function() {
|
|
2827
|
+
canvas.find('.column, div[class*="col-"], div.col').each(function() {
|
|
2456
2828
|
var col = $(this).addClass('column');
|
|
2457
2829
|
|
|
2458
|
-
|
|
2830
|
+
// A column in a row with row-cols is sized by its row
|
|
2831
|
+
if (sizedTiers(col).length || hasRowCols(col.parent())) { return; }
|
|
2459
2832
|
|
|
2460
2833
|
setSize(col, BREAKPOINTS[0], MAX_COL_SIZE);
|
|
2461
2834
|
});
|
|
2462
2835
|
}
|
|
2463
2836
|
|
|
2837
|
+
/* --------------------------------------------------------------
|
|
2838
|
+
* Columns per row: row-cols-*.
|
|
2839
|
+
*
|
|
2840
|
+
* A row's row-cols class gives every child an equal share of a
|
|
2841
|
+
* line, and a column's own size class takes that share's place.
|
|
2842
|
+
* Which of the two wins at a breakpoint is settled the way
|
|
2843
|
+
* Bootstrap's css settles it: the class from the wider breakpoint,
|
|
2844
|
+
* and at one breakpoint col loses to row-cols, which loses to
|
|
2845
|
+
* col-auto and col-N - the order Bootstrap writes their rules in.
|
|
2846
|
+
* -------------------------------------------------------------- */
|
|
2847
|
+
|
|
2848
|
+
function hasRowCols(row) {
|
|
2849
|
+
return row.hasClass('row') && BREAKPOINTS.some(function(tier) {
|
|
2850
|
+
return ROW_COLS_VALUES.some(function(value) { return row.hasClass(rowColsClass(tier, value)); });
|
|
2851
|
+
});
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
/** The row-cols class that applies to a row at a tier, as { tier, value }, or null. */
|
|
2855
|
+
function rowColsSource(row, tier) {
|
|
2856
|
+
if (!row.hasClass('row')) { return null; }
|
|
2857
|
+
|
|
2858
|
+
for (var i = BREAKPOINTS.indexOf(tier); i >= 0; i--) {
|
|
2859
|
+
for (var v = 0; v < ROW_COLS_VALUES.length; v++) {
|
|
2860
|
+
if (row.hasClass(rowColsClass(BREAKPOINTS[i], ROW_COLS_VALUES[v]))) {
|
|
2861
|
+
return { tier: i, value: ROW_COLS_VALUES[v] };
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
return null;
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
/** The column's own size that applies at a tier, as { tier, size }, or null. */
|
|
2870
|
+
function columnSource(col, tier) {
|
|
2871
|
+
for (var i = BREAKPOINTS.indexOf(tier); i >= 0; i--) {
|
|
2872
|
+
var size = getSize(col, BREAKPOINTS[i]);
|
|
2873
|
+
if (size !== null) { return { tier: i, size: size }; }
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
return null;
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
/**
|
|
2880
|
+
* The row-cols class that sizes this column at a tier, or null when
|
|
2881
|
+
* the column's own size does.
|
|
2882
|
+
*/
|
|
2883
|
+
function rowColsWinner(col, tier) {
|
|
2884
|
+
var row = rowColsSource(col.parent(), tier);
|
|
2885
|
+
if (!row) { return null; }
|
|
2886
|
+
|
|
2887
|
+
var own = columnSource(col, tier);
|
|
2888
|
+
if (!own || row.tier > own.tier) { return row; }
|
|
2889
|
+
|
|
2890
|
+
return row.tier === own.tier && own.size === 'equal' ? row : null;
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
/** A column's share of a line when its row sizes it, in units: auto has no number. */
|
|
2894
|
+
function rowColsUnits(winner) {
|
|
2895
|
+
return winner.value === 'auto' ? 0 : MAX_COL_SIZE / parseInt(winner.value, 10);
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2898
|
+
/**
|
|
2899
|
+
* What a breakpoint view shows of the row-cols a column is under. The
|
|
2900
|
+
* view narrows the canvas, not the window, and Bootstrap's
|
|
2901
|
+
* .row-cols-md-3 > * answers to the window - and to nothing the
|
|
2902
|
+
* preview can put on the row, since it styles the row's children.
|
|
2903
|
+
*/
|
|
2904
|
+
function rowColsPreview(col, tier) {
|
|
2905
|
+
var winner = rowColsWinner(col, tier);
|
|
2906
|
+
|
|
2907
|
+
if (winner) {
|
|
2908
|
+
return {
|
|
2909
|
+
flex: '0 0 auto',
|
|
2910
|
+
width: winner.value === 'auto' ? 'auto' : (100 / parseInt(winner.value, 10)) + '%',
|
|
2911
|
+
'max-width': '100%',
|
|
2912
|
+
};
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
// A wider breakpoint's row-cols is live in a wide window; a
|
|
2916
|
+
// column with no size of its own here is a full width one
|
|
2917
|
+
if (hasRowCols(col.parent()) && !columnSource(col, tier)) {
|
|
2918
|
+
return { flex: '0 0 auto', width: '100%', 'max-width': '100%' };
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
return {};
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
/**
|
|
2925
|
+
* The badge on a row whose columns are sized by row-cols in the view,
|
|
2926
|
+
* and in the all view by its row-cols with no breakpoint.
|
|
2927
|
+
*/
|
|
2928
|
+
function markRowCols(scope) {
|
|
2929
|
+
scope.find('.row').addBack('.row').each(function() {
|
|
2930
|
+
var row = $(this);
|
|
2931
|
+
var source = settings.row_cols === false ? null : (curView === ALL_VIEW
|
|
2932
|
+
? (rowColsSource(row, BREAKPOINTS[0]) || null)
|
|
2933
|
+
: rowColsSource(row, breakpoint(curView)));
|
|
2934
|
+
|
|
2935
|
+
if (!source) {
|
|
2936
|
+
row.removeAttr('data-ge-row-cols');
|
|
2937
|
+
} else {
|
|
2938
|
+
row.attr('data-ge-row-cols', rowColsLabel(source.value));
|
|
2939
|
+
}
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
function rowColsLabel(value) {
|
|
2944
|
+
return value === 'auto' ? t('badge.row_cols_auto') : t('badge.row_cols', { count: value });
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
/** The core's family for the field in a row's panel. */
|
|
2948
|
+
function rowColsFamily() {
|
|
2949
|
+
return {
|
|
2950
|
+
name: 'row-cols',
|
|
2951
|
+
prefix: 'row-cols',
|
|
2952
|
+
values: ROW_COLS_VALUES,
|
|
2953
|
+
appliesTo: ['row'],
|
|
2954
|
+
labelKey: 'utility.row_cols',
|
|
2955
|
+
};
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2464
2958
|
/* --------------------------------------------------------------
|
|
2465
2959
|
* The sizing core.
|
|
2466
2960
|
*
|
|
@@ -2470,9 +2964,18 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2470
2964
|
* names, the 12 unit budget and what an absent class means.
|
|
2471
2965
|
* -------------------------------------------------------------- */
|
|
2472
2966
|
|
|
2473
|
-
/**
|
|
2967
|
+
/**
|
|
2968
|
+
* A column's size at one tier: a number of units, `equal`, `auto`, or
|
|
2969
|
+
* null when that tier says nothing.
|
|
2970
|
+
*/
|
|
2474
2971
|
function getSize(col, tier) {
|
|
2475
|
-
|
|
2972
|
+
var units = readUnits(col, tier.colPrefix);
|
|
2973
|
+
if (units !== null) { return units; }
|
|
2974
|
+
|
|
2975
|
+
if (col.hasClass(sizeClass(tier, 'auto'))) { return 'auto'; }
|
|
2976
|
+
if (col.hasClass(sizeClass(tier, 'equal'))) { return 'equal'; }
|
|
2977
|
+
|
|
2978
|
+
return null;
|
|
2476
2979
|
}
|
|
2477
2980
|
|
|
2478
2981
|
/** The units a column is indented by at one tier, or null. */
|
|
@@ -2522,8 +3025,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2522
3025
|
col.attr('class', classes.join(' '));
|
|
2523
3026
|
}
|
|
2524
3027
|
|
|
2525
|
-
|
|
2526
|
-
|
|
3028
|
+
/** One size per tier: writing a size takes whatever size the tier had off. */
|
|
3029
|
+
function setSize(col, tier, size) {
|
|
3030
|
+
writeUnits(col, tier.colPrefix, null);
|
|
3031
|
+
FLEX_SIZES.forEach(function(flex) { col.removeClass(sizeClass(tier, flex)); });
|
|
3032
|
+
|
|
3033
|
+
if (size !== null && size !== undefined) { col.addClass(sizeClass(tier, size)); }
|
|
2527
3034
|
}
|
|
2528
3035
|
|
|
2529
3036
|
/** An offset of 0 is written as no class at all, which is what it means. */
|
|
@@ -2549,7 +3056,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2549
3056
|
var sibling = $(this);
|
|
2550
3057
|
if (ignore && sibling[0] === ignore[0]) { return; }
|
|
2551
3058
|
|
|
2552
|
-
|
|
3059
|
+
// An equal or auto column takes what is left, so it uses none;
|
|
3060
|
+
// one its row sizes uses its share of the line
|
|
3061
|
+
var winner = rowColsWinner(sibling, tier);
|
|
3062
|
+
var size = winner ? rowColsUnits(winner) : getEffectiveSize(sibling, tier);
|
|
3063
|
+
used += (isUnits(size) ? size : 0) + (getEffectiveOffset(sibling, tier) || 0);
|
|
2553
3064
|
});
|
|
2554
3065
|
|
|
2555
3066
|
return MAX_COL_SIZE - used;
|
|
@@ -2570,7 +3081,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2570
3081
|
|
|
2571
3082
|
offset = Math.min(Math.max(offset, 0), MAX_COL_OFFSET);
|
|
2572
3083
|
|
|
2573
|
-
if (size === null) { return { size:
|
|
3084
|
+
if (size === null || !isUnits(size)) { return { size: size, offset: offset, refused: false }; }
|
|
2574
3085
|
|
|
2575
3086
|
size = Math.min(Math.max(size, 1), MAX_COL_SIZE);
|
|
2576
3087
|
|
|
@@ -2614,6 +3125,35 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2614
3125
|
return 'ge-' + name + '-' + instanceId;
|
|
2615
3126
|
}
|
|
2616
3127
|
|
|
3128
|
+
/**
|
|
3129
|
+
* What the canvas, the columns and the plugins' regions move: rows,
|
|
3130
|
+
* content areas and containers, and whatever blocks a feature adds -
|
|
3131
|
+
* the sections plugin's sections.
|
|
3132
|
+
*/
|
|
3133
|
+
function blockSelector() {
|
|
3134
|
+
return ['.row', '.ge-content', '[data-ge-container]'].concat(pluginHooks('blocks')).join(', ');
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
/** A selector every feature plugin may contribute to, under one name. */
|
|
3138
|
+
function pluginHooks(name) {
|
|
3139
|
+
return $.map(FEATURES, function(feature) { return feature[name] || null; });
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
/**
|
|
3143
|
+
* Whether a region will have a block dropped in it. Every block goes
|
|
3144
|
+
* everywhere unless a feature says otherwise: a section only on the
|
|
3145
|
+
* canvas, and only rows in a section.
|
|
3146
|
+
*/
|
|
3147
|
+
function acceptsBlock(region, node) {
|
|
3148
|
+
var accepted = true;
|
|
3149
|
+
|
|
3150
|
+
$.each(FEATURES, function(name, feature) {
|
|
3151
|
+
if (accepted && feature.accepts && feature.accepts(region, node) === false) { accepted = false; }
|
|
3152
|
+
});
|
|
3153
|
+
|
|
3154
|
+
return accepted;
|
|
3155
|
+
}
|
|
3156
|
+
|
|
2617
3157
|
/** What must never start a drag, whatever the handle is. */
|
|
2618
3158
|
function dragCancelSelector() {
|
|
2619
3159
|
return settings.drag_handle === 'drawer'
|
|
@@ -2651,6 +3191,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2651
3191
|
? { name: groupName(options.group) }
|
|
2652
3192
|
: { name: groupName(options.draggable + '-' + (++soloGroup)), pull: false, put: false };
|
|
2653
3193
|
|
|
3194
|
+
// A list may turn some of its group's items away. A put
|
|
3195
|
+
// function replaces SortableJS's own test that the item comes
|
|
3196
|
+
// from the same group, so it makes that test too: without it
|
|
3197
|
+
// a column would drop into the canvas, or into another editor
|
|
3198
|
+
if (options.group && options.accepts) {
|
|
3199
|
+
group.put = function(to, from, dragged) {
|
|
3200
|
+
return from.options.group.name === group.name && options.accepts($(to.el), $(dragged));
|
|
3201
|
+
};
|
|
3202
|
+
}
|
|
3203
|
+
|
|
2654
3204
|
sortables.push(window.Sortable.create(list, $.extend({
|
|
2655
3205
|
group: group,
|
|
2656
3206
|
draggable: options.draggable,
|
|
@@ -2715,10 +3265,25 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2715
3265
|
});
|
|
2716
3266
|
|
|
2717
3267
|
sortable(canvas.add(canvas.find('.column')), {
|
|
2718
|
-
draggable:
|
|
3268
|
+
draggable: blockSelector(),
|
|
2719
3269
|
group: 'block',
|
|
3270
|
+
accepts: acceptsBlock,
|
|
2720
3271
|
});
|
|
2721
3272
|
|
|
3273
|
+
// A plugin's region can be a block itself - a section is both -
|
|
3274
|
+
// and SortableJS tests a list's own element against the draggable
|
|
3275
|
+
// selector when it counts the list's children, so every child of
|
|
3276
|
+
// a section would count as a block, its drawer first. '>' is
|
|
3277
|
+
// SortableJS for "direct children only", which the list is not.
|
|
3278
|
+
var regions = pluginHooks('regions');
|
|
3279
|
+
if (regions.length) {
|
|
3280
|
+
sortable(canvas.find(regions.join(', ')), {
|
|
3281
|
+
draggable: '>' + blockSelector(),
|
|
3282
|
+
group: 'block',
|
|
3283
|
+
accepts: acceptsBlock,
|
|
3284
|
+
});
|
|
3285
|
+
}
|
|
3286
|
+
|
|
2722
3287
|
// A plugin makes its own: only it knows which of its parts move
|
|
2723
3288
|
plugins('onSortable', sortable);
|
|
2724
3289
|
}
|
|
@@ -2889,20 +3454,21 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2889
3454
|
* divider between two columns looks like it should do.
|
|
2890
3455
|
*/
|
|
2891
3456
|
function snapUnits(col, pixels) {
|
|
2892
|
-
var
|
|
2893
|
-
var style = window.getComputedStyle(row[0]);
|
|
2894
|
-
var content = row[0].clientWidth -
|
|
2895
|
-
parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
|
|
2896
|
-
|
|
2897
|
-
var units = Math.round(pixels / content * MAX_COL_SIZE);
|
|
3457
|
+
var units = Math.round(pixels / rowContentWidth(col.parent()) * MAX_COL_SIZE);
|
|
2898
3458
|
var next = balanceSibling(col);
|
|
3459
|
+
var nextSize = next ? currentSize(next) : null;
|
|
3460
|
+
|
|
3461
|
+
// Measured when the drag started: the column is the width of the
|
|
3462
|
+
// pointer now, which is not what it was
|
|
3463
|
+
var own = col.data('ge-resize-units');
|
|
2899
3464
|
|
|
2900
3465
|
// With a sibling to balance against, the drag may take that
|
|
2901
3466
|
// column's units but not its last one. Without one, the row is
|
|
2902
3467
|
// allowed to wrap - that is what balance false means - so the only
|
|
2903
3468
|
// limit is the column's own budget against its indent.
|
|
2904
|
-
|
|
2905
|
-
|
|
3469
|
+
// An equal or auto sibling gives way by itself, so it sets no limit
|
|
3470
|
+
var room = next && isUnits(nextSize)
|
|
3471
|
+
? own + nextSize - smallest(settings.valid_col_sizes)
|
|
2906
3472
|
: MAX_COL_SIZE - currentOffset(col);
|
|
2907
3473
|
|
|
2908
3474
|
return Math.min(
|
|
@@ -2948,7 +3514,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2948
3514
|
if (!allowed) { return false; }
|
|
2949
3515
|
|
|
2950
3516
|
col.data('ge-resize-from', from);
|
|
2951
|
-
|
|
3517
|
+
col.data('ge-resize-units', currentUnits(col));
|
|
3518
|
+
resizeReadout(col, sizeLabel(col.data('ge-resize-units')));
|
|
2952
3519
|
|
|
2953
3520
|
return true;
|
|
2954
3521
|
}
|
|
@@ -2959,30 +3526,33 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2959
3526
|
|
|
2960
3527
|
function resizeStop(col, width) {
|
|
2961
3528
|
var from = col.data('ge-resize-from');
|
|
3529
|
+
var started = col.data('ge-resize-units');
|
|
2962
3530
|
var units = snapUnits(col, width);
|
|
2963
3531
|
|
|
2964
|
-
col.removeData('ge-resize-from');
|
|
3532
|
+
col.removeData('ge-resize-from').removeData('ge-resize-units');
|
|
2965
3533
|
resizeReadout(col, '');
|
|
2966
3534
|
stripPixelWidths(col);
|
|
2967
3535
|
|
|
2968
3536
|
if (from === undefined) { return; }
|
|
2969
3537
|
|
|
2970
3538
|
// A drag of a couple of pixels lands on the size it started from,
|
|
2971
|
-
// and is not a resize
|
|
2972
|
-
|
|
3539
|
+
// and is not a resize - not even of an equal or auto column,
|
|
3540
|
+
// which it would otherwise turn into a number
|
|
3541
|
+
if (units === started) { return; }
|
|
2973
3542
|
|
|
2974
3543
|
var plan = planSize(col, units);
|
|
2975
3544
|
if (!plan) { return; }
|
|
2976
3545
|
|
|
2977
3546
|
operate(function() {
|
|
2978
3547
|
writeSize(col, plan);
|
|
2979
|
-
balanceAfterResize(col,
|
|
3548
|
+
balanceAfterResize(col, units - started);
|
|
3549
|
+
refreshUtilities(col);
|
|
2980
3550
|
|
|
2981
|
-
emit('after-resize', payloadFor('column', col, {
|
|
3551
|
+
emit('after-resize', payloadFor('column', col, withCleared({
|
|
2982
3552
|
source: 'dragdrop',
|
|
2983
3553
|
from: from,
|
|
2984
3554
|
to: plan.size,
|
|
2985
|
-
}));
|
|
3555
|
+
}, plan.cleared)));
|
|
2986
3556
|
});
|
|
2987
3557
|
}
|
|
2988
3558
|
|
|
@@ -2990,12 +3560,22 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2990
3560
|
* Move the delta into the following column, so a full row stays full.
|
|
2991
3561
|
* It is part of the same gesture, so it is not announced separately.
|
|
2992
3562
|
*/
|
|
3563
|
+
/**
|
|
3564
|
+
* The column after takes what the resized one gave or took, unless it
|
|
3565
|
+
* is equal or auto: those take what is left by themselves.
|
|
3566
|
+
*/
|
|
2993
3567
|
function balanceAfterResize(col, delta) {
|
|
2994
3568
|
var next = balanceSibling(col);
|
|
2995
3569
|
if (!next || !delta) { return; }
|
|
2996
3570
|
|
|
2997
|
-
var
|
|
2998
|
-
if (
|
|
3571
|
+
var size = currentSize(next);
|
|
3572
|
+
if (!isUnits(size)) { return; }
|
|
3573
|
+
|
|
3574
|
+
var plan = planSize(next, size - delta);
|
|
3575
|
+
if (plan) {
|
|
3576
|
+
writeSize(next, plan);
|
|
3577
|
+
refreshUtilities(next);
|
|
3578
|
+
}
|
|
2999
3579
|
}
|
|
3000
3580
|
|
|
3001
3581
|
/**
|
|
@@ -3045,7 +3625,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3045
3625
|
var add = function() {
|
|
3046
3626
|
return addNode(kind, node, function() {
|
|
3047
3627
|
node[placement](options[placement]);
|
|
3048
|
-
}, { parent: parent, source: 'api' });
|
|
3628
|
+
}, { parent: parent, source: options.source || 'api' });
|
|
3049
3629
|
};
|
|
3050
3630
|
|
|
3051
3631
|
if (operationDepth > 0) {
|
|
@@ -3062,13 +3642,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3062
3642
|
function apiCreateRow(layout, options) {
|
|
3063
3643
|
var row = createRow();
|
|
3064
3644
|
|
|
3065
|
-
if (layout !== undefined && !Array.isArray(layout)) {
|
|
3066
|
-
warn('createRow: the layout is an array of column sizes, as in [8, 4]
|
|
3067
|
-
'Making an empty row instead.');
|
|
3645
|
+
if (layout !== undefined && !Array.isArray(layout) && !(layout && layout.row_cols)) {
|
|
3646
|
+
warn('createRow: the layout is an array of column sizes, as in [8, 4], or ' +
|
|
3647
|
+
'{ row_cols, columns }. Making an empty row instead.');
|
|
3068
3648
|
layout = [];
|
|
3069
3649
|
}
|
|
3070
3650
|
|
|
3071
|
-
(layout
|
|
3651
|
+
if (layout && !Array.isArray(layout)) { row = rowFromLayoutValue(layout); }
|
|
3652
|
+
|
|
3653
|
+
(Array.isArray(layout) ? layout : []).forEach(function(size) {
|
|
3072
3654
|
createColumn(size).appendTo(row);
|
|
3073
3655
|
});
|
|
3074
3656
|
|
|
@@ -3081,7 +3663,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3081
3663
|
function apiCreateColumn(size, options) {
|
|
3082
3664
|
options = options || {};
|
|
3083
3665
|
|
|
3084
|
-
|
|
3666
|
+
// Going into a row with row-cols, no size is a size: the row's share
|
|
3667
|
+
var into = $(options.appendTo || options.prependTo || []).first();
|
|
3668
|
+
|
|
3669
|
+
if (size === undefined && into.length && rowColsSource(into, leadingTier())) {
|
|
3670
|
+
size = null;
|
|
3671
|
+
} else if (!isUnits(size) && FLEX_SIZES.indexOf(size) === -1) {
|
|
3085
3672
|
warn('createColumn: no column size given, using ' + MAX_COL_SIZE);
|
|
3086
3673
|
size = MAX_COL_SIZE;
|
|
3087
3674
|
}
|
|
@@ -3152,8 +3739,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3152
3739
|
}
|
|
3153
3740
|
|
|
3154
3741
|
/**
|
|
3155
|
-
* A column sized for the current view:
|
|
3156
|
-
* all view. `offset` indents it, within the same 12 unit budget.
|
|
3742
|
+
* A column sized for the current view: its tier, or the base class in
|
|
3743
|
+
* the all view. `offset` indents it, within the same 12 unit budget.
|
|
3157
3744
|
*/
|
|
3158
3745
|
function createColumn(size, offset) {
|
|
3159
3746
|
var rte = getRTE(settings.content_types[0]);
|
|
@@ -3161,12 +3748,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3161
3748
|
.append(createDefaultContentWrapper().html(rte ? rte.initialContent : ''))
|
|
3162
3749
|
;
|
|
3163
3750
|
|
|
3164
|
-
|
|
3165
|
-
|
|
3751
|
+
// The tier being edited, or the base class in the all view
|
|
3752
|
+
var tier = tiersFor(curView)[0];
|
|
3753
|
+
var wanted = clamp({ size: size, offset: offset || 0, leading: 'offset' });
|
|
3166
3754
|
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
});
|
|
3755
|
+
setSize(column, tier, wanted.size === null ? size : wanted.size);
|
|
3756
|
+
setOffset(column, tier, wanted.offset);
|
|
3170
3757
|
|
|
3171
3758
|
return column;
|
|
3172
3759
|
}
|
|
@@ -3232,11 +3819,19 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3232
3819
|
return $();
|
|
3233
3820
|
}
|
|
3234
3821
|
|
|
3822
|
+
/**
|
|
3823
|
+
* A content area for the first content type. With no content types
|
|
3824
|
+
* it is a content area and nothing more: there is no type to name.
|
|
3825
|
+
*/
|
|
3235
3826
|
function createDefaultContentWrapper() {
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3827
|
+
var type = settings.content_types[0];
|
|
3828
|
+
var contentArea = $('<div class="ge-content"/>');
|
|
3829
|
+
|
|
3830
|
+
if (type) {
|
|
3831
|
+
contentArea.addClass('ge-content-type-' + type).attr('data-ge-content-type', type);
|
|
3832
|
+
}
|
|
3833
|
+
|
|
3834
|
+
return contentArea;
|
|
3240
3835
|
}
|
|
3241
3836
|
|
|
3242
3837
|
/**
|
|
@@ -3304,6 +3899,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3304
3899
|
*/
|
|
3305
3900
|
var handle = {
|
|
3306
3901
|
getHtml: getHtml,
|
|
3902
|
+
getPlainHtml: getPlainHtml,
|
|
3307
3903
|
// init and reset are deferred when a handler calls them, so an
|
|
3308
3904
|
// operation in flight finishes before the canvas is rebuilt
|
|
3309
3905
|
init: function() { defer(init); },
|
|
@@ -3324,6 +3920,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3324
3920
|
|
|
3325
3921
|
return featureMethods.createElement(content, options);
|
|
3326
3922
|
},
|
|
3923
|
+
createSection: function(options) {
|
|
3924
|
+
if (!featureMethods.createSection) {
|
|
3925
|
+
warnOnceHere('plugin:sections', 'createSection needs the sections plugin: ' +
|
|
3926
|
+
'include dist/plugins/grideditor.sections.js after the editor');
|
|
3927
|
+
return null;
|
|
3928
|
+
}
|
|
3929
|
+
|
|
3930
|
+
return featureMethods.createSection(options);
|
|
3931
|
+
},
|
|
3327
3932
|
createContainer: apiCreateContainer,
|
|
3328
3933
|
addTab: function(container, options) { return addPaneTo(container, 'tabs', options); },
|
|
3329
3934
|
addAccordionItem: function(container, options) {
|
|
@@ -3416,6 +4021,8 @@ $.fn.gridEditor.locales = {
|
|
|
3416
4021
|
'tool.add_row': 'Add row',
|
|
3417
4022
|
'tool.add_column': 'Add column\n(hold to choose the width)',
|
|
3418
4023
|
'tool.column_size': '{size} of 12',
|
|
4024
|
+
'tool.column_equal': 'Equal: shares what the row has left',
|
|
4025
|
+
'tool.column_auto': 'Auto: as wide as its content',
|
|
3419
4026
|
'tool.delete_row': 'Remove row',
|
|
3420
4027
|
'tool.delete_column': 'Remove col',
|
|
3421
4028
|
'tool.delete_container': 'Remove container',
|
|
@@ -3433,6 +4040,7 @@ $.fn.gridEditor.locales = {
|
|
|
3433
4040
|
'tool.classes_title': 'Css classes, separated by spaces',
|
|
3434
4041
|
'tool.toggle_class': 'Toggle "{label}" styling',
|
|
3435
4042
|
'row.add': 'Add row {layout}',
|
|
4043
|
+
'row.add_row_cols': 'Add a row of {columns} columns, {counts} per row',
|
|
3436
4044
|
'confirm.title': 'Confirm',
|
|
3437
4045
|
'confirm.ok': 'Delete',
|
|
3438
4046
|
'confirm.cancel': 'Cancel',
|
|
@@ -3447,6 +4055,13 @@ $.fn.gridEditor.locales = {
|
|
|
3447
4055
|
'view.xl': 'Large desktop',
|
|
3448
4056
|
'view.xxl': 'Widescreen',
|
|
3449
4057
|
'utility.section': 'Responsive: {view}',
|
|
4058
|
+
'utility.col_width': 'Width',
|
|
4059
|
+
'utility.col_equal': 'Equal',
|
|
4060
|
+
'utility.col_auto': 'Auto',
|
|
4061
|
+
'utility.col_from_row': 'From the row: {count}',
|
|
4062
|
+
'utility.row_cols': 'Columns per row',
|
|
4063
|
+
'badge.row_cols': '{count} per row',
|
|
4064
|
+
'badge.row_cols_auto': 'As wide as their content',
|
|
3450
4065
|
'utility.default': 'Default',
|
|
3451
4066
|
'utility.inherit': 'Inherit: {value} (from {breakpoint})',
|
|
3452
4067
|
'utility.varies': 'Changes at {breakpoints}; choosing here replaces that',
|