@themarioga/grid-editor 8.4.0 → 8.6.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 +51 -0
- package/README.md +105 -5
- package/dist/grideditor.bundle.min.js +3 -3
- package/dist/grideditor.css +15 -4
- package/dist/grideditor.d.ts +76 -4
- package/dist/grideditor.esm.js +212 -38
- package/dist/grideditor.js +212 -38
- package/dist/grideditor.min.css +1 -1
- package/dist/grideditor.min.css.map +1 -1
- package/dist/grideditor.min.js +2 -2
- package/dist/grideditor.min.js.map +3 -3
- package/dist/locales/grideditor.es.esm.js +5 -0
- package/dist/locales/grideditor.es.js +5 -0
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +2 -2
- package/dist/plugins/grideditor.accordion.esm.js +7 -0
- package/dist/plugins/grideditor.accordion.js +7 -0
- package/dist/plugins/grideditor.accordion.min.js +1 -1
- package/dist/plugins/grideditor.accordion.min.js.map +3 -3
- package/dist/plugins/grideditor.autosave.esm.js +309 -0
- package/dist/plugins/grideditor.autosave.js +316 -0
- package/dist/plugins/grideditor.autosave.min.js +1 -0
- package/dist/plugins/grideditor.autosave.min.js.map +7 -0
- package/dist/plugins/grideditor.card.esm.js +10 -0
- package/dist/plugins/grideditor.card.js +10 -0
- package/dist/plugins/grideditor.card.min.js +1 -1
- package/dist/plugins/grideditor.card.min.js.map +3 -3
- package/dist/plugins/grideditor.ckeditor.esm.js +30 -1
- package/dist/plugins/grideditor.ckeditor.js +30 -1
- package/dist/plugins/grideditor.ckeditor.min.js +1 -1
- package/dist/plugins/grideditor.ckeditor.min.js.map +3 -3
- package/dist/plugins/grideditor.clipboard.esm.js +3 -0
- package/dist/plugins/grideditor.clipboard.js +3 -0
- package/dist/plugins/grideditor.clipboard.min.js +1 -1
- package/dist/plugins/grideditor.clipboard.min.js.map +2 -2
- package/dist/plugins/grideditor.codemirror-inline.esm.js +11 -0
- package/dist/plugins/grideditor.codemirror-inline.js +11 -0
- package/dist/plugins/grideditor.codemirror-inline.min.js +1 -1
- package/dist/plugins/grideditor.codemirror-inline.min.js.map +3 -3
- package/dist/plugins/grideditor.elements.esm.js +78 -4
- package/dist/plugins/grideditor.elements.js +78 -4
- package/dist/plugins/grideditor.elements.min.js +1 -1
- package/dist/plugins/grideditor.elements.min.js.map +3 -3
- package/dist/plugins/grideditor.gutters.esm.js +5 -0
- package/dist/plugins/grideditor.gutters.js +5 -0
- package/dist/plugins/grideditor.gutters.min.js +1 -1
- package/dist/plugins/grideditor.gutters.min.js.map +3 -3
- package/dist/plugins/grideditor.inline-style.esm.js +18 -10
- package/dist/plugins/grideditor.inline-style.js +18 -10
- package/dist/plugins/grideditor.inline-style.min.js +3 -3
- package/dist/plugins/grideditor.inline-style.min.js.map +3 -3
- package/dist/plugins/grideditor.order.esm.js +5 -0
- package/dist/plugins/grideditor.order.js +5 -0
- package/dist/plugins/grideditor.order.min.js +1 -1
- package/dist/plugins/grideditor.order.min.js.map +3 -3
- package/dist/plugins/grideditor.popup.esm.js +17 -6
- package/dist/plugins/grideditor.popup.js +17 -6
- package/dist/plugins/grideditor.popup.min.js +1 -1
- package/dist/plugins/grideditor.popup.min.js.map +3 -3
- package/dist/plugins/grideditor.sections.esm.js +6 -3
- package/dist/plugins/grideditor.sections.js +6 -3
- package/dist/plugins/grideditor.sections.min.js +1 -1
- package/dist/plugins/grideditor.sections.min.js.map +3 -3
- package/dist/plugins/grideditor.summernote.esm.js +40 -1
- package/dist/plugins/grideditor.summernote.js +40 -1
- package/dist/plugins/grideditor.summernote.min.js +1 -1
- package/dist/plugins/grideditor.summernote.min.js.map +3 -3
- package/dist/plugins/grideditor.tabs.esm.js +7 -0
- package/dist/plugins/grideditor.tabs.js +7 -0
- package/dist/plugins/grideditor.tabs.min.js +1 -1
- package/dist/plugins/grideditor.tabs.min.js.map +3 -3
- package/dist/plugins/grideditor.tinymce.esm.js +32 -1
- package/dist/plugins/grideditor.tinymce.js +32 -1
- package/dist/plugins/grideditor.tinymce.min.js +1 -1
- package/dist/plugins/grideditor.tinymce.min.js.map +3 -3
- package/docs/events.md +8 -0
- package/docs/locale-keys.md +16 -1
- package/docs/plugins.md +60 -7
- package/example/autosave.html +39 -22
- package/example/index.html +1 -1
- package/example/plugins.html +10 -0
- package/package.json +1 -2
- package/src/js/grideditor.js +248 -28
- package/src/js/inline-style/display.js +4 -3
- package/src/js/inline-style/drawerflow.js +10 -5
- package/src/js/locales/grideditor.es.js +5 -0
- package/src/js/plugins/grideditor.accordion.js +6 -0
- package/src/js/plugins/grideditor.autosave.js +349 -0
- package/src/js/plugins/grideditor.card.js +6 -0
- package/src/js/plugins/grideditor.ckeditor.js +6 -0
- package/src/js/plugins/grideditor.clipboard.js +3 -0
- package/src/js/plugins/grideditor.codemirror-inline.js +7 -0
- package/src/js/plugins/grideditor.elements.js +98 -4
- package/src/js/plugins/grideditor.gutters.js +4 -0
- package/src/js/plugins/grideditor.inline-style.js +2 -0
- package/src/js/plugins/grideditor.order.js +4 -0
- package/src/js/plugins/grideditor.popup.js +15 -6
- package/src/js/plugins/grideditor.sections.js +4 -3
- package/src/js/plugins/grideditor.summernote.js +14 -0
- package/src/js/plugins/grideditor.tabs.js +6 -0
- package/src/js/plugins/grideditor.tinymce.js +8 -0
- package/src/js/text/grideditor.text.js +27 -1
- package/src/less/grideditor.less +16 -8
- package/types/grideditor.d.ts +76 -4
- package/AUTO_SAVE.md +0 -30
package/src/js/grideditor.js
CHANGED
|
@@ -142,6 +142,7 @@ var NESTED_SETTINGS = {
|
|
|
142
142
|
enabled: 'auto', // 'auto' turns them on when the page has any
|
|
143
143
|
selector: '[data-ge-element]', // What the host marks an element with
|
|
144
144
|
auto: false, // Treat every child of a content area as an element
|
|
145
|
+
types: [], // The elements the toolbar offers: { type, html, label | labelKey, iconClass, group }
|
|
145
146
|
},
|
|
146
147
|
resize: {
|
|
147
148
|
enabled: true, // The handle on the column's edge
|
|
@@ -627,30 +628,61 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
627
628
|
return;
|
|
628
629
|
}
|
|
629
630
|
|
|
631
|
+
confirmWith(message, { danger: true }, function(confirmed) {
|
|
632
|
+
if (confirmed) { whenConfirmed(); }
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* ge.confirm(): a question of a plugin's own, in the same modal.
|
|
638
|
+
* `answer` is called once: true for the ok button, false for cancel,
|
|
639
|
+
* the close button or Escape, and null when the question goes
|
|
640
|
+
* unanswered because the modal is taken away - setLocale, destroy, or
|
|
641
|
+
* another question asked over it.
|
|
642
|
+
*/
|
|
643
|
+
function confirmWith(message, options, answer) {
|
|
644
|
+
options = options || {};
|
|
630
645
|
var Modal = modalLibrary();
|
|
631
646
|
|
|
632
647
|
if (!Modal) {
|
|
633
|
-
|
|
648
|
+
answer(window.confirm(message));
|
|
634
649
|
return;
|
|
635
650
|
}
|
|
636
651
|
|
|
637
652
|
var modal = confirmModal();
|
|
638
653
|
var confirmed = false;
|
|
654
|
+
var ok = dom.one(modal, '.ge-confirm-ok');
|
|
655
|
+
|
|
656
|
+
// The question before this one, if it is still up, goes unanswered
|
|
657
|
+
if (pendingAnswer) { pendingAnswer(null); }
|
|
658
|
+
|
|
659
|
+
var settle = function(value) {
|
|
660
|
+
if (pendingAnswer !== settle) { return; }
|
|
661
|
+
pendingAnswer = null;
|
|
662
|
+
answer(value);
|
|
663
|
+
};
|
|
664
|
+
pendingAnswer = settle;
|
|
665
|
+
|
|
666
|
+
dom.one(modal, '.modal-title').textContent = options.title || t('confirm.title');
|
|
667
|
+
dom.one(modal, '.ge-confirm-cancel').textContent = options.cancel || t('confirm.cancel');
|
|
668
|
+
ok.textContent = options.ok || t('confirm.ok');
|
|
669
|
+
dom.toggleClass(ok, 'btn-danger', !!options.danger);
|
|
670
|
+
dom.toggleClass(ok, 'btn-primary', !options.danger);
|
|
639
671
|
|
|
640
672
|
dom.one(modal, '.ge-confirm-message').textContent = message;
|
|
641
|
-
|
|
673
|
+
ok.onclick = function() {
|
|
642
674
|
confirmed = true;
|
|
643
675
|
Modal.getInstance(modal).hide();
|
|
644
676
|
};
|
|
645
677
|
|
|
646
678
|
confirmHandlers.hidden = function() {
|
|
647
679
|
// After the modal is out of the way, so the backdrop is not
|
|
648
|
-
// sitting over the animation
|
|
649
|
-
|
|
680
|
+
// sitting over the animation a delete runs
|
|
681
|
+
settle(confirmed);
|
|
650
682
|
};
|
|
651
683
|
|
|
652
684
|
confirmHandlers.shown = function() {
|
|
653
|
-
|
|
685
|
+
ok.focus();
|
|
654
686
|
};
|
|
655
687
|
|
|
656
688
|
Modal.getOrCreateInstance(modal).show();
|
|
@@ -659,6 +691,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
659
691
|
// What the confirm modal does when Bootstrap says it is shown or
|
|
660
692
|
// hidden: this question's answer, replaced by the next question's
|
|
661
693
|
var confirmHandlers = { hidden: null, shown: null };
|
|
694
|
+
var pendingAnswer = null; // The open question's answer, until it is given
|
|
662
695
|
|
|
663
696
|
/** Built once per instance, and taken away again by destroy(). */
|
|
664
697
|
function confirmModal() {
|
|
@@ -689,11 +722,15 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
689
722
|
dom.one(confirmDialog, '.ge-confirm-ok').textContent = t('confirm.ok');
|
|
690
723
|
|
|
691
724
|
trackModal(confirmDialog);
|
|
725
|
+
// Only while it is the modal asking: one being taken away -
|
|
726
|
+
// setLocale builds another - finishes hiding after the next
|
|
727
|
+
// question is up, and that answer is not its to give
|
|
728
|
+
var asking = confirmDialog;
|
|
692
729
|
confirmDialog.addEventListener('hidden.bs.modal', function() {
|
|
693
|
-
if (confirmHandlers.hidden) { confirmHandlers.hidden(); }
|
|
730
|
+
if (asking === confirmDialog && confirmHandlers.hidden) { confirmHandlers.hidden(); }
|
|
694
731
|
});
|
|
695
732
|
confirmDialog.addEventListener('shown.bs.modal', function() {
|
|
696
|
-
if (confirmHandlers.shown) { confirmHandlers.shown(); }
|
|
733
|
+
if (asking === confirmDialog && confirmHandlers.shown) { confirmHandlers.shown(); }
|
|
697
734
|
});
|
|
698
735
|
|
|
699
736
|
return confirmDialog;
|
|
@@ -708,6 +745,9 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
708
745
|
confirmHandlers.shown = null;
|
|
709
746
|
retireModal(confirmDialog);
|
|
710
747
|
confirmDialog = null;
|
|
748
|
+
|
|
749
|
+
// A plugin's question goes unanswered, and the plugin is told so
|
|
750
|
+
if (pendingAnswer) { pendingAnswer(null); }
|
|
711
751
|
}
|
|
712
752
|
|
|
713
753
|
/**
|
|
@@ -1080,7 +1120,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1080
1120
|
settings.new_row_layouts.forEach(function(layout) {
|
|
1081
1121
|
var grouped = !Array.isArray(layout);
|
|
1082
1122
|
var btn = dom.element('a', {
|
|
1083
|
-
'class': 'btn btn-sm btn-
|
|
1123
|
+
'class': 'btn btn-sm btn-light',
|
|
1084
1124
|
title: grouped
|
|
1085
1125
|
? t('row.add_row_cols', { columns: layout.columns, counts: rowColsText(layout.row_cols) })
|
|
1086
1126
|
: t('row.add', { layout: layout.join('-') }),
|
|
@@ -1125,7 +1165,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1125
1165
|
// buttons next to these ones do
|
|
1126
1166
|
Object.keys(CONTAINERS).forEach(function(type) {
|
|
1127
1167
|
var definition = CONTAINERS[type];
|
|
1128
|
-
var button = labelButton(dom.element('a', { 'class': 'btn btn-sm btn-
|
|
1168
|
+
var button = labelButton(dom.element('a', { 'class': 'btn btn-sm btn-light ge-add-container' }),
|
|
1129
1169
|
t(definition.labelKey), definition.iconClass);
|
|
1130
1170
|
|
|
1131
1171
|
dom.attr(button, { 'data-ge-toolbar': 'container', 'data-ge-container-type': type });
|
|
@@ -1239,6 +1279,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1239
1279
|
var CORE_GROUPS = [
|
|
1240
1280
|
{ name: 'rows', labelKey: 'group.rows' },
|
|
1241
1281
|
{ name: 'content', labelKey: 'group.content' },
|
|
1282
|
+
{ name: 'elements', labelKey: 'group.elements' },
|
|
1242
1283
|
];
|
|
1243
1284
|
|
|
1244
1285
|
/** A plugin's category, when it names one. */
|
|
@@ -1272,7 +1313,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1272
1313
|
names.forEach(function(name) {
|
|
1273
1314
|
var tab = tabs.appendChild(dom.element('button', {
|
|
1274
1315
|
type: 'button',
|
|
1275
|
-
'class': 'btn btn-sm btn-outline-
|
|
1316
|
+
'class': 'btn btn-sm btn-outline-secondary',
|
|
1276
1317
|
role: 'tab',
|
|
1277
1318
|
'data-ge-group': name,
|
|
1278
1319
|
}, groupLabel(name)));
|
|
@@ -1331,7 +1372,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1331
1372
|
*/
|
|
1332
1373
|
function createOverflowMenu(start) {
|
|
1333
1374
|
var more = dom.create('<div class="ge-toolbar-more">' +
|
|
1334
|
-
'<button type="button" class="btn btn-sm btn-
|
|
1375
|
+
'<button type="button" class="btn btn-sm btn-light"><i class="bi bi-three-dots"></i></button>' +
|
|
1335
1376
|
'<div class="ge-toolbar-overflow">' +
|
|
1336
1377
|
'<div class="ge-addRowGroup btn-group"></div>' +
|
|
1337
1378
|
'<div class="ge-addContainerGroup btn-group"></div>' +
|
|
@@ -1440,7 +1481,10 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1440
1481
|
// A label of its own, worked out when the toolbar is built - and
|
|
1441
1482
|
// built again by setLocale - or the string its labelKey names
|
|
1442
1483
|
var label = typeof item.label === 'function' ? item.label() : (item.label || t(item.labelKey));
|
|
1443
|
-
|
|
1484
|
+
// Grey with the add buttons on the left, blue with the source and
|
|
1485
|
+
// preview buttons on the right
|
|
1486
|
+
var colour = item.align === 'end' ? 'btn-primary' : 'btn-light';
|
|
1487
|
+
var button = labelButton(dom.element('a', { 'class': 'btn btn-sm ' + colour + ' ge-add-container ge-add-feature' }), label, iconClass);
|
|
1444
1488
|
|
|
1445
1489
|
dom.addClass(button, item.className || '');
|
|
1446
1490
|
dom.attr(button, {
|
|
@@ -1452,6 +1496,8 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1452
1496
|
if (activeTarget) { addToTarget(button, item.source || 'tool'); return; }
|
|
1453
1497
|
|
|
1454
1498
|
var made = item.create();
|
|
1499
|
+
// A plugin that could not make one says so with null
|
|
1500
|
+
if (!made) { return; }
|
|
1455
1501
|
|
|
1456
1502
|
// One that belongs in a column brings a row and a column
|
|
1457
1503
|
// of its own, the way a container does
|
|
@@ -1611,6 +1657,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
1611
1657
|
function insertFeatureFromToolbar(button, where, source) {
|
|
1612
1658
|
var item = FEATURES[button.getAttribute('data-ge-feature')].toolbar[parseInt(button.getAttribute('data-ge-item'), 10)];
|
|
1613
1659
|
var made = item.create();
|
|
1660
|
+
if (!made) { return null; }
|
|
1614
1661
|
var placed = made;
|
|
1615
1662
|
|
|
1616
1663
|
if (item.inColumn) {
|
|
@@ -2085,26 +2132,144 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
2085
2132
|
hideDropMarker();
|
|
2086
2133
|
// In case a dialog was opened with no settings panel open
|
|
2087
2134
|
closeDialog();
|
|
2088
|
-
|
|
2135
|
+
removeDrawers(canvas);
|
|
2089
2136
|
pluginFields.clear();
|
|
2090
|
-
unwrapTexts();
|
|
2137
|
+
unwrapTexts(canvas);
|
|
2091
2138
|
plugins('onDeinit');
|
|
2092
2139
|
// After the rich text editors have let go of their content areas:
|
|
2093
2140
|
// one that rebuilt its area's DOM brought the preview styles back
|
|
2094
2141
|
// with it, and the attribute recording them came back too
|
|
2095
2142
|
clearPreviews(canvas);
|
|
2096
|
-
|
|
2143
|
+
clearRowCols(canvas);
|
|
2097
2144
|
unmarkContainers();
|
|
2098
2145
|
removeSortable();
|
|
2099
2146
|
removeResizable();
|
|
2100
|
-
runFilter(false);
|
|
2147
|
+
runFilter(false, canvas);
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
function removeDrawers(root) {
|
|
2151
|
+
dom.all(root, '.ge-tools-drawer').forEach(function(drawer) { drawer.remove(); });
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
function clearRowCols(root) {
|
|
2155
|
+
dom.all(root, '[data-ge-row-cols]').forEach(function(row) { row.removeAttribute('data-ge-row-cols'); });
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
/**
|
|
2159
|
+
* The plugins that cannot be read without the canvas leaving editing:
|
|
2160
|
+
* the ones that put something on the canvas - an unmark, an onDeinit
|
|
2161
|
+
* or an onBeforeDeinit takes it off - and say nothing of how to take
|
|
2162
|
+
* it off a copy.
|
|
2163
|
+
*/
|
|
2164
|
+
function pluginsWithoutCleanMarkup() {
|
|
2165
|
+
var names = [];
|
|
2166
|
+
|
|
2167
|
+
[CONTAINERS, FEATURES, UTILITIES].forEach(function(registry) {
|
|
2168
|
+
Object.keys(registry).forEach(function(name) {
|
|
2169
|
+
var plugin = registry[name];
|
|
2170
|
+
var marks = plugin.unmark || plugin.onDeinit || plugin.onBeforeDeinit;
|
|
2171
|
+
if (marks && !plugin.cleanMarkup) { names.push(name); }
|
|
2172
|
+
});
|
|
2173
|
+
});
|
|
2174
|
+
|
|
2175
|
+
return names;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
/**
|
|
2179
|
+
* A copy of the canvas, and the way from each of its elements back to
|
|
2180
|
+
* the one it was copied from. The two trees are walked side by side,
|
|
2181
|
+
* which works because a deep clone has the same shape.
|
|
2182
|
+
*/
|
|
2183
|
+
function copyCanvas() {
|
|
2184
|
+
var copy = canvas.cloneNode(true);
|
|
2185
|
+
var toLive = new Map();
|
|
2186
|
+
var toCopy = new Map();
|
|
2187
|
+
var live = document.createTreeWalker(canvas, NodeFilter.SHOW_ELEMENT);
|
|
2188
|
+
var copied = document.createTreeWalker(copy, NodeFilter.SHOW_ELEMENT);
|
|
2189
|
+
var a = live.currentNode;
|
|
2190
|
+
var b = copied.currentNode;
|
|
2191
|
+
|
|
2192
|
+
while (a && b) {
|
|
2193
|
+
toLive.set(b, a);
|
|
2194
|
+
toCopy.set(a, b);
|
|
2195
|
+
a = live.nextNode();
|
|
2196
|
+
b = copied.nextNode();
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
return {
|
|
2200
|
+
root: copy,
|
|
2201
|
+
liveOf: function(node) { return toLive.get(node) || null; },
|
|
2202
|
+
copyOf: function(node) { return toCopy.get(node) || null; },
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
/**
|
|
2207
|
+
* getHtml without the canvas leaving editing: what deinit takes off,
|
|
2208
|
+
* taken off a copy, so the text being typed into, the settings panel
|
|
2209
|
+
* and the focus are where they were. The same markup getHtml gives,
|
|
2210
|
+
* or getHtml itself - with a word, once - when a plugin can only take
|
|
2211
|
+
* its marking off the canvas, or will not this time.
|
|
2212
|
+
*/
|
|
2213
|
+
function snapshotHtml() {
|
|
2214
|
+
// Nothing is being edited to keep: the canvas is out of editing
|
|
2215
|
+
if (sourceOpen) { return getHtml(); }
|
|
2216
|
+
|
|
2217
|
+
var missing = pluginsWithoutCleanMarkup();
|
|
2218
|
+
if (missing.length) {
|
|
2219
|
+
missing.forEach(function(name) {
|
|
2220
|
+
warnOnceHere('snapshot:' + name, 'the "' + name + '" plugin has no cleanMarkup, so the canvas ' +
|
|
2221
|
+
'leaves editing to be read: open texts and settings panels close');
|
|
2222
|
+
});
|
|
2223
|
+
return getHtml();
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
var copy = copyCanvas();
|
|
2227
|
+
var root = copy.root;
|
|
2228
|
+
|
|
2229
|
+
[root].concat(dom.all(root, '.ge-active-target, .ge-settings-target')).forEach(function(node) {
|
|
2230
|
+
dom.removeClass(node, 'ge-active-target ge-settings-target');
|
|
2231
|
+
dom.dropEmptyClass(node);
|
|
2232
|
+
});
|
|
2233
|
+
dom.all(root, '.ge-drop-marker').forEach(function(marker) { marker.remove(); });
|
|
2234
|
+
removeDrawers(root);
|
|
2235
|
+
unwrapTexts(root);
|
|
2236
|
+
|
|
2237
|
+
var refused = null;
|
|
2238
|
+
[CONTAINERS, FEATURES, UTILITIES].forEach(function(registry) {
|
|
2239
|
+
Object.keys(registry).forEach(function(name) {
|
|
2240
|
+
var plugin = registry[name];
|
|
2241
|
+
if (refused || !plugin.cleanMarkup) { return; }
|
|
2242
|
+
if (plugin.cleanMarkup(root, copy.liveOf) === false) { refused = name; }
|
|
2243
|
+
});
|
|
2244
|
+
});
|
|
2245
|
+
|
|
2246
|
+
if (refused) {
|
|
2247
|
+
warnOnceHere('snapshot-refused:' + refused, 'the "' + refused + '" plugin cannot take its marking off ' +
|
|
2248
|
+
'a copy right now, so the canvas leaves editing to be read');
|
|
2249
|
+
return getHtml();
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
clearPreviews(root);
|
|
2253
|
+
clearRowCols(root);
|
|
2254
|
+
dom.all(root, '[data-ge-container]').forEach(unmarkContainerClasses);
|
|
2255
|
+
sortables.forEach(function(sortableInstance) {
|
|
2256
|
+
var list = copy.copyOf(sortableInstance.el);
|
|
2257
|
+
if (list) { dom.all(list, '[draggable]').forEach(function(node) { node.removeAttribute('draggable'); }); }
|
|
2258
|
+
});
|
|
2259
|
+
removeResizeFurniture(root);
|
|
2260
|
+
runFilter(false, root);
|
|
2261
|
+
stripPixelWidths(root);
|
|
2262
|
+
|
|
2263
|
+
return root.innerHTML;
|
|
2101
2264
|
}
|
|
2102
2265
|
|
|
2103
2266
|
/**
|
|
2104
2267
|
* The markup as a host would save it: no drawers, no editor, no
|
|
2105
2268
|
* sortables. The canvas goes back to editing afterwards.
|
|
2106
2269
|
*/
|
|
2107
|
-
function getHtml() {
|
|
2270
|
+
function getHtml(options) {
|
|
2271
|
+
if (options && options.keepEditing) { return snapshotHtml(); }
|
|
2272
|
+
|
|
2108
2273
|
deinit();
|
|
2109
2274
|
stripPixelWidths(canvas);
|
|
2110
2275
|
var html = canvas.innerHTML;
|
|
@@ -2125,8 +2290,31 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
2125
2290
|
}
|
|
2126
2291
|
|
|
2127
2292
|
/** getHtml with grid-editor's own classes and attributes taken off. */
|
|
2128
|
-
function getPlainHtml() {
|
|
2129
|
-
return plainHtml(getHtml());
|
|
2293
|
+
function getPlainHtml(options) {
|
|
2294
|
+
return plainHtml(getHtml(options));
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
/**
|
|
2298
|
+
* ge.setHtml(): the canvas made of other markup, and edited again. Not
|
|
2299
|
+
* an add or a delete of anything, so no events: what was there is
|
|
2300
|
+
* replaced as a whole. innerHTML, as the source view does, so a
|
|
2301
|
+
* <script> in it is markup and does not run in the editor.
|
|
2302
|
+
*/
|
|
2303
|
+
function setHtml(html) {
|
|
2304
|
+
// What is in the textarea is not wanted - html replaces it - but
|
|
2305
|
+
// the source view closes the one way it always does
|
|
2306
|
+
if (sourceOpen) {
|
|
2307
|
+
closeSource();
|
|
2308
|
+
if (mainControls) {
|
|
2309
|
+
dom.all(mainControls, '.gm-edit-mode').forEach(function(button) {
|
|
2310
|
+
dom.removeClass(button, 'active btn-danger');
|
|
2311
|
+
});
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
deinit();
|
|
2316
|
+
dom.setHtml(canvas, html);
|
|
2317
|
+
init();
|
|
2130
2318
|
}
|
|
2131
2319
|
|
|
2132
2320
|
/**
|
|
@@ -2136,6 +2324,8 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
2136
2324
|
* as a framework tearing a component down does.
|
|
2137
2325
|
*/
|
|
2138
2326
|
function destroy() {
|
|
2327
|
+
// First, while the editor is whole: a plugin may still read it
|
|
2328
|
+
plugins('onDestroy');
|
|
2139
2329
|
// The html being edited is what the canvas is left with
|
|
2140
2330
|
if (sourceOpen) { closeSource(); }
|
|
2141
2331
|
deinit();
|
|
@@ -2263,6 +2453,11 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
2263
2453
|
closeDialog: closeDialog,
|
|
2264
2454
|
rowFromLayout: rowFromLayoutValue,
|
|
2265
2455
|
nodeHtml: nodeHtml,
|
|
2456
|
+
// The markup as getHtml gives it, with the canvas left editing
|
|
2457
|
+
snapshotHtml: snapshotHtml,
|
|
2458
|
+
setHtml: setHtml,
|
|
2459
|
+
// A question in the editor's confirm modal
|
|
2460
|
+
confirm: confirmWith,
|
|
2266
2461
|
// A text editor has rewritten a content area, so whatever the
|
|
2267
2462
|
// editor and its plugins had put in there goes back in
|
|
2268
2463
|
textReady: textReady,
|
|
@@ -2985,11 +3180,15 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
2985
3180
|
|
|
2986
3181
|
if (definition) { definition.unmark(container); }
|
|
2987
3182
|
|
|
2988
|
-
|
|
2989
|
-
dom.dropEmptyClass(container);
|
|
3183
|
+
unmarkContainerClasses(container);
|
|
2990
3184
|
});
|
|
2991
3185
|
}
|
|
2992
3186
|
|
|
3187
|
+
function unmarkContainerClasses(container) {
|
|
3188
|
+
dom.removeClass(container, 'ge-container ge-container-' + containerTypeOf(container));
|
|
3189
|
+
dom.dropEmptyClass(container);
|
|
3190
|
+
}
|
|
3191
|
+
|
|
2993
3192
|
/** A new drawer as the first child of `node`. */
|
|
2994
3193
|
function prependDrawer(node, className) {
|
|
2995
3194
|
var drawer = dom.element('div', { 'class': className });
|
|
@@ -4918,10 +5117,14 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
4918
5117
|
}
|
|
4919
5118
|
|
|
4920
5119
|
function removeResizable() {
|
|
4921
|
-
|
|
5120
|
+
removeResizeFurniture(canvas);
|
|
5121
|
+
}
|
|
4922
5122
|
|
|
4923
|
-
|
|
4924
|
-
|
|
5123
|
+
function removeResizeFurniture(root) {
|
|
5124
|
+
dom.all(root, '.ge-resize-handle').forEach(function(handle) { handle.remove(); });
|
|
5125
|
+
|
|
5126
|
+
dom.all(root, '.ge-resize-size').forEach(function(readout) { readout.remove(); });
|
|
5127
|
+
stripPixelWidths(root);
|
|
4925
5128
|
}
|
|
4926
5129
|
|
|
4927
5130
|
/**
|
|
@@ -5247,7 +5450,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
5247
5450
|
* function, or the name of one on window, and gets the canvas and
|
|
5248
5451
|
* whether this is init.
|
|
5249
5452
|
*/
|
|
5250
|
-
function runFilter(isInit) {
|
|
5453
|
+
function runFilter(isInit, root) {
|
|
5251
5454
|
if (!settings.custom_filter || !settings.custom_filter.length) { return; }
|
|
5252
5455
|
|
|
5253
5456
|
var filters = typeof settings.custom_filter === 'string' || typeof settings.custom_filter === 'function'
|
|
@@ -5259,7 +5462,7 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
5259
5462
|
func = window[func];
|
|
5260
5463
|
}
|
|
5261
5464
|
|
|
5262
|
-
func(canvas, isInit);
|
|
5465
|
+
func(root || canvas, isInit);
|
|
5263
5466
|
});
|
|
5264
5467
|
}
|
|
5265
5468
|
|
|
@@ -5452,8 +5655,8 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
5452
5655
|
}
|
|
5453
5656
|
|
|
5454
5657
|
/** After the drawers are gone, so a wrapper holds its content area and nothing else. */
|
|
5455
|
-
function unwrapTexts() {
|
|
5456
|
-
dom.all(
|
|
5658
|
+
function unwrapTexts(root) {
|
|
5659
|
+
dom.all(root, '.ge-text-block').forEach(function(textBlock) {
|
|
5457
5660
|
dom.unwrap(textBlock);
|
|
5458
5661
|
});
|
|
5459
5662
|
}
|
|
@@ -5661,6 +5864,22 @@ function build(instance, baseElem, optionsOrMethod) {
|
|
|
5661
5864
|
// Again, with what the plugins filled in: the text editors'
|
|
5662
5865
|
// content_types when the host gave none
|
|
5663
5866
|
instance.settings = settingsCopy();
|
|
5867
|
+
|
|
5868
|
+
// A feature plugin's methods that are not the editor's own documented
|
|
5869
|
+
// ones - the autosave plugin's - are the instance's too, while the
|
|
5870
|
+
// plugin is there
|
|
5871
|
+
Object.keys(featureMethods).forEach(function(name) {
|
|
5872
|
+
if (Object.prototype.hasOwnProperty.call(own, name) || name in instance) { return; }
|
|
5873
|
+
|
|
5874
|
+
instance[name] = function() {
|
|
5875
|
+
if (destroyed) {
|
|
5876
|
+
warnOnceHere('destroyed:' + name, t('warning.destroyed', { method: name }));
|
|
5877
|
+
return null;
|
|
5878
|
+
}
|
|
5879
|
+
|
|
5880
|
+
return featureMethods[name].apply(null, arguments);
|
|
5881
|
+
};
|
|
5882
|
+
});
|
|
5664
5883
|
setup();
|
|
5665
5884
|
init();
|
|
5666
5885
|
|
|
@@ -5770,6 +5989,7 @@ GridEditor.locales = {
|
|
|
5770
5989
|
'tool.more': 'More',
|
|
5771
5990
|
'group.rows': 'Rows',
|
|
5772
5991
|
'group.content': 'Content',
|
|
5992
|
+
'group.elements': 'Elements',
|
|
5773
5993
|
'group.select': 'Add',
|
|
5774
5994
|
'panel.title': '{kind} settings',
|
|
5775
5995
|
'panel.close': 'Close',
|
|
@@ -177,8 +177,8 @@ export function displayPart(ge, given) {
|
|
|
177
177
|
});
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
function unmark() {
|
|
181
|
-
dom.all(ge.canvas, '.ge-hidden-in-view, [data-ge-hidden-in], [' + SHOWN_ATTR + ']').forEach(function(node) {
|
|
180
|
+
function unmark(root) {
|
|
181
|
+
dom.all(root || ge.canvas, '.ge-hidden-in-view, [data-ge-hidden-in], [' + SHOWN_ATTR + ']').forEach(function(node) {
|
|
182
182
|
dom.removeClass(node, 'ge-hidden-in-view');
|
|
183
183
|
node.removeAttribute('data-ge-hidden-in');
|
|
184
184
|
node.removeAttribute(SHOWN_ATTR);
|
|
@@ -224,6 +224,7 @@ export function displayPart(ge, given) {
|
|
|
224
224
|
},
|
|
225
225
|
|
|
226
226
|
onRefresh: mark,
|
|
227
|
-
onDeinit: unmark,
|
|
227
|
+
onDeinit: function() { unmark(); },
|
|
228
|
+
cleanMarkup: unmark,
|
|
228
229
|
};
|
|
229
230
|
}
|
|
@@ -95,15 +95,19 @@ export function drawerflowPart(ge) {
|
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
function
|
|
99
|
-
|
|
100
|
-
observer = null;
|
|
101
|
-
|
|
102
|
-
dom.all(ge.canvas, '.' + OUT_CLASS).forEach(function(node) {
|
|
98
|
+
function unmarkNodes(root) {
|
|
99
|
+
dom.all(root, '.' + OUT_CLASS).forEach(function(node) {
|
|
103
100
|
dom.removeClass(node, OUT_CLASS);
|
|
104
101
|
node.removeAttribute(OUT_ATTR);
|
|
105
102
|
dom.dropEmptyClass(node);
|
|
106
103
|
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function unmark() {
|
|
107
|
+
if (observer) { observer.disconnect(); }
|
|
108
|
+
observer = null;
|
|
109
|
+
|
|
110
|
+
unmarkNodes(ge.canvas);
|
|
107
111
|
|
|
108
112
|
if (sheet) { sheet.remove(); }
|
|
109
113
|
sheet = null;
|
|
@@ -114,5 +118,6 @@ export function drawerflowPart(ge) {
|
|
|
114
118
|
families: [],
|
|
115
119
|
onRefresh: mark,
|
|
116
120
|
onDeinit: unmark,
|
|
121
|
+
cleanMarkup: unmarkNodes,
|
|
117
122
|
};
|
|
118
123
|
}
|
|
@@ -54,6 +54,7 @@ GridEditor.locales.es = {
|
|
|
54
54
|
'tool.more': 'Más',
|
|
55
55
|
'group.rows': 'Filas',
|
|
56
56
|
'group.content': 'Contenido',
|
|
57
|
+
'group.elements': 'Elementos',
|
|
57
58
|
'group.select': 'Añadir',
|
|
58
59
|
'panel.title': 'Ajustes: {kind}',
|
|
59
60
|
'panel.close': 'Cerrar',
|
|
@@ -139,6 +140,10 @@ GridEditor.locales.es = {
|
|
|
139
140
|
'tool.paste': 'Pegar',
|
|
140
141
|
'clipboard.paste_row': 'Pegar fila',
|
|
141
142
|
'clipboard.paste_section': 'Pegar sección',
|
|
143
|
+
'autosave.restore_title': '¿Recuperar el borrador?',
|
|
144
|
+
'autosave.restore_message': 'Hay un borrador de esta página guardado el {date}, con cambios que no se publicaron. ¿Quieres recuperarlo?',
|
|
145
|
+
'autosave.restore': 'Recuperar',
|
|
146
|
+
'autosave.discard': 'Descartar',
|
|
142
147
|
'utility.col_from_row': 'De la fila: {count}',
|
|
143
148
|
'utility.row_cols': 'Columnas por fila',
|
|
144
149
|
'badge.row_cols': '{count} por fila',
|
|
@@ -206,6 +206,12 @@ GridEditor.containers.accordion = function(ge) {
|
|
|
206
206
|
ge.unwrapLabels(container);
|
|
207
207
|
},
|
|
208
208
|
|
|
209
|
+
// The same, on a copy of the canvas: unmark only touches markup
|
|
210
|
+
cleanMarkup: function(root) {
|
|
211
|
+
var definition = this;
|
|
212
|
+
dom.all(root, '[data-ge-container="accordion"]').forEach(function(container) { definition.unmark(container); });
|
|
213
|
+
},
|
|
214
|
+
|
|
209
215
|
afterPaneMove: function(container, item) {
|
|
210
216
|
reparentAccordionItem(container, item);
|
|
211
217
|
},
|