@themarioga/grid-editor 5.1.2 → 5.3.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/BUILDING.md +6 -0
- package/CHANGELOG.md +58 -0
- package/README.md +46 -9
- package/UPGRADING.md +25 -0
- package/dist/grideditor.css +28 -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 +760 -245
- package/dist/jquery.grideditor.min.js +1 -1
- package/dist/jquery.grideditor.min.js.map +1 -1
- package/dist/locales/grideditor.es.js +11 -0
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +1 -1
- package/dist/plugins/grideditor.ckeditor.js +120 -0
- package/dist/plugins/grideditor.ckeditor.min.js +2 -0
- package/dist/plugins/grideditor.ckeditor.min.js.map +1 -0
- package/dist/plugins/grideditor.clipboard.js +8 -7
- package/dist/plugins/grideditor.clipboard.min.js +1 -1
- package/dist/plugins/grideditor.clipboard.min.js.map +1 -1
- package/dist/plugins/grideditor.spacing.js +1 -1
- package/dist/plugins/grideditor.spacing.min.js +1 -1
- package/dist/plugins/grideditor.spacing.min.js.map +1 -1
- package/dist/plugins/grideditor.summernote.js +98 -0
- package/dist/plugins/grideditor.summernote.min.js +2 -0
- package/dist/plugins/grideditor.summernote.min.js.map +1 -0
- package/dist/plugins/grideditor.textalign.js +1 -1
- package/dist/plugins/grideditor.textalign.min.js +1 -1
- package/dist/plugins/grideditor.textalign.min.js.map +1 -1
- package/dist/plugins/grideditor.tinymce.js +162 -0
- package/dist/plugins/grideditor.tinymce.min.js +2 -0
- package/dist/plugins/grideditor.tinymce.min.js.map +1 -0
- package/dist/plugins/grideditor.visibility.js +3 -3
- package/dist/plugins/grideditor.visibility.min.js +1 -1
- package/dist/plugins/grideditor.visibility.min.js.map +1 -1
- package/docs/events.md +5 -2
- package/docs/locale-keys.md +23 -1
- package/docs/plugins.md +61 -4
- package/example/attributes.html +4 -2
- package/example/autosave.html +2 -0
- package/example/basic.html +2 -0
- package/example/ckeditor.html +2 -0
- package/example/clipboard.html +2 -0
- package/example/containers.html +2 -0
- package/example/elements.html +2 -0
- package/example/summernote.html +2 -0
- package/example/wrap_content.html +2 -0
- package/package.json +1 -1
- package/src/js/compat/bundled-texts.js +14 -0
- package/src/js/jquery.grideditor.js +444 -33
- package/src/js/locales/grideditor.es.js +11 -0
- package/src/js/plugins/grideditor.ckeditor.js +120 -0
- package/src/js/plugins/grideditor.clipboard.js +8 -7
- package/src/js/plugins/grideditor.spacing.js +1 -1
- package/src/js/plugins/grideditor.summernote.js +98 -0
- package/src/js/plugins/grideditor.textalign.js +1 -1
- package/src/js/plugins/grideditor.tinymce.js +162 -0
- package/src/js/plugins/grideditor.visibility.js +3 -3
- package/src/less/grideditor.less +34 -0
- package/src/js/jquery.grideditor.ckeditor.js +0 -77
- package/src/js/jquery.grideditor.summernote.js +0 -72
- package/src/js/jquery.grideditor.tinymce.js +0 -143
|
@@ -29,6 +29,7 @@ var METHODS = {
|
|
|
29
29
|
createRow: { value: true },
|
|
30
30
|
createColumn: { value: true },
|
|
31
31
|
createElement: { value: true },
|
|
32
|
+
createText: { value: true },
|
|
32
33
|
createSection: { value: true },
|
|
33
34
|
createContainer: { value: true },
|
|
34
35
|
addTab: { value: true },
|
|
@@ -338,6 +339,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
338
339
|
'toolbar_drag' : 'auto', // Drag the toolbar's buttons onto the canvas. 'auto' follows drag_handle
|
|
339
340
|
'element_tools' : [], // Host tools on element drawers, same shape as row_tools
|
|
340
341
|
'element_classes' : [], // Preset class toggles on an element's settings panel
|
|
342
|
+
'text_tools' : [], // Host tools on text block drawers
|
|
343
|
+
'text_classes' : [], // Preset class toggles on a text block's settings panel
|
|
341
344
|
'container_classes' : [], // The same, on a container's panel
|
|
342
345
|
'pane_classes' : [], // And on a tab's or an accordion item's
|
|
343
346
|
'container_tools' : [], // Host tools on container drawers
|
|
@@ -831,7 +834,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
831
834
|
if (node.hasClass('row')) { return 'row'; }
|
|
832
835
|
if (node.hasClass('column')) { return 'column'; }
|
|
833
836
|
if (node.hasClass('ge-element')) { return 'element'; }
|
|
834
|
-
if (node.hasClass('ge-content')) { return '
|
|
837
|
+
if (node.hasClass('ge-content') || node.hasClass('ge-text-block')) { return 'text'; }
|
|
835
838
|
return 'node';
|
|
836
839
|
}
|
|
837
840
|
|
|
@@ -879,6 +882,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
879
882
|
// which costs the element drawers inside it. The integrations say
|
|
880
883
|
// when their editor is ready, and the drawers go back in.
|
|
881
884
|
canvas.on('ge-rte-ready', '.ge-content', function() {
|
|
885
|
+
// The first time only: an undo says ready again, and by then
|
|
886
|
+
// the host may have changed the content area itself
|
|
887
|
+
if ($(this).data('ge-text-before') && !$(this).data('ge-text-ready')) {
|
|
888
|
+
$(this).data('ge-text-ready', attributesOf(this));
|
|
889
|
+
}
|
|
890
|
+
|
|
882
891
|
plugins('onContentReady', $(this));
|
|
883
892
|
refreshPreviews($(this));
|
|
884
893
|
});
|
|
@@ -936,6 +945,35 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
936
945
|
|
|
937
946
|
addContainerGroup.appendTo(wrapper);
|
|
938
947
|
|
|
948
|
+
// A text block of each editor offered. Like a container, it goes
|
|
949
|
+
// into a row of its own when clicked, or where it is dropped
|
|
950
|
+
var texts = offeredTexts();
|
|
951
|
+
texts.forEach(function(type) {
|
|
952
|
+
var label = texts.length > 1 ? t('text.add_type', { editor: textLabel(type) }) : t('text.add');
|
|
953
|
+
|
|
954
|
+
$('<a class="btn btn-sm btn-primary ge-add-container ge-add-text-button" />')
|
|
955
|
+
.attr('title', label)
|
|
956
|
+
.attr('data-ge-toolbar', 'text')
|
|
957
|
+
.attr('data-ge-text', type)
|
|
958
|
+
.append('<i class="bi bi-plus"></i>')
|
|
959
|
+
.append($('<span />').text(label))
|
|
960
|
+
.on('click', function() {
|
|
961
|
+
var row = createRow();
|
|
962
|
+
var block = makeText(type);
|
|
963
|
+
createColumn(MAX_COL_SIZE).appendTo(row).find('> .ge-content').replaceWith(block);
|
|
964
|
+
|
|
965
|
+
var added = addNode('text', block, function() {
|
|
966
|
+
row.appendTo(canvas);
|
|
967
|
+
}, { parent: canvas, source: 'tool' });
|
|
968
|
+
|
|
969
|
+
if (added && row[0].scrollIntoView) {
|
|
970
|
+
row[0].scrollIntoView({behavior: 'smooth'});
|
|
971
|
+
}
|
|
972
|
+
})
|
|
973
|
+
.appendTo(addContainerGroup)
|
|
974
|
+
;
|
|
975
|
+
});
|
|
976
|
+
|
|
939
977
|
// A container starts in a row of its own, the way the add row
|
|
940
978
|
// buttons next to these ones do
|
|
941
979
|
$.each(CONTAINERS, function(type, definition) {
|
|
@@ -1226,6 +1264,28 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1226
1264
|
}, { parent: where.region, source: item.source || 'dragdrop' });
|
|
1227
1265
|
}
|
|
1228
1266
|
|
|
1267
|
+
/**
|
|
1268
|
+
* A text block dropped from the toolbar: where it lands in a column,
|
|
1269
|
+
* or in a row and a column of its own anywhere else.
|
|
1270
|
+
*/
|
|
1271
|
+
function insertTextFromToolbar(button, where) {
|
|
1272
|
+
var made = makeText(button.attr('data-ge-text'));
|
|
1273
|
+
var placed = made;
|
|
1274
|
+
|
|
1275
|
+
if (!where.region.is('.column')) {
|
|
1276
|
+
placed = createRow();
|
|
1277
|
+
createColumn(MAX_COL_SIZE).appendTo(placed).find('> .ge-content').replaceWith(made);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
return addNode('text', made, function() {
|
|
1281
|
+
if (where.before) {
|
|
1282
|
+
placed.insertBefore(where.before);
|
|
1283
|
+
} else {
|
|
1284
|
+
placed.appendTo(where.region);
|
|
1285
|
+
}
|
|
1286
|
+
}, { parent: where.region, source: 'dragdrop' });
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1229
1289
|
/** A line where the block would go, following the pointer. */
|
|
1230
1290
|
function showDropMarker(pageX, pageY) {
|
|
1231
1291
|
var where = dropPlaceAt(pageX, pageY);
|
|
@@ -1255,6 +1315,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1255
1315
|
if (button.attr('data-ge-toolbar') === 'feature') {
|
|
1256
1316
|
return insertFeatureFromToolbar(button, where);
|
|
1257
1317
|
}
|
|
1318
|
+
if (button.attr('data-ge-toolbar') === 'text') {
|
|
1319
|
+
return insertTextFromToolbar(button, where);
|
|
1320
|
+
}
|
|
1258
1321
|
|
|
1259
1322
|
var container = button.attr('data-ge-toolbar') === 'container';
|
|
1260
1323
|
var type = button.attr('data-ge-container-type');
|
|
@@ -1404,11 +1467,28 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1404
1467
|
// its toolbar out against, and nothing anyone can type into
|
|
1405
1468
|
if (!$(this).is(':visible')) { return; }
|
|
1406
1469
|
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1470
|
+
// The attribute, not jQuery's cached copy of it: it is markup, and
|
|
1471
|
+
// the drawer reads it the same way
|
|
1472
|
+
var type = $(this).attr('data-ge-content-type');
|
|
1473
|
+
var text = textFor(type);
|
|
1474
|
+
if (!text) { return; }
|
|
1475
|
+
|
|
1476
|
+
// Not marked active, so the next click tries again: the library
|
|
1477
|
+
// may be loaded by then
|
|
1478
|
+
if (text.available && !text.available()) {
|
|
1479
|
+
if (text.missingKey) { console.error(t(text.missingKey)); }
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
if (text.bundled) {
|
|
1484
|
+
warnOnceHere('text-bundled:' + type, 'the ' + type + ' text editor is the copy in the ' +
|
|
1485
|
+
'main bundle, which 6.0 will not include: load dist/plugins/grideditor.' + type +
|
|
1486
|
+
'.js after the editor');
|
|
1411
1487
|
}
|
|
1488
|
+
|
|
1489
|
+
$(this).data('ge-text-before', attributesOf(this)).removeData('ge-text-ready');
|
|
1490
|
+
$(this).addClass('ge-rte-active');
|
|
1491
|
+
text.start($(this));
|
|
1412
1492
|
}
|
|
1413
1493
|
|
|
1414
1494
|
function reset() {
|
|
@@ -1422,6 +1502,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1422
1502
|
canvas.toggleClass('ge-drag-drawer', settings.drag_handle === 'drawer');
|
|
1423
1503
|
addAllColClasses();
|
|
1424
1504
|
wrapContent();
|
|
1505
|
+
wrapTexts();
|
|
1425
1506
|
createRowControls();
|
|
1426
1507
|
createColControls();
|
|
1427
1508
|
markContainers();
|
|
@@ -1434,21 +1515,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1434
1515
|
|
|
1435
1516
|
function deinit() {
|
|
1436
1517
|
canvas.removeClass('ge-editing ge-drag-drawer ge-dropping');
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
var rte = getRTE(content.data('ge-content-type'));
|
|
1440
|
-
if (rte) {
|
|
1441
|
-
rte.deinit(settings, content);
|
|
1442
|
-
}
|
|
1443
|
-
// Cleared after rte.deinit, not before: an editor can restore the
|
|
1444
|
-
// class attribute it snapshotted when it was created, which would
|
|
1445
|
-
// leave ge-rte-active in place and make initRTE ignore every later
|
|
1446
|
-
// click on this content area.
|
|
1447
|
-
content.removeClass('ge-rte-active');
|
|
1518
|
+
canvas.find('.ge-content').each(function() {
|
|
1519
|
+
closeText($(this));
|
|
1448
1520
|
});
|
|
1449
1521
|
closeSizePicker();
|
|
1450
1522
|
hideDropMarker();
|
|
1451
1523
|
canvas.find('.ge-tools-drawer').remove();
|
|
1524
|
+
unwrapTexts();
|
|
1452
1525
|
plugins('onDeinit');
|
|
1453
1526
|
// After the rich text editors have let go of their content areas:
|
|
1454
1527
|
// one that rebuilt its area's DOM brought the preview styles back
|
|
@@ -1555,6 +1628,23 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1555
1628
|
if (wanted(name)) { FEATURES[name] = factory(api); }
|
|
1556
1629
|
});
|
|
1557
1630
|
|
|
1631
|
+
// Text editors are chosen by content_types rather than by the
|
|
1632
|
+
// plugins setting: a page that names its containers there has
|
|
1633
|
+
// named no editor, and still wants the one it uses
|
|
1634
|
+
$.each($.fn.gridEditor.texts, function(type, factory) {
|
|
1635
|
+
TEXTS[type] = $.extend({ bundled: !!factory.bundled }, factory(api));
|
|
1636
|
+
});
|
|
1637
|
+
|
|
1638
|
+
// 5.x's registry, for an integration a host wrote itself. One the
|
|
1639
|
+
// plugins above already provide is theirs.
|
|
1640
|
+
$.each($.fn.gridEditor.RTEs, function(type, rte) {
|
|
1641
|
+
if (TEXTS[type]) { return; }
|
|
1642
|
+
|
|
1643
|
+
warnOnceHere('rtes:' + type, '$.fn.gridEditor.RTEs is deprecated and will be removed ' +
|
|
1644
|
+
'in 7.0: register "' + type + '" under $.fn.gridEditor.texts, see docs/plugins.md');
|
|
1645
|
+
TEXTS[type] = legacyText(rte);
|
|
1646
|
+
});
|
|
1647
|
+
|
|
1558
1648
|
$.each($.fn.gridEditor.utilities, function(name, factory) {
|
|
1559
1649
|
if (!wanted(name)) { return; }
|
|
1560
1650
|
|
|
@@ -1631,6 +1721,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1631
1721
|
bareStyle: bareStyle,
|
|
1632
1722
|
rowFromLayout: rowFromLayoutValue,
|
|
1633
1723
|
nodeHtml: nodeHtml,
|
|
1724
|
+
// A text editor has rewritten a content area, so whatever the
|
|
1725
|
+
// editor and its plugins had put in there goes back in
|
|
1726
|
+
textReady: function(block) { block.trigger('ge-rte-ready'); },
|
|
1727
|
+
// A node's drawer: its first child, or for a content area the
|
|
1728
|
+
// one beside it in its text block
|
|
1729
|
+
drawerOf: function(node) {
|
|
1730
|
+
return node.hasClass('ge-content')
|
|
1731
|
+
? node.parent('.ge-text-block').children('.ge-tools-drawer')
|
|
1732
|
+
: node.children('.ge-tools-drawer');
|
|
1733
|
+
},
|
|
1634
1734
|
toolbarItems: function(name) {
|
|
1635
1735
|
return mainControls
|
|
1636
1736
|
? mainControls.find('[data-ge-toolbar="feature"][data-ge-feature="' + name + '"]')
|
|
@@ -1657,7 +1757,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1657
1757
|
* -------------------------------------------------------------- */
|
|
1658
1758
|
|
|
1659
1759
|
var FAMILIES = {}; // Every family the utility plugins declare, by name
|
|
1660
|
-
var UTILITY_NODES = '.row, .column, .ge-element, [data-ge-container]';
|
|
1760
|
+
var UTILITY_NODES = '.row, .column, .ge-content, .ge-element, [data-ge-container]';
|
|
1661
1761
|
var PREVIEW_ATTR = 'data-ge-preview';
|
|
1662
1762
|
var utilitiesOpen = false; // Whether the panels show their Responsive section unfolded
|
|
1663
1763
|
|
|
@@ -2164,6 +2264,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2164
2264
|
* -------------------------------------------------------------- */
|
|
2165
2265
|
|
|
2166
2266
|
var CONTAINERS = {}; // The container plugins in use, by the type each builds
|
|
2267
|
+
var TEXTS = {}; // The text editor plugins, by the content type each edits
|
|
2167
2268
|
var FEATURES = {}; // The feature plugins in use, by name
|
|
2168
2269
|
var UTILITIES = {}; // The utility plugins in use, by name
|
|
2169
2270
|
var featureMethods = {}; // The methods those features contribute
|
|
@@ -2444,6 +2545,14 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2444
2545
|
function attachSizePicker(tool, row) {
|
|
2445
2546
|
if (!settings.add_column.picker) { return; }
|
|
2446
2547
|
|
|
2548
|
+
attachPicker(tool, function() { openSizePicker(tool, row); });
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
/**
|
|
2552
|
+
* Hold a tool - or rest the pointer on it - and `open` offers a
|
|
2553
|
+
* choice under it. The add text tool offers its editors the same way.
|
|
2554
|
+
*/
|
|
2555
|
+
function attachPicker(tool, open) {
|
|
2447
2556
|
var timer = null;
|
|
2448
2557
|
|
|
2449
2558
|
var cancel = function() {
|
|
@@ -2456,7 +2565,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2456
2565
|
|
|
2457
2566
|
timer = window.setTimeout(function() {
|
|
2458
2567
|
timer = null;
|
|
2459
|
-
|
|
2568
|
+
open();
|
|
2460
2569
|
}, settings.add_column.delay);
|
|
2461
2570
|
});
|
|
2462
2571
|
|
|
@@ -2606,6 +2715,22 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2606
2715
|
});
|
|
2607
2716
|
});
|
|
2608
2717
|
|
|
2718
|
+
// A text block of the first editor offered; held, the tool
|
|
2719
|
+
// offers each of them when there is more than one
|
|
2720
|
+
var texts = offeredTexts();
|
|
2721
|
+
if (texts.length) {
|
|
2722
|
+
createTool(drawer, t('tool.add_text'), 'ge-add-text', 'bi bi-type', function() {
|
|
2723
|
+
if (closeSizePicker()) { return; } // The picker was open: that was the answer
|
|
2724
|
+
|
|
2725
|
+
addTextTo(col, texts[0]);
|
|
2726
|
+
});
|
|
2727
|
+
|
|
2728
|
+
if (texts.length > 1) {
|
|
2729
|
+
var textTool = drawer.find('> .ge-add-text');
|
|
2730
|
+
attachPicker(textTool, function() { openTextPicker(textTool, col); });
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2609
2734
|
createTool(drawer, t('tool.add_row'), 'ge-add-row', 'bi bi-plus-circle', function() {
|
|
2610
2735
|
// An empty row: the columns in it are the next decision,
|
|
2611
2736
|
// and its drawer's add column tool is where that is made
|
|
@@ -2720,7 +2845,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2720
2845
|
}
|
|
2721
2846
|
|
|
2722
2847
|
function createTool(drawer, title, className, iconClass, eventHandlers) {
|
|
2723
|
-
|
|
2848
|
+
// Through attr rather than spliced into markup: a title is text,
|
|
2849
|
+
// and a quote in it - a type name, a host's own title - would
|
|
2850
|
+
// end the attribute early
|
|
2851
|
+
var tool = $('<a />')
|
|
2852
|
+
.attr('title', title)
|
|
2853
|
+
.attr('class', className)
|
|
2854
|
+
.append($('<i />').attr('class', iconClass))
|
|
2724
2855
|
.appendTo(drawer)
|
|
2725
2856
|
;
|
|
2726
2857
|
if (typeof eventHandlers == 'function') {
|
|
@@ -3154,11 +3285,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3154
3285
|
|
|
3155
3286
|
/**
|
|
3156
3287
|
* What the canvas, the columns and the plugins' regions move: rows,
|
|
3157
|
-
*
|
|
3158
|
-
* the sections plugin's sections.
|
|
3288
|
+
* text blocks and containers, and whatever blocks a feature adds -
|
|
3289
|
+
* the sections plugin's sections. A content area is a block through
|
|
3290
|
+
* the text block around it while editing, and on its own before.
|
|
3159
3291
|
*/
|
|
3160
3292
|
function blockSelector() {
|
|
3161
|
-
return ['.row', '.ge-content', '[data-ge-container]']
|
|
3293
|
+
return ['.row', '.ge-text-block', '.ge-content', '[data-ge-container]']
|
|
3294
|
+
.concat(pluginHooks('blocks')).join(', ');
|
|
3162
3295
|
}
|
|
3163
3296
|
|
|
3164
3297
|
/** A selector every feature plugin may contribute to, under one name. */
|
|
@@ -3324,12 +3457,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3324
3457
|
function sortStart(e) {
|
|
3325
3458
|
var node = $(e.item);
|
|
3326
3459
|
var from = positionOf(node);
|
|
3460
|
+
var subject = moveSubject(node);
|
|
3327
3461
|
|
|
3328
3462
|
node.data('ge-move-from', from);
|
|
3329
3463
|
node.removeData('ge-move-canceled');
|
|
3330
3464
|
|
|
3331
3465
|
operate(function() {
|
|
3332
|
-
var moving = emit('before-move', payloadFor(
|
|
3466
|
+
var moving = emit('before-move', payloadFor(subject.kind, subject.node, {
|
|
3333
3467
|
parent: from.parent,
|
|
3334
3468
|
source: 'dragdrop',
|
|
3335
3469
|
from: from,
|
|
@@ -3339,6 +3473,19 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3339
3473
|
});
|
|
3340
3474
|
}
|
|
3341
3475
|
|
|
3476
|
+
/**
|
|
3477
|
+
* What a drag reports as moving. A text block is the editor's own
|
|
3478
|
+
* wrapper, so what moved is the content area inside it, and until 6.0
|
|
3479
|
+
* a content area moves as kind 'content', as it did in 5.x - adding
|
|
3480
|
+
* and deleting one, which 5.x never announced, already say 'text'.
|
|
3481
|
+
*/
|
|
3482
|
+
function moveSubject(item) {
|
|
3483
|
+
var node = item.hasClass('ge-text-block') ? item.children('.ge-content') : item;
|
|
3484
|
+
var kind = kindOf(node);
|
|
3485
|
+
|
|
3486
|
+
return { kind: kind === 'text' ? 'content' : kind, node: node };
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3342
3489
|
/** Put a node back where a refused drag found it. */
|
|
3343
3490
|
function putBack(node, from) {
|
|
3344
3491
|
var siblings = from.parent.children().not('.ge-tools-drawer').not(node);
|
|
@@ -3376,8 +3523,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3376
3523
|
// No init() here, unlike an add: the node brought its drawer
|
|
3377
3524
|
// with it, and the drag is still being finished, so this is the
|
|
3378
3525
|
// wrong moment to rebuild the lists it is using.
|
|
3526
|
+
var subject = moveSubject(node);
|
|
3527
|
+
|
|
3379
3528
|
operate(function() {
|
|
3380
|
-
emit('after-move', payloadFor(
|
|
3529
|
+
emit('after-move', payloadFor(subject.kind, subject.node, {
|
|
3381
3530
|
parent: to.parent,
|
|
3382
3531
|
source: 'dragdrop',
|
|
3383
3532
|
from: from,
|
|
@@ -3770,9 +3919,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3770
3919
|
* the all view. `offset` indents it, within the same 12 unit budget.
|
|
3771
3920
|
*/
|
|
3772
3921
|
function createColumn(size, offset) {
|
|
3773
|
-
var
|
|
3922
|
+
var text = textFor(settings.content_types[0]);
|
|
3774
3923
|
var column = $('<div class="column"/>')
|
|
3775
|
-
.append(createDefaultContentWrapper().html(
|
|
3924
|
+
.append(createDefaultContentWrapper().html(text ? text.initialContent : ''))
|
|
3776
3925
|
;
|
|
3777
3926
|
|
|
3778
3927
|
// The tier being edited, or the base class in the all view
|
|
@@ -3820,7 +3969,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3820
3969
|
// A container sits in the column beside the content
|
|
3821
3970
|
// areas, not inside one, so it ends a run of loose
|
|
3822
3971
|
// content rather than joining it
|
|
3823
|
-
if (child.is('.row, .ge-content, [data-ge-container]')) {
|
|
3972
|
+
if (child.is('.row, .ge-content, .ge-text-block, [data-ge-container]')) {
|
|
3824
3973
|
contents = doWrap(contents);
|
|
3825
3974
|
} else {
|
|
3826
3975
|
contents = contents.add(child);
|
|
@@ -3847,11 +3996,12 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3847
3996
|
}
|
|
3848
3997
|
|
|
3849
3998
|
/**
|
|
3850
|
-
* A content area for the first
|
|
3851
|
-
* it is a content area and nothing more: there is no
|
|
3999
|
+
* A content area for a content type, the first one by default. With
|
|
4000
|
+
* no content types it is a content area and nothing more: there is no
|
|
4001
|
+
* type to name.
|
|
3852
4002
|
*/
|
|
3853
|
-
function createDefaultContentWrapper() {
|
|
3854
|
-
|
|
4003
|
+
function createDefaultContentWrapper(type) {
|
|
4004
|
+
type = type || settings.content_types[0];
|
|
3855
4005
|
var contentArea = $('<div class="ge-content"/>');
|
|
3856
4006
|
|
|
3857
4007
|
if (type) {
|
|
@@ -3861,6 +4011,236 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3861
4011
|
return contentArea;
|
|
3862
4012
|
}
|
|
3863
4013
|
|
|
4014
|
+
/* --------------------------------------------------------------
|
|
4015
|
+
* Text blocks: a content area as a block of its own, with a drawer.
|
|
4016
|
+
*
|
|
4017
|
+
* The drawer cannot go inside the content area, as every other
|
|
4018
|
+
* block's does: what is inside is the text editor's, which would make
|
|
4019
|
+
* the drawer editable text, copy it into its own document or take it
|
|
4020
|
+
* away on an undo. So while editing, each content area in a column
|
|
4021
|
+
* sits in a .ge-text-block beside its drawer, and that wrapper is the
|
|
4022
|
+
* block the column moves. deinit takes it off again: it is never part
|
|
4023
|
+
* of the markup.
|
|
4024
|
+
* -------------------------------------------------------------- */
|
|
4025
|
+
|
|
4026
|
+
/** The text editors this editor offers, in content_types order: the ones loaded. */
|
|
4027
|
+
function offeredTexts() {
|
|
4028
|
+
return settings.content_types.filter(function(type) { return !!TEXTS[type]; });
|
|
4029
|
+
}
|
|
4030
|
+
|
|
4031
|
+
function wrapTexts() {
|
|
4032
|
+
canvas.find('.column > .ge-content').each(function() {
|
|
4033
|
+
$(this).wrap('<div class="ge-text-block" />');
|
|
4034
|
+
});
|
|
4035
|
+
|
|
4036
|
+
canvas.find('.ge-text-block').each(function() {
|
|
4037
|
+
var textBlock = $(this);
|
|
4038
|
+
if (!textBlock.children('.ge-tools-drawer').length) { createTextControls(textBlock); }
|
|
4039
|
+
});
|
|
4040
|
+
}
|
|
4041
|
+
|
|
4042
|
+
/** After the drawers are gone, so a wrapper holds its content area and nothing else. */
|
|
4043
|
+
function unwrapTexts() {
|
|
4044
|
+
canvas.find('.ge-text-block').each(function() {
|
|
4045
|
+
$(this).replaceWith($(this).contents());
|
|
4046
|
+
});
|
|
4047
|
+
}
|
|
4048
|
+
|
|
4049
|
+
function createTextControls(textBlock) {
|
|
4050
|
+
var block = textBlock.children('.ge-content');
|
|
4051
|
+
var type = block.attr('data-ge-content-type');
|
|
4052
|
+
var drawer = $('<div class="ge-tools-drawer ge-text-drawer" />').prependTo(textBlock);
|
|
4053
|
+
|
|
4054
|
+
createMoveTool(drawer);
|
|
4055
|
+
|
|
4056
|
+
// Which editor edits it, or that none can: a type whose plugin is
|
|
4057
|
+
// not loaded is still a block to move and delete, but not to edit
|
|
4058
|
+
if (type && TEXTS[type]) {
|
|
4059
|
+
createTool(drawer, t('tool.text_info', { editor: textLabel(type) }), 'ge-text-info', 'bi bi-fonts');
|
|
4060
|
+
} else if (type) {
|
|
4061
|
+
createTool(drawer, t('text.no_editor', { type: type }), 'ge-text-info ge-text-missing',
|
|
4062
|
+
'bi bi-exclamation-triangle');
|
|
4063
|
+
}
|
|
4064
|
+
|
|
4065
|
+
addSettingsTool(drawer, block, settings.text_classes);
|
|
4066
|
+
|
|
4067
|
+
settings.text_tools.forEach(function(hostTool) {
|
|
4068
|
+
createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
4069
|
+
hostTool.iconClass || 'bi bi-wrench', hostTool.on);
|
|
4070
|
+
});
|
|
4071
|
+
|
|
4072
|
+
createTool(drawer, t('tool.delete_text'), 'ge-delete-text', 'bi bi-trash', function() {
|
|
4073
|
+
deleteNode('text', block, t('confirm.delete_text'), function(removed) {
|
|
4074
|
+
// Its editor lets go first: removed while open, it would
|
|
4075
|
+
// be left behind, attached to nothing
|
|
4076
|
+
closeText(block);
|
|
4077
|
+
textBlock.slideUp(function() {
|
|
4078
|
+
textBlock.remove();
|
|
4079
|
+
removed();
|
|
4080
|
+
});
|
|
4081
|
+
});
|
|
4082
|
+
});
|
|
4083
|
+
}
|
|
4084
|
+
|
|
4085
|
+
/**
|
|
4086
|
+
* Close the text editor on one content area, and leave the content
|
|
4087
|
+
* area's own attributes as the host left them.
|
|
4088
|
+
*
|
|
4089
|
+
* An editor adds attributes of its own while it is open, and takes
|
|
4090
|
+
* them off again, more or less: CKEditor leaves aria-readonly behind.
|
|
4091
|
+
* tinyMCE does worse, and puts back every attribute as it was when it
|
|
4092
|
+
* opened, so an id, a class or a plugin's attribute given while it was
|
|
4093
|
+
* open is lost. So the attributes are read three times - before the
|
|
4094
|
+
* editor opens, once it has opened, and before it closes - and what
|
|
4095
|
+
* changed between the second and the third, the host's doing, is
|
|
4096
|
+
* played back onto the first, the host's markup. What the editor did
|
|
4097
|
+
* is left out either way.
|
|
4098
|
+
*/
|
|
4099
|
+
function closeText(block) {
|
|
4100
|
+
var text = textFor(block.attr('data-ge-content-type'));
|
|
4101
|
+
var before = block.data('ge-text-before');
|
|
4102
|
+
var open = before ? attributesOf(block[0]) : null;
|
|
4103
|
+
|
|
4104
|
+
// Every content area is told, as in 5.x: one whose editor never
|
|
4105
|
+
// started is the plugin's to ignore
|
|
4106
|
+
if (text) { text.stop(block); }
|
|
4107
|
+
|
|
4108
|
+
// After stop, not before: an editor that restores the class
|
|
4109
|
+
// attribute it snapshotted would put ge-rte-active back
|
|
4110
|
+
block.removeClass('ge-rte-active');
|
|
4111
|
+
|
|
4112
|
+
if (before) {
|
|
4113
|
+
restoreAttributes(block, before, block.data('ge-text-ready') || before, open);
|
|
4114
|
+
block.removeData('ge-text-before').removeData('ge-text-ready');
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
|
|
4118
|
+
/** What a text editor puts on a content area while it is open, whenever it likes. */
|
|
4119
|
+
var EDITOR_CLASS = /^(mce-|cke|note-)|^(active|ge-rte-active)$/;
|
|
4120
|
+
var EDITOR_ATTRIBUTE = /^(data-mce-|contenteditable$|spellcheck$)/;
|
|
4121
|
+
|
|
4122
|
+
function attributesOf(element) {
|
|
4123
|
+
var found = {};
|
|
4124
|
+
$.each($.makeArray(element.attributes), function(i, attribute) {
|
|
4125
|
+
found[attribute.name] = attribute.value;
|
|
4126
|
+
});
|
|
4127
|
+
return found;
|
|
4128
|
+
}
|
|
4129
|
+
|
|
4130
|
+
function classesIn(value) {
|
|
4131
|
+
return (value || '').split(/\s+/).filter(function(name) {
|
|
4132
|
+
return name !== '' && !EDITOR_CLASS.test(name);
|
|
4133
|
+
});
|
|
4134
|
+
}
|
|
4135
|
+
|
|
4136
|
+
/** The host's markup, with what changed from `ready` to `open` played back onto it. */
|
|
4137
|
+
function restoreAttributes(block, before, ready, open) {
|
|
4138
|
+
var result = $.extend({}, before);
|
|
4139
|
+
|
|
4140
|
+
$.each($.extend({}, ready, open), function(name) {
|
|
4141
|
+
if (name === 'class' || EDITOR_ATTRIBUTE.test(name) || ready[name] === open[name]) { return; }
|
|
4142
|
+
|
|
4143
|
+
if (open[name] === undefined) {
|
|
4144
|
+
delete result[name];
|
|
4145
|
+
} else {
|
|
4146
|
+
result[name] = open[name];
|
|
4147
|
+
}
|
|
4148
|
+
});
|
|
4149
|
+
|
|
4150
|
+
var readyClasses = classesIn(ready['class']);
|
|
4151
|
+
var openClasses = classesIn(open['class']);
|
|
4152
|
+
var classes = classesIn(before['class']).filter(function(name) {
|
|
4153
|
+
return openClasses.indexOf(name) !== -1 || readyClasses.indexOf(name) === -1;
|
|
4154
|
+
});
|
|
4155
|
+
openClasses.forEach(function(name) {
|
|
4156
|
+
if (readyClasses.indexOf(name) === -1 && classes.indexOf(name) === -1) { classes.push(name); }
|
|
4157
|
+
});
|
|
4158
|
+
|
|
4159
|
+
// In the host's order, class where it was: getHtml should not
|
|
4160
|
+
// shuffle a node's attributes because it was edited
|
|
4161
|
+
if (classes.length) { result['class'] = classes.join(' '); } else { delete result['class']; }
|
|
4162
|
+
|
|
4163
|
+
$.each(attributesOf(block[0]), function(name) { block.removeAttr(name); });
|
|
4164
|
+
$.each(result, function(name, value) { block.attr(name, value); });
|
|
4165
|
+
}
|
|
4166
|
+
|
|
4167
|
+
/** What a text editor is called: its plugin's label, or its type. */
|
|
4168
|
+
function textLabel(type) {
|
|
4169
|
+
var text = TEXTS[type];
|
|
4170
|
+
return text && text.labelKey ? t(text.labelKey) : type;
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
/** A detached content area of `type`, holding `content` or the editor's initial content. */
|
|
4174
|
+
function makeText(type, content) {
|
|
4175
|
+
var text = TEXTS[type];
|
|
4176
|
+
return createDefaultContentWrapper(type)
|
|
4177
|
+
.html(content !== undefined ? content : (text && text.initialContent) || '');
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
/** A text block at the end of a column, through the add events. */
|
|
4181
|
+
function addTextTo(col, type) {
|
|
4182
|
+
var block = makeText(type);
|
|
4183
|
+
|
|
4184
|
+
return addNode('text', block, function() {
|
|
4185
|
+
col.append(block);
|
|
4186
|
+
}, { parent: col, source: 'tool' });
|
|
4187
|
+
}
|
|
4188
|
+
|
|
4189
|
+
/**
|
|
4190
|
+
* createText(type?, options?): a content area of a text editor's,
|
|
4191
|
+
* detached unless a placement is given. The type is the first one
|
|
4192
|
+
* offered by default. `options.content` is its html.
|
|
4193
|
+
*/
|
|
4194
|
+
function apiCreateText(type, options) {
|
|
4195
|
+
if (type && typeof type === 'object') {
|
|
4196
|
+
options = type;
|
|
4197
|
+
type = undefined;
|
|
4198
|
+
}
|
|
4199
|
+
options = options || {};
|
|
4200
|
+
type = type || offeredTexts()[0];
|
|
4201
|
+
|
|
4202
|
+
if (!type || !TEXTS[type]) {
|
|
4203
|
+
warnOnceHere('createText:' + type, 'createText: no text editor "' + type + '" is loaded; ' +
|
|
4204
|
+
'load its plugin and name it in content_types');
|
|
4205
|
+
return null;
|
|
4206
|
+
}
|
|
4207
|
+
|
|
4208
|
+
return place(makeText(type, options.content), 'text', options);
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
/**
|
|
4212
|
+
* The text editors offered, as a strip under the add text tool, when
|
|
4213
|
+
* there is more than one to choose from.
|
|
4214
|
+
*/
|
|
4215
|
+
function openTextPicker(tool, col) {
|
|
4216
|
+
closeSizePicker();
|
|
4217
|
+
|
|
4218
|
+
tool.closest('.ge-tools-drawer').addClass('ge-picker-open');
|
|
4219
|
+
sizePicker = $('<div class="ge-size-picker ge-text-picker" />').appendTo(tool);
|
|
4220
|
+
|
|
4221
|
+
offeredTexts().forEach(function(type) {
|
|
4222
|
+
$('<a class="ge-size ge-size-flex" />')
|
|
4223
|
+
.attr('data-ge-content-type', type)
|
|
4224
|
+
.attr('title', t('tool.add_text_type', { editor: textLabel(type) }))
|
|
4225
|
+
.text(textLabel(type))
|
|
4226
|
+
.on('click', function(e) {
|
|
4227
|
+
e.preventDefault();
|
|
4228
|
+
e.stopPropagation();
|
|
4229
|
+
|
|
4230
|
+
closeSizePicker();
|
|
4231
|
+
addTextTo(col, type);
|
|
4232
|
+
})
|
|
4233
|
+
.appendTo(sizePicker)
|
|
4234
|
+
;
|
|
4235
|
+
});
|
|
4236
|
+
|
|
4237
|
+
tool.one('mouseleave', function() {
|
|
4238
|
+
window.setTimeout(function() {
|
|
4239
|
+
if (sizePicker && !sizePicker.is(':hover')) { closeSizePicker(); }
|
|
4240
|
+
}, 400);
|
|
4241
|
+
});
|
|
4242
|
+
}
|
|
4243
|
+
|
|
3864
4244
|
/**
|
|
3865
4245
|
* Constrain the canvas to the view's preview width and make that
|
|
3866
4246
|
* tier's classes the effective ones. The all view constrains nothing:
|
|
@@ -3915,8 +4295,21 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3915
4295
|
return curView;
|
|
3916
4296
|
}
|
|
3917
4297
|
|
|
3918
|
-
|
|
3919
|
-
|
|
4298
|
+
/** The text editor plugin for a content type, or null. */
|
|
4299
|
+
function textFor(type) {
|
|
4300
|
+
return TEXTS[type] || null;
|
|
4301
|
+
}
|
|
4302
|
+
|
|
4303
|
+
/**
|
|
4304
|
+
* An integration written to 5.x's contract - init and deinit over a
|
|
4305
|
+
* set of content areas - as a text editor plugin.
|
|
4306
|
+
*/
|
|
4307
|
+
function legacyText(rte) {
|
|
4308
|
+
return {
|
|
4309
|
+
initialContent: rte.initialContent,
|
|
4310
|
+
start: function(block) { rte.init(settings, block); },
|
|
4311
|
+
stop: function(block) { rte.deinit(settings, block); },
|
|
4312
|
+
};
|
|
3920
4313
|
}
|
|
3921
4314
|
|
|
3922
4315
|
/**
|
|
@@ -3938,6 +4331,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3938
4331
|
getView: getView,
|
|
3939
4332
|
createRow: apiCreateRow,
|
|
3940
4333
|
createColumn: apiCreateColumn,
|
|
4334
|
+
createText: apiCreateText,
|
|
3941
4335
|
createElement: function(content, options) {
|
|
3942
4336
|
if (!featureMethods.createElement) {
|
|
3943
4337
|
warnOnceHere('plugin:elements', 'createElement needs the elements plugin: ' +
|
|
@@ -3991,6 +4385,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3991
4385
|
|
|
3992
4386
|
};
|
|
3993
4387
|
|
|
4388
|
+
/**
|
|
4389
|
+
* Text editor plugins: tinyMCE, CKEditor, summernote, and whatever a host
|
|
4390
|
+
* writes. A factory registered under the content type it edits, called once
|
|
4391
|
+
* per editor with the handle described in docs/plugins.md, returning
|
|
4392
|
+
* { labelKey, initialContent, available, missingKey, start, stop }.
|
|
4393
|
+
*/
|
|
4394
|
+
$.fn.gridEditor.texts = {};
|
|
4395
|
+
|
|
4396
|
+
/** 5.x's registry of text editors, adapted with a warning. Removed in 7.0. */
|
|
3994
4397
|
$.fn.gridEditor.RTEs = {};
|
|
3995
4398
|
|
|
3996
4399
|
/**
|
|
@@ -4046,6 +4449,13 @@ $.fn.gridEditor.locales = {
|
|
|
4046
4449
|
'tool.move': 'Move',
|
|
4047
4450
|
'tool.settings': 'Settings',
|
|
4048
4451
|
'tool.add_row': 'Add row',
|
|
4452
|
+
'tool.add_text': 'Add text',
|
|
4453
|
+
'tool.add_text_type': 'Add {editor} text',
|
|
4454
|
+
'tool.text_info': 'Text: {editor}',
|
|
4455
|
+
'tool.delete_text': 'Remove text',
|
|
4456
|
+
'text.add': 'Text',
|
|
4457
|
+
'text.add_type': 'Text ({editor})',
|
|
4458
|
+
'text.no_editor': 'No text editor "{type}" is loaded: this text can be moved and deleted, not edited',
|
|
4049
4459
|
'tool.add_column': 'Add column\n(hold to choose the width)',
|
|
4050
4460
|
'tool.column_size': '{size} of 12',
|
|
4051
4461
|
'tool.column_equal': 'Equal: shares what the row has left',
|
|
@@ -4073,6 +4483,7 @@ $.fn.gridEditor.locales = {
|
|
|
4073
4483
|
'confirm.cancel': 'Cancel',
|
|
4074
4484
|
'confirm.delete_row': 'Delete row?',
|
|
4075
4485
|
'confirm.delete_column': 'Delete column?',
|
|
4486
|
+
'confirm.delete_text': 'Delete this text?',
|
|
4076
4487
|
'confirm.delete_container': 'Delete this container and everything in it?',
|
|
4077
4488
|
'view.all': 'All sizes',
|
|
4078
4489
|
'view.xs': 'Phone',
|
|
@@ -4101,30 +4512,235 @@ $.fn.gridEditor.locales = {
|
|
|
4101
4512
|
};
|
|
4102
4513
|
|
|
4103
4514
|
})( jQuery );
|
|
4515
|
+
/**
|
|
4516
|
+
* tinyMCE for grid-editor's content areas.
|
|
4517
|
+
*
|
|
4518
|
+
* A text editor plugin: load this file after the editor, and tinyMCE 6
|
|
4519
|
+
* after or before it, and content_types: ['tinymce'] edits each content area
|
|
4520
|
+
* with an inline tinyMCE. What it can ask the editor for is the handle its
|
|
4521
|
+
* factory is called with, described in docs/plugins.md.
|
|
4522
|
+
*
|
|
4523
|
+
* <script src="tinymce/tinymce.min.js"></script>
|
|
4524
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
4525
|
+
* <script src="dist/plugins/grideditor.tinymce.min.js"></script>
|
|
4526
|
+
*
|
|
4527
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
4528
|
+
*/
|
|
4104
4529
|
(function($) {
|
|
4105
|
-
$.fn.gridEditor.RTEs.ckeditor = {
|
|
4106
4530
|
|
|
4107
|
-
|
|
4531
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
4532
|
+
'text.tinymce': 'tinyMCE',
|
|
4533
|
+
});
|
|
4108
4534
|
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4535
|
+
// tinyMCE snapshots the target element's attributes when an inline editor is
|
|
4536
|
+
// created and restores them on remove(), so this has to run *after* remove()
|
|
4537
|
+
// to keep the grid editor's own class and tinyMCE's leftovers off the element.
|
|
4538
|
+
function cleanUp(contentArea) {
|
|
4539
|
+
contentArea
|
|
4540
|
+
.removeClass('active')
|
|
4541
|
+
.removeClass('ge-rte-active')
|
|
4542
|
+
.removeAttr('id')
|
|
4543
|
+
.removeAttr('style')
|
|
4544
|
+
.removeAttr('spellcheck')
|
|
4545
|
+
.removeAttr('contenteditable')
|
|
4546
|
+
.removeAttr('data-mce-style')
|
|
4547
|
+
;
|
|
4548
|
+
}
|
|
4549
|
+
|
|
4550
|
+
var INITIAL_CONTENT = '<p>Lorem ipsum dolores</p>';
|
|
4551
|
+
|
|
4552
|
+
$.fn.gridEditor.texts.tinymce = function(ge) {
|
|
4553
|
+
return {
|
|
4554
|
+
labelKey: 'text.tinymce',
|
|
4555
|
+
initialContent: INITIAL_CONTENT,
|
|
4556
|
+
missingKey: 'error.tinymce_missing',
|
|
4557
|
+
|
|
4558
|
+
available: function() { return !!window.tinymce; },
|
|
4559
|
+
|
|
4560
|
+
start: function(contentAreas) {
|
|
4561
|
+
var settings = ge.settings;
|
|
4562
|
+
var userConfig = (settings.tinymce && settings.tinymce.config) ? settings.tinymce.config : {};
|
|
4112
4563
|
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
if (contentArea.html() ==
|
|
4118
|
-
|
|
4119
|
-
contentArea.html(' ');
|
|
4564
|
+
contentAreas.each(function() {
|
|
4565
|
+
var contentArea = $(this);
|
|
4566
|
+
if (contentArea.hasClass('active')) { return; }
|
|
4567
|
+
|
|
4568
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
4569
|
+
contentArea.html('');
|
|
4120
4570
|
}
|
|
4121
|
-
|
|
4571
|
+
contentArea.addClass('active');
|
|
4572
|
+
|
|
4573
|
+
var configuration = $.extend({
|
|
4574
|
+
// tinyMCE's own "Upgrade" badge in the menubar. Off by
|
|
4575
|
+
// default because an inline editor here is a column of
|
|
4576
|
+
// someone's page, not tinyMCE's own interface; a host that
|
|
4577
|
+
// wants it back passes promotion: true.
|
|
4578
|
+
promotion: false,
|
|
4579
|
+
}, userConfig, {
|
|
4580
|
+
target: this,
|
|
4581
|
+
inline: true,
|
|
4582
|
+
init_instance_callback: function(editor) {
|
|
4583
|
+
// deinit ran before this init finished, so tear it down again
|
|
4584
|
+
if (contentArea.data('ge-tinymce-pending-remove')) {
|
|
4585
|
+
contentArea.removeData('ge-tinymce-pending-remove');
|
|
4586
|
+
editor.remove();
|
|
4587
|
+
// deinit already ran and cannot clean up after this
|
|
4588
|
+
// late remove(), so do it here instead
|
|
4589
|
+
cleanUp(contentArea);
|
|
4590
|
+
return;
|
|
4591
|
+
}
|
|
4592
|
+
|
|
4593
|
+
contentArea.data('ge-tinymce', editor);
|
|
4594
|
+
|
|
4595
|
+
// The editor rewrote what is inside this content area
|
|
4596
|
+
// while it took it over, so whatever the grid editor
|
|
4597
|
+
// had in there is gone. Saying so lets it put its own
|
|
4598
|
+
// furniture back.
|
|
4599
|
+
ge.textReady(contentArea);
|
|
4600
|
+
|
|
4601
|
+
// Undo and redo rewrite it too, from snapshots that
|
|
4602
|
+
// leave out whatever is marked data-mce-bogus - an
|
|
4603
|
+
// element's drawer among them - so it goes back in
|
|
4604
|
+
// after each of those as well
|
|
4605
|
+
editor.on('Undo Redo', function() {
|
|
4606
|
+
ge.textReady(contentArea);
|
|
4607
|
+
});
|
|
4608
|
+
|
|
4609
|
+
// The inline toolbar is laid out against the element's
|
|
4610
|
+
// geometry at the moment tinyMCE draws it, and an
|
|
4611
|
+
// element that has just appeared - a tab pane, an
|
|
4612
|
+
// accordion body, a column whose width is still
|
|
4613
|
+
// settling - may not have its own width yet. Asking
|
|
4614
|
+
// for the ui again once the browser has laid the frame
|
|
4615
|
+
// out measures it as it now is, instead of leaving a
|
|
4616
|
+
// toolbar wrapped into a narrow column.
|
|
4617
|
+
window.requestAnimationFrame(function() {
|
|
4618
|
+
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
4619
|
+
|
|
4620
|
+
editor.ui.show();
|
|
4621
|
+
});
|
|
4622
|
+
|
|
4623
|
+
// And again whenever the user comes back to this
|
|
4624
|
+
// editor: by then the element may have been resized,
|
|
4625
|
+
// hidden and shown again - a tab switched away from
|
|
4626
|
+
// and back, a column made narrower - and the toolbar
|
|
4627
|
+
// is only ever as right as its last measurement.
|
|
4628
|
+
editor.on('focus', function() {
|
|
4629
|
+
window.requestAnimationFrame(function() {
|
|
4630
|
+
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
4631
|
+
|
|
4632
|
+
editor.ui.show();
|
|
4633
|
+
});
|
|
4634
|
+
});
|
|
4635
|
+
|
|
4636
|
+
// Bring focus to text field
|
|
4637
|
+
editor.focus();
|
|
4638
|
+
|
|
4639
|
+
// Call the original callbacks, if any were passed in the config
|
|
4640
|
+
if (userConfig.init_instance_callback) {
|
|
4641
|
+
userConfig.init_instance_callback.call(this, editor);
|
|
4642
|
+
}
|
|
4643
|
+
// 'oninit' is the pre-6 name, honoured so existing configs keep working
|
|
4644
|
+
if (userConfig.oninit) {
|
|
4645
|
+
userConfig.oninit.call(this, editor);
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
});
|
|
4649
|
+
// We always edit the element we were handed, so a selector in the
|
|
4650
|
+
// user config would only fight with target
|
|
4651
|
+
delete configuration.selector;
|
|
4652
|
+
|
|
4653
|
+
window.tinymce.init(configuration);
|
|
4654
|
+
});
|
|
4655
|
+
},
|
|
4656
|
+
|
|
4657
|
+
stop: function(contentAreas) {
|
|
4658
|
+
contentAreas.filter('.active').each(function() {
|
|
4659
|
+
var contentArea = $(this);
|
|
4660
|
+
var editor = contentArea.data('ge-tinymce');
|
|
4661
|
+
|
|
4662
|
+
if (editor) {
|
|
4663
|
+
contentArea.removeData('ge-tinymce');
|
|
4664
|
+
editor.remove();
|
|
4665
|
+
} else {
|
|
4666
|
+
// tinymce.init() is asynchronous, so the editor may not exist
|
|
4667
|
+
// yet. Leave a note for init_instance_callback to remove it.
|
|
4668
|
+
contentArea.data('ge-tinymce-pending-remove', true);
|
|
4669
|
+
}
|
|
4670
|
+
|
|
4671
|
+
cleanUp(contentArea);
|
|
4672
|
+
});
|
|
4673
|
+
},
|
|
4674
|
+
};
|
|
4675
|
+
};
|
|
4676
|
+
})(jQuery);
|
|
4677
|
+
|
|
4678
|
+
/**
|
|
4679
|
+
* CKEditor for grid-editor's content areas.
|
|
4680
|
+
*
|
|
4681
|
+
* A text editor plugin: load this file after the editor, and CKEditor 4
|
|
4682
|
+
* after or before it, and content_types: ['ckeditor'] edits each content area
|
|
4683
|
+
* with an inline CKEditor. What it can ask the editor for is the handle its
|
|
4684
|
+
* factory is called with, described in docs/plugins.md.
|
|
4685
|
+
*
|
|
4686
|
+
* <script src="ckeditor/ckeditor.js"></script>
|
|
4687
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
4688
|
+
* <script src="dist/plugins/grideditor.ckeditor.min.js"></script>
|
|
4689
|
+
*
|
|
4690
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
4691
|
+
*/
|
|
4692
|
+
(function($) {
|
|
4693
|
+
|
|
4694
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
4695
|
+
'text.ckeditor': 'CKEditor',
|
|
4696
|
+
});
|
|
4697
|
+
|
|
4698
|
+
var INITIAL_CONTENT = '<p>Lorem initius... </p>';
|
|
4699
|
+
|
|
4700
|
+
$.fn.gridEditor.texts.ckeditor = function(ge) {
|
|
4701
|
+
|
|
4702
|
+
/**
|
|
4703
|
+
* The instance editing this content area. Kept in jQuery data when it
|
|
4704
|
+
* is made, and looked for among CKEditor's own as a fallback, since
|
|
4705
|
+
* an instance made by another version of this file has no data.
|
|
4706
|
+
*/
|
|
4707
|
+
function instanceOf(contentArea) {
|
|
4708
|
+
var kept = contentArea.data('ge-ckeditor');
|
|
4709
|
+
if (kept) { return kept; }
|
|
4710
|
+
|
|
4711
|
+
var found = null;
|
|
4712
|
+
$.each(window.CKEDITOR.instances, function(name, instance) {
|
|
4713
|
+
if (instance.element && instance.element.$ === contentArea[0]) { found = instance; }
|
|
4714
|
+
});
|
|
4715
|
+
|
|
4716
|
+
return found;
|
|
4717
|
+
}
|
|
4718
|
+
|
|
4719
|
+
return {
|
|
4720
|
+
labelKey: 'text.ckeditor',
|
|
4721
|
+
initialContent: INITIAL_CONTENT,
|
|
4722
|
+
missingKey: 'error.ckeditor_missing',
|
|
4723
|
+
|
|
4724
|
+
available: function() { return !!window.CKEDITOR; },
|
|
4725
|
+
|
|
4726
|
+
start: function(contentAreas) {
|
|
4727
|
+
var settings = ge.settings;
|
|
4728
|
+
|
|
4729
|
+
contentAreas.each(function() {
|
|
4730
|
+
var contentArea = $(this);
|
|
4731
|
+
if (contentArea.hasClass('active')) { return; }
|
|
4732
|
+
|
|
4733
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
4734
|
+
// CKEditor kills this ' ' creating a non usable box :/
|
|
4735
|
+
contentArea.html(' ');
|
|
4736
|
+
}
|
|
4737
|
+
|
|
4122
4738
|
// Add the .attr('contenteditable',''true') or CKEditor loads readonly
|
|
4123
4739
|
contentArea.addClass('active').attr('contenteditable', 'true');
|
|
4124
|
-
|
|
4740
|
+
|
|
4125
4741
|
var configuration = $.extend(
|
|
4126
4742
|
{},
|
|
4127
|
-
(settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
|
|
4743
|
+
(settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
|
|
4128
4744
|
{
|
|
4129
4745
|
// Focus editor on creation
|
|
4130
4746
|
on: {
|
|
@@ -4143,56 +4759,86 @@ $.fn.gridEditor.locales = {
|
|
|
4143
4759
|
// The editor owns what is inside the
|
|
4144
4760
|
// content area now, so the grid editor is
|
|
4145
4761
|
// told to put its own furniture back
|
|
4146
|
-
|
|
4762
|
+
ge.textReady(contentArea);
|
|
4147
4763
|
|
|
4148
4764
|
instance.focus();
|
|
4149
4765
|
}
|
|
4150
4766
|
}
|
|
4151
4767
|
}
|
|
4152
4768
|
);
|
|
4153
|
-
var instance = CKEDITOR.inline(contentArea.get(0), configuration);
|
|
4154
|
-
|
|
4155
|
-
});
|
|
4156
|
-
},
|
|
4157
|
-
|
|
4158
|
-
deinit: function(settings, contentAreas) {
|
|
4159
|
-
contentAreas.filter('.active').each(function() {
|
|
4160
|
-
var contentArea = $(this);
|
|
4161
|
-
|
|
4162
|
-
// Destroy all CKEditor instances
|
|
4163
|
-
$.each(CKEDITOR.instances, function(_, instance) {
|
|
4164
|
-
instance.destroy();
|
|
4769
|
+
var instance = window.CKEDITOR.inline(contentArea.get(0), configuration);
|
|
4770
|
+
contentArea.data('ge-ckeditor', instance);
|
|
4165
4771
|
});
|
|
4772
|
+
},
|
|
4166
4773
|
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
.
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4774
|
+
stop: function(contentAreas) {
|
|
4775
|
+
contentAreas.filter('.active').each(function() {
|
|
4776
|
+
var contentArea = $(this);
|
|
4777
|
+
|
|
4778
|
+
// This content area's instance, and no other: up to 5.x
|
|
4779
|
+
// closing one content area destroyed every CKEditor on
|
|
4780
|
+
// the page, other editors' and the host's own included
|
|
4781
|
+
var instance = window.CKEDITOR ? instanceOf(contentArea) : null;
|
|
4782
|
+
if (instance) { instance.destroy(); }
|
|
4783
|
+
contentArea.removeData('ge-ckeditor');
|
|
4784
|
+
|
|
4785
|
+
// Cleanup
|
|
4786
|
+
contentArea
|
|
4787
|
+
.removeClass('active cke_focus')
|
|
4788
|
+
.removeAttr('id')
|
|
4789
|
+
.removeAttr('style')
|
|
4790
|
+
.removeAttr('spellcheck')
|
|
4791
|
+
.removeAttr('contenteditable')
|
|
4792
|
+
;
|
|
4793
|
+
});
|
|
4794
|
+
},
|
|
4795
|
+
};
|
|
4179
4796
|
};
|
|
4180
4797
|
})(jQuery);
|
|
4798
|
+
|
|
4799
|
+
/**
|
|
4800
|
+
* Summernote for grid-editor's content areas.
|
|
4801
|
+
*
|
|
4802
|
+
* A text editor plugin: load this file after the editor, and summernote
|
|
4803
|
+
* after or before it, and content_types: ['summernote'] edits each content
|
|
4804
|
+
* area with summernote in air mode. What it can ask the editor for is the
|
|
4805
|
+
* handle its factory is called with, described in docs/plugins.md.
|
|
4806
|
+
*
|
|
4807
|
+
* <script src="summernote/summernote-bs5.min.js"></script>
|
|
4808
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
4809
|
+
* <script src="dist/plugins/grideditor.summernote.min.js"></script>
|
|
4810
|
+
*
|
|
4811
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
4812
|
+
*/
|
|
4181
4813
|
(function($) {
|
|
4182
4814
|
|
|
4183
|
-
$.fn.gridEditor.
|
|
4815
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
4816
|
+
'text.summernote': 'Summernote',
|
|
4817
|
+
});
|
|
4184
4818
|
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
if (!jQuery().summernote) {
|
|
4188
|
-
console.error($.fn.gridEditor.t(settings, 'error.summernote_missing'));
|
|
4189
|
-
}
|
|
4819
|
+
var INITIAL_CONTENT = '<p>Lorem ipsum dolores</p>';
|
|
4190
4820
|
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4821
|
+
$.fn.gridEditor.texts.summernote = function(ge) {
|
|
4822
|
+
return {
|
|
4823
|
+
labelKey: 'text.summernote',
|
|
4824
|
+
initialContent: INITIAL_CONTENT,
|
|
4825
|
+
missingKey: 'error.summernote_missing',
|
|
4826
|
+
|
|
4827
|
+
available: function() { return !!$.fn.summernote; },
|
|
4828
|
+
|
|
4829
|
+
start: function(contentAreas) {
|
|
4830
|
+
var settings = ge.settings;
|
|
4831
|
+
|
|
4832
|
+
// Summernote 0.9.1 calls $.now(), which jQuery 4 removed, and
|
|
4833
|
+
// cannot open without it. Given back only where it is missing,
|
|
4834
|
+
// and only once summernote is actually used.
|
|
4835
|
+
if (!$.now) { $.now = Date.now; }
|
|
4836
|
+
|
|
4837
|
+
contentAreas.each(function() {
|
|
4838
|
+
var contentArea = $(this);
|
|
4839
|
+
if (contentArea.hasClass('active')) { return; }
|
|
4840
|
+
|
|
4841
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
4196
4842
|
contentArea.html('');
|
|
4197
4843
|
}
|
|
4198
4844
|
contentArea.addClass('active');
|
|
@@ -4207,7 +4853,7 @@ $.fn.gridEditor.locales = {
|
|
|
4207
4853
|
// Focus editor on creation
|
|
4208
4854
|
callbacks: {
|
|
4209
4855
|
onInit: function() {
|
|
4210
|
-
|
|
4856
|
+
|
|
4211
4857
|
// Call original oninit function, if one was passed in the config
|
|
4212
4858
|
var callback;
|
|
4213
4859
|
try {
|
|
@@ -4222,175 +4868,44 @@ $.fn.gridEditor.locales = {
|
|
|
4222
4868
|
// The editor owns what is inside the
|
|
4223
4869
|
// content area now, so the grid editor is
|
|
4224
4870
|
// told to put its own furniture back
|
|
4225
|
-
|
|
4226
|
-
|
|
4871
|
+
ge.textReady(contentArea);
|
|
4872
|
+
|
|
4227
4873
|
contentArea.summernote('focus');
|
|
4228
4874
|
}
|
|
4229
4875
|
}
|
|
4230
4876
|
}
|
|
4231
4877
|
);
|
|
4232
4878
|
contentArea.summernote(configuration);
|
|
4233
|
-
}
|
|
4234
|
-
}
|
|
4235
|
-
},
|
|
4236
|
-
|
|
4237
|
-
deinit: function(settings, contentAreas) {
|
|
4238
|
-
contentAreas.filter('.active').each(function() {
|
|
4239
|
-
var contentArea = $(this);
|
|
4240
|
-
contentArea.summernote('destroy');
|
|
4241
|
-
contentArea
|
|
4242
|
-
.removeClass('active')
|
|
4243
|
-
.removeAttr('id')
|
|
4244
|
-
.removeAttr('style')
|
|
4245
|
-
.removeAttr('spellcheck')
|
|
4246
|
-
;
|
|
4247
|
-
});
|
|
4248
|
-
},
|
|
4879
|
+
});
|
|
4880
|
+
},
|
|
4249
4881
|
|
|
4250
|
-
|
|
4882
|
+
stop: function(contentAreas) {
|
|
4883
|
+
contentAreas.filter('.active').each(function() {
|
|
4884
|
+
var contentArea = $(this);
|
|
4885
|
+
contentArea.summernote('destroy');
|
|
4886
|
+
contentArea
|
|
4887
|
+
.removeClass('active')
|
|
4888
|
+
.removeAttr('id')
|
|
4889
|
+
.removeAttr('style')
|
|
4890
|
+
.removeAttr('spellcheck')
|
|
4891
|
+
;
|
|
4892
|
+
});
|
|
4893
|
+
},
|
|
4894
|
+
};
|
|
4251
4895
|
};
|
|
4252
4896
|
})(jQuery);
|
|
4253
4897
|
|
|
4898
|
+
/**
|
|
4899
|
+
* Up to 6.0 the main bundle carries a copy of each text editor plugin, so a
|
|
4900
|
+
* page that loaded only the editor keeps the editor it had. This marks those
|
|
4901
|
+
* copies, and the editor warns once when a content area is edited with one:
|
|
4902
|
+
* 6.0 leaves them out. Loaded on its own, a plugin's file registers itself
|
|
4903
|
+
* again, unmarked, and is the one used.
|
|
4904
|
+
*
|
|
4905
|
+
* Only ever concatenated after the plugins it marks, never built on its own.
|
|
4906
|
+
*/
|
|
4254
4907
|
(function($) {
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
// to keep the grid editor's own class and tinyMCE's leftovers off the element.
|
|
4259
|
-
function cleanUp(contentArea) {
|
|
4260
|
-
contentArea
|
|
4261
|
-
.removeClass('active')
|
|
4262
|
-
.removeClass('ge-rte-active')
|
|
4263
|
-
.removeAttr('id')
|
|
4264
|
-
.removeAttr('style')
|
|
4265
|
-
.removeAttr('spellcheck')
|
|
4266
|
-
.removeAttr('contenteditable')
|
|
4267
|
-
.removeAttr('data-mce-style')
|
|
4268
|
-
;
|
|
4269
|
-
}
|
|
4270
|
-
|
|
4271
|
-
$.fn.gridEditor.RTEs.tinymce = {
|
|
4272
|
-
|
|
4273
|
-
init: function(settings, contentAreas) {
|
|
4274
|
-
|
|
4275
|
-
if (!window.tinymce) {
|
|
4276
|
-
console.error($.fn.gridEditor.t(settings, 'error.tinymce_missing'));
|
|
4277
|
-
return;
|
|
4278
|
-
}
|
|
4279
|
-
|
|
4280
|
-
var self = this;
|
|
4281
|
-
var userConfig = (settings.tinymce && settings.tinymce.config) ? settings.tinymce.config : {};
|
|
4282
|
-
|
|
4283
|
-
contentAreas.each(function() {
|
|
4284
|
-
var contentArea = $(this);
|
|
4285
|
-
if (contentArea.hasClass('active')) { return; }
|
|
4286
|
-
|
|
4287
|
-
if (contentArea.html() == self.initialContent) {
|
|
4288
|
-
contentArea.html('');
|
|
4289
|
-
}
|
|
4290
|
-
contentArea.addClass('active');
|
|
4291
|
-
|
|
4292
|
-
var configuration = $.extend({
|
|
4293
|
-
// tinyMCE's own "Upgrade" badge in the menubar. Off by
|
|
4294
|
-
// default because an inline editor here is a column of
|
|
4295
|
-
// someone's page, not tinyMCE's own interface; a host that
|
|
4296
|
-
// wants it back passes promotion: true.
|
|
4297
|
-
promotion: false,
|
|
4298
|
-
}, userConfig, {
|
|
4299
|
-
target: this,
|
|
4300
|
-
inline: true,
|
|
4301
|
-
init_instance_callback: function(editor) {
|
|
4302
|
-
// deinit ran before this init finished, so tear it down again
|
|
4303
|
-
if (contentArea.data('ge-tinymce-pending-remove')) {
|
|
4304
|
-
contentArea.removeData('ge-tinymce-pending-remove');
|
|
4305
|
-
editor.remove();
|
|
4306
|
-
// deinit already ran and cannot clean up after this
|
|
4307
|
-
// late remove(), so do it here instead
|
|
4308
|
-
cleanUp(contentArea);
|
|
4309
|
-
return;
|
|
4310
|
-
}
|
|
4311
|
-
|
|
4312
|
-
contentArea.data('ge-tinymce', editor);
|
|
4313
|
-
|
|
4314
|
-
// The editor rewrote what is inside this content area
|
|
4315
|
-
// while it took it over, so whatever the grid editor
|
|
4316
|
-
// had in there is gone. Saying so lets it put its own
|
|
4317
|
-
// furniture back (see RTE_READY in the core).
|
|
4318
|
-
contentArea.trigger('ge-rte-ready');
|
|
4319
|
-
|
|
4320
|
-
// Undo and redo rewrite it too, from snapshots that
|
|
4321
|
-
// leave out whatever is marked data-mce-bogus - an
|
|
4322
|
-
// element's drawer among them - so it goes back in
|
|
4323
|
-
// after each of those as well
|
|
4324
|
-
editor.on('Undo Redo', function() {
|
|
4325
|
-
contentArea.trigger('ge-rte-ready');
|
|
4326
|
-
});
|
|
4327
|
-
|
|
4328
|
-
// The inline toolbar is laid out against the element's
|
|
4329
|
-
// geometry at the moment tinyMCE draws it, and an
|
|
4330
|
-
// element that has just appeared - a tab pane, an
|
|
4331
|
-
// accordion body, a column whose width is still
|
|
4332
|
-
// settling - may not have its own width yet. Asking
|
|
4333
|
-
// for the ui again once the browser has laid the frame
|
|
4334
|
-
// out measures it as it now is, instead of leaving a
|
|
4335
|
-
// toolbar wrapped into a narrow column.
|
|
4336
|
-
window.requestAnimationFrame(function() {
|
|
4337
|
-
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
4338
|
-
|
|
4339
|
-
editor.ui.show();
|
|
4340
|
-
});
|
|
4341
|
-
|
|
4342
|
-
// And again whenever the user comes back to this
|
|
4343
|
-
// editor: by then the element may have been resized,
|
|
4344
|
-
// hidden and shown again - a tab switched away from
|
|
4345
|
-
// and back, a column made narrower - and the toolbar
|
|
4346
|
-
// is only ever as right as its last measurement.
|
|
4347
|
-
editor.on('focus', function() {
|
|
4348
|
-
window.requestAnimationFrame(function() {
|
|
4349
|
-
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
4350
|
-
|
|
4351
|
-
editor.ui.show();
|
|
4352
|
-
});
|
|
4353
|
-
});
|
|
4354
|
-
|
|
4355
|
-
// Bring focus to text field
|
|
4356
|
-
editor.focus();
|
|
4357
|
-
|
|
4358
|
-
// Call the original callbacks, if any were passed in the config
|
|
4359
|
-
if (userConfig.init_instance_callback) {
|
|
4360
|
-
userConfig.init_instance_callback.call(this, editor);
|
|
4361
|
-
}
|
|
4362
|
-
// 'oninit' is the pre-6 name, honoured so existing configs keep working
|
|
4363
|
-
if (userConfig.oninit) {
|
|
4364
|
-
userConfig.oninit.call(this, editor);
|
|
4365
|
-
}
|
|
4366
|
-
}
|
|
4367
|
-
});
|
|
4368
|
-
// We always edit the element we were handed, so a selector in the
|
|
4369
|
-
// user config would only fight with target
|
|
4370
|
-
delete configuration.selector;
|
|
4371
|
-
|
|
4372
|
-
window.tinymce.init(configuration);
|
|
4373
|
-
});
|
|
4374
|
-
},
|
|
4375
|
-
|
|
4376
|
-
deinit: function(settings, contentAreas) {
|
|
4377
|
-
contentAreas.filter('.active').each(function() {
|
|
4378
|
-
var contentArea = $(this);
|
|
4379
|
-
var editor = contentArea.data('ge-tinymce');
|
|
4380
|
-
|
|
4381
|
-
if (editor) {
|
|
4382
|
-
contentArea.removeData('ge-tinymce');
|
|
4383
|
-
editor.remove();
|
|
4384
|
-
} else {
|
|
4385
|
-
// tinymce.init() is asynchronous, so the editor may not exist
|
|
4386
|
-
// yet. Leave a note for init_instance_callback to remove it.
|
|
4387
|
-
contentArea.data('ge-tinymce-pending-remove', true);
|
|
4388
|
-
}
|
|
4389
|
-
|
|
4390
|
-
cleanUp(contentArea);
|
|
4391
|
-
});
|
|
4392
|
-
},
|
|
4393
|
-
|
|
4394
|
-
initialContent: '<p>Lorem ipsum dolores</p>',
|
|
4395
|
-
};
|
|
4908
|
+
['tinymce', 'ckeditor', 'summernote'].forEach(function(type) {
|
|
4909
|
+
if ($.fn.gridEditor.texts[type]) { $.fn.gridEditor.texts[type].bundled = true; }
|
|
4910
|
+
});
|
|
4396
4911
|
})(jQuery);
|