@themarioga/grid-editor 6.0.0-beta.3 → 6.0.0-beta.4
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 +3 -1
- package/CHANGELOG.md +50 -1
- package/README.md +16 -5
- package/UPGRADING.md +36 -7
- package/dist/grideditor.css +14 -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 +303 -385
- package/dist/jquery.grideditor.min.js +1 -1
- package/dist/jquery.grideditor.min.js.map +1 -1
- package/dist/locales/grideditor.es.js +3 -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 +397 -3
- package/dist/plugins/grideditor.ckeditor.min.js +1 -1
- package/dist/plugins/grideditor.ckeditor.min.js.map +1 -1
- package/dist/plugins/grideditor.summernote.js +397 -3
- package/dist/plugins/grideditor.summernote.min.js +1 -1
- package/dist/plugins/grideditor.summernote.min.js.map +1 -1
- package/dist/plugins/grideditor.tinymce.js +397 -3
- package/dist/plugins/grideditor.tinymce.min.js +1 -1
- package/dist/plugins/grideditor.tinymce.min.js.map +1 -1
- package/dist/plugins/grideditor.visibility.js +1 -1
- package/dist/plugins/grideditor.visibility.min.js +1 -1
- package/dist/plugins/grideditor.visibility.min.js.map +1 -1
- package/docs/events.md +11 -2
- package/docs/locale-keys.md +12 -3
- package/docs/plugins.md +109 -46
- package/example/custom_editor.html +193 -0
- package/example/index.html +8 -0
- package/example/wrap_content.html +5 -3
- package/package.json +1 -1
- package/src/js/jquery.grideditor.js +303 -385
- package/src/js/locales/grideditor.es.js +3 -0
- package/src/js/plugins/grideditor.ckeditor.js +7 -3
- package/src/js/plugins/grideditor.summernote.js +7 -3
- package/src/js/plugins/grideditor.tinymce.js +7 -3
- package/src/js/plugins/grideditor.visibility.js +1 -1
- package/src/js/text/grideditor.text.js +389 -0
- package/src/less/grideditor.less +17 -0
|
@@ -339,8 +339,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
339
339
|
'toolbar_drag' : 'auto', // Drag the toolbar's buttons onto the canvas. 'auto' follows drag_handle
|
|
340
340
|
'element_tools' : [], // Host tools on element drawers, same shape as row_tools
|
|
341
341
|
'element_classes' : [], // Preset class toggles on an element's settings panel
|
|
342
|
-
|
|
343
|
-
|
|
342
|
+
// content_types, text_tools and text_classes are the text editor
|
|
343
|
+
// plugins' settings since 6.0: see grideditor.text.js
|
|
344
344
|
'container_classes' : [], // The same, on a container's panel
|
|
345
345
|
'pane_classes' : [], // And on a tab's or an accordion item's
|
|
346
346
|
'container_tools' : [], // Host tools on container drawers
|
|
@@ -351,7 +351,6 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
351
351
|
'utilities' : {}, // Options for the utility plugins, by plugin name
|
|
352
352
|
'elements' : NESTED_SETTINGS.elements, // Element level controls, below the column
|
|
353
353
|
'custom_filter' : '',
|
|
354
|
-
'content_types' : ['tinymce'],
|
|
355
354
|
'valid_col_sizes' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'equal', 'auto'],
|
|
356
355
|
'valid_col_offsets' : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
357
356
|
'add_column' : NESTED_SETTINGS.add_column, // The add column tool
|
|
@@ -836,19 +835,21 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
836
835
|
if (node.hasClass('row')) { return 'row'; }
|
|
837
836
|
if (node.hasClass('column')) { return 'column'; }
|
|
838
837
|
if (node.hasClass('ge-element')) { return 'element'; }
|
|
839
|
-
|
|
838
|
+
// A content area is a text when an editor's type is on it, and the
|
|
839
|
+
// host's plain content when there is none
|
|
840
|
+
if (node.hasClass('ge-text-block')) { node = node.children('.ge-content'); }
|
|
841
|
+
if (node.hasClass('ge-content')) { return node.attr('data-ge-content-type') ? 'text' : 'plain'; }
|
|
840
842
|
return 'node';
|
|
841
843
|
}
|
|
842
844
|
|
|
843
845
|
// Copy html to sourceElement if a source textarea is given
|
|
844
846
|
if (settings.source_textarea) {
|
|
845
847
|
var sourceHtml = $(settings.source_textarea).val();
|
|
848
|
+
// Html with no grid in it goes into a row and a full width column
|
|
849
|
+
// of its own, where init wraps it as the host's plain content
|
|
846
850
|
if (sourceHtml.length > 0 && $('<div>' + sourceHtml + '</div>').find('.row').addBack('.row').length == 0) {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
sourceColumn.find('.ge-content').html(sourceHtml);
|
|
850
|
-
sourceHtml = sourceColumn.html();
|
|
851
|
-
}
|
|
851
|
+
sourceHtml = '<div class="row"><div class="col-lg-12">' + sourceHtml + '</div></div>';
|
|
852
|
+
}
|
|
852
853
|
baseElem.html(sourceHtml);
|
|
853
854
|
}
|
|
854
855
|
|
|
@@ -871,8 +872,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
871
872
|
// Make controls fixed on scroll
|
|
872
873
|
$(window).on('scroll', onScroll);
|
|
873
874
|
|
|
874
|
-
/*
|
|
875
|
-
canvas.on('click', '.ge-content',
|
|
875
|
+
/* A click on the host's plain content offers to make it a text */
|
|
876
|
+
canvas.on('click', '.ge-content', onContentClick);
|
|
876
877
|
|
|
877
878
|
/* A trigger is often a link, and a link still navigates even
|
|
878
879
|
with its Bootstrap attributes suspended */
|
|
@@ -884,12 +885,6 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
884
885
|
// which costs the element drawers inside it. The integrations say
|
|
885
886
|
// when their editor is ready, and the drawers go back in.
|
|
886
887
|
canvas.on('ge-rte-ready', '.ge-content', function() {
|
|
887
|
-
// The first time only: an undo says ready again, and by then
|
|
888
|
-
// the host may have changed the content area itself
|
|
889
|
-
if ($(this).data('ge-text-before') && !$(this).data('ge-text-ready')) {
|
|
890
|
-
$(this).data('ge-text-ready', attributesOf(this));
|
|
891
|
-
}
|
|
892
|
-
|
|
893
888
|
plugins('onContentReady', $(this));
|
|
894
889
|
refreshPreviews($(this));
|
|
895
890
|
});
|
|
@@ -947,50 +942,16 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
947
942
|
|
|
948
943
|
addContainerGroup.appendTo(wrapper);
|
|
949
944
|
|
|
950
|
-
// A text block of each editor offered. Like a container, it goes
|
|
951
|
-
// into a row of its own when clicked, or where it is dropped
|
|
952
|
-
var texts = offeredTexts();
|
|
953
|
-
texts.forEach(function(type) {
|
|
954
|
-
var label = texts.length > 1 ? t('text.add_type', { editor: textLabel(type) }) : t('text.add');
|
|
955
|
-
|
|
956
|
-
$('<a class="btn btn-sm btn-primary ge-add-container ge-add-text-button" />')
|
|
957
|
-
.attr('title', label)
|
|
958
|
-
.attr('data-ge-toolbar', 'text')
|
|
959
|
-
.attr('data-ge-text', type)
|
|
960
|
-
.append('<i class="bi bi-plus"></i>')
|
|
961
|
-
.append($('<span />').text(label))
|
|
962
|
-
.on('click', function() {
|
|
963
|
-
var row = createRow();
|
|
964
|
-
var block = makeText(type);
|
|
965
|
-
createColumn(MAX_COL_SIZE).appendTo(row).find('> .ge-content').replaceWith(block);
|
|
966
|
-
|
|
967
|
-
var added = addNode('text', block, function() {
|
|
968
|
-
row.appendTo(canvas);
|
|
969
|
-
}, { parent: canvas, source: 'tool' });
|
|
970
|
-
|
|
971
|
-
if (added && row[0].scrollIntoView) {
|
|
972
|
-
row[0].scrollIntoView({behavior: 'smooth'});
|
|
973
|
-
}
|
|
974
|
-
})
|
|
975
|
-
.appendTo(addContainerGroup)
|
|
976
|
-
;
|
|
977
|
-
});
|
|
978
|
-
|
|
979
945
|
// A container starts in a row of its own, the way the add row
|
|
980
946
|
// buttons next to these ones do
|
|
981
947
|
$.each(CONTAINERS, function(type, definition) {
|
|
982
|
-
$('<a class="btn btn-sm btn-primary ge-add-container" />')
|
|
983
|
-
.attr('title', t(definition.labelKey))
|
|
948
|
+
labelButton($('<a class="btn btn-sm btn-primary ge-add-container" />'), t(definition.labelKey), definition.iconClass)
|
|
984
949
|
.attr('data-ge-toolbar', 'container')
|
|
985
950
|
.attr('data-ge-container-type', type)
|
|
986
|
-
.append('<i class="bi bi-plus"></i>')
|
|
987
|
-
.append($('<span />').text(t(definition.labelKey)))
|
|
988
951
|
.on('click', function() {
|
|
989
952
|
var row = createRow();
|
|
990
953
|
var column = createColumn(MAX_COL_SIZE).appendTo(row);
|
|
991
|
-
var container = definition.create({});
|
|
992
|
-
|
|
993
|
-
column.find('> .ge-content').replaceWith(container);
|
|
954
|
+
var container = definition.create({}).appendTo(column);
|
|
994
955
|
|
|
995
956
|
addNode(type, container, function() {
|
|
996
957
|
row.appendTo(canvas);
|
|
@@ -1093,25 +1054,49 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1093
1054
|
makeToolbarDraggable();
|
|
1094
1055
|
}
|
|
1095
1056
|
|
|
1096
|
-
/**
|
|
1057
|
+
/**
|
|
1058
|
+
* A toolbar button's face: the plugin's icon alone when it has one,
|
|
1059
|
+
* with its label as the title, or a plus and the label otherwise.
|
|
1060
|
+
*/
|
|
1061
|
+
function labelButton(button, label, iconClass) {
|
|
1062
|
+
button.attr('title', label);
|
|
1063
|
+
|
|
1064
|
+
if (iconClass) { return button.append($('<i />').addClass(iconClass)); }
|
|
1065
|
+
|
|
1066
|
+
return button
|
|
1067
|
+
.append('<i class="bi bi-plus"></i>')
|
|
1068
|
+
.append($('<span />').text(label))
|
|
1069
|
+
;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/** A feature plugin's toolbar button. At the end it is always an icon, `bi bi-plus` if it has none of its own. */
|
|
1097
1073
|
function featureButton(name, item, index) {
|
|
1098
|
-
var
|
|
1099
|
-
|
|
1074
|
+
var iconClass = item.iconClass || (item.align === 'end' ? 'bi bi-plus' : null);
|
|
1075
|
+
// A label of its own, worked out when the toolbar is built - and
|
|
1076
|
+
// built again by setLocale - or the string its labelKey names
|
|
1077
|
+
var label = typeof item.label === 'function' ? item.label() : (item.label || t(item.labelKey));
|
|
1078
|
+
var button = labelButton($('<a class="btn btn-sm btn-primary ge-add-container ge-add-feature" />'), label, iconClass)
|
|
1079
|
+
.addClass(item.className || '')
|
|
1100
1080
|
.attr('data-ge-toolbar', 'feature')
|
|
1101
1081
|
.attr('data-ge-feature', name)
|
|
1102
1082
|
.attr('data-ge-item', index)
|
|
1103
|
-
.append($('<i />').addClass(item.iconClass || 'bi bi-plus'))
|
|
1104
1083
|
.on('click', function() {
|
|
1105
1084
|
var made = item.create();
|
|
1106
1085
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1086
|
+
// One that belongs in a column brings a row and a column
|
|
1087
|
+
// of its own, the way a container does
|
|
1088
|
+
var placed = item.inColumn ? inRowOfItsOwn(made) : made;
|
|
1089
|
+
|
|
1090
|
+
var added = addNode(item.kind, made, function() {
|
|
1091
|
+
placed.appendTo(canvas);
|
|
1109
1092
|
}, { parent: canvas, source: item.source || 'tool' });
|
|
1093
|
+
|
|
1094
|
+
if (added && item.inColumn && placed[0].scrollIntoView) {
|
|
1095
|
+
placed[0].scrollIntoView({behavior: 'smooth'});
|
|
1096
|
+
}
|
|
1110
1097
|
})
|
|
1111
1098
|
;
|
|
1112
1099
|
|
|
1113
|
-
if (item.align !== 'end') { button.append($('<span />').text(t(item.labelKey))); }
|
|
1114
|
-
|
|
1115
1100
|
return button;
|
|
1116
1101
|
}
|
|
1117
1102
|
|
|
@@ -1250,8 +1235,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1250
1235
|
function insertFeatureFromToolbar(button, where) {
|
|
1251
1236
|
var item = FEATURES[button.attr('data-ge-feature')].toolbar[parseInt(button.attr('data-ge-item'), 10)];
|
|
1252
1237
|
var made = item.create();
|
|
1238
|
+
var placed = made;
|
|
1253
1239
|
|
|
1254
|
-
if (
|
|
1240
|
+
if (item.inColumn) {
|
|
1241
|
+
// Where it lands in a column, or in a row and a column of its
|
|
1242
|
+
// own anywhere else
|
|
1243
|
+
if (!where.region.is('.column')) { placed = inRowOfItsOwn(made); }
|
|
1244
|
+
} else if (!acceptsBlock(where.region, made)) {
|
|
1255
1245
|
var top = where.region.parentsUntil(canvas).addBack().first();
|
|
1256
1246
|
where = { region: canvas, before: top.length ? top.next() : null };
|
|
1257
1247
|
if (where.before && !where.before.length) { where.before = null; }
|
|
@@ -1259,33 +1249,19 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1259
1249
|
|
|
1260
1250
|
return addNode(item.kind, made, function() {
|
|
1261
1251
|
if (where.before) {
|
|
1262
|
-
|
|
1252
|
+
placed.insertBefore(where.before);
|
|
1263
1253
|
} else {
|
|
1264
|
-
|
|
1254
|
+
placed.appendTo(where.region);
|
|
1265
1255
|
}
|
|
1266
1256
|
}, { parent: where.region, source: item.source || 'dragdrop' });
|
|
1267
1257
|
}
|
|
1268
1258
|
|
|
1269
|
-
/**
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
function insertTextFromToolbar(button, where) {
|
|
1274
|
-
var made = makeText(button.attr('data-ge-text'));
|
|
1275
|
-
var placed = made;
|
|
1276
|
-
|
|
1277
|
-
if (!where.region.is('.column')) {
|
|
1278
|
-
placed = createRow();
|
|
1279
|
-
createColumn(MAX_COL_SIZE).appendTo(placed).find('> .ge-content').replaceWith(made);
|
|
1280
|
-
}
|
|
1259
|
+
/** A detached row with one full width column holding `node`. */
|
|
1260
|
+
function inRowOfItsOwn(node) {
|
|
1261
|
+
var row = createRow();
|
|
1262
|
+
createColumn(MAX_COL_SIZE).appendTo(row).append(node);
|
|
1281
1263
|
|
|
1282
|
-
return
|
|
1283
|
-
if (where.before) {
|
|
1284
|
-
placed.insertBefore(where.before);
|
|
1285
|
-
} else {
|
|
1286
|
-
placed.appendTo(where.region);
|
|
1287
|
-
}
|
|
1288
|
-
}, { parent: where.region, source: 'dragdrop' });
|
|
1264
|
+
return row;
|
|
1289
1265
|
}
|
|
1290
1266
|
|
|
1291
1267
|
/** A line where the block would go, following the pointer. */
|
|
@@ -1317,9 +1293,6 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1317
1293
|
if (button.attr('data-ge-toolbar') === 'feature') {
|
|
1318
1294
|
return insertFeatureFromToolbar(button, where);
|
|
1319
1295
|
}
|
|
1320
|
-
if (button.attr('data-ge-toolbar') === 'text') {
|
|
1321
|
-
return insertTextFromToolbar(button, where);
|
|
1322
|
-
}
|
|
1323
1296
|
|
|
1324
1297
|
var container = button.attr('data-ge-toolbar') === 'container';
|
|
1325
1298
|
var type = button.attr('data-ge-container-type');
|
|
@@ -1330,11 +1303,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1330
1303
|
// A container belongs in a column: dropped straight onto the
|
|
1331
1304
|
// canvas it brings a row and a column of its own
|
|
1332
1305
|
var placed = made;
|
|
1333
|
-
if (container && !where.region.is('.column')) {
|
|
1334
|
-
placed = createRow();
|
|
1335
|
-
createColumn(MAX_COL_SIZE).appendTo(placed)
|
|
1336
|
-
.find('> .ge-content').replaceWith(made);
|
|
1337
|
-
}
|
|
1306
|
+
if (container && !where.region.is('.column')) { placed = inRowOfItsOwn(made); }
|
|
1338
1307
|
|
|
1339
1308
|
return addNode(container ? type : 'row', made, function() {
|
|
1340
1309
|
if (where.before) {
|
|
@@ -1461,30 +1430,153 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1461
1430
|
}
|
|
1462
1431
|
}
|
|
1463
1432
|
|
|
1464
|
-
|
|
1465
|
-
|
|
1433
|
+
/**
|
|
1434
|
+
* A click on the host's plain content makes it a text: of the one
|
|
1435
|
+
* editor offered, or of the one chosen when there are several. What
|
|
1436
|
+
* a click on a text does is its editor plugin's business.
|
|
1437
|
+
*/
|
|
1438
|
+
function onContentClick() {
|
|
1439
|
+
var block = $(this);
|
|
1440
|
+
if (block.attr('data-ge-content-type')) { return; }
|
|
1441
|
+
|
|
1442
|
+
// A second click, with the choice still open, withdraws it
|
|
1443
|
+
if (closeSizePicker()) { return; }
|
|
1466
1444
|
|
|
1467
|
-
//
|
|
1468
|
-
//
|
|
1445
|
+
// Content nobody can see - a tab that is not the open one, a
|
|
1446
|
+
// closed accordion item - has no geometry for an editor to lay
|
|
1469
1447
|
// its toolbar out against, and nothing anyone can type into
|
|
1470
|
-
if (
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1448
|
+
if (!block.is(':visible')) { return; }
|
|
1449
|
+
|
|
1450
|
+
var offers = textOffers();
|
|
1451
|
+
if (!offers.length) { return; }
|
|
1452
|
+
|
|
1453
|
+
if (offers.length === 1) {
|
|
1454
|
+
convertPlain(block, offers[0]);
|
|
1455
|
+
} else {
|
|
1456
|
+
openConvertPicker(block, offers);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
/**
|
|
1461
|
+
* Plain content made a text of `offer`'s type, through the convert
|
|
1462
|
+
* events: the type goes on, and the plugin that declared it takes the
|
|
1463
|
+
* block over and opens its editor. Nothing else about the node
|
|
1464
|
+
* changes. False when the library is missing or a handler canceled.
|
|
1465
|
+
*/
|
|
1466
|
+
function convertPlain(block, offer) {
|
|
1467
|
+
// Not converted, so the next click tries again: the library may
|
|
1468
|
+
// be loaded by then
|
|
1469
|
+
if (offer.available && !offer.available()) {
|
|
1470
|
+
if (offer.missingKey) { console.error(t(offer.missingKey)); }
|
|
1471
|
+
return false;
|
|
1483
1472
|
}
|
|
1484
1473
|
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1474
|
+
return operate(function() {
|
|
1475
|
+
var payload = payloadFor('plain', block, { source: 'tool', from: 'plain', to: offer.type });
|
|
1476
|
+
|
|
1477
|
+
if (!emit('before-convert', payload)) { return false; }
|
|
1478
|
+
|
|
1479
|
+
block.addClass('ge-content-type-' + offer.type).attr('data-ge-content-type', offer.type);
|
|
1480
|
+
|
|
1481
|
+
// Its plain drawer goes: the block is the plugin's now, and
|
|
1482
|
+
// the plugin gives it the drawer a text has
|
|
1483
|
+
block.parent('.ge-text-block').removeClass('ge-plain-block').children('.ge-tools-drawer').remove();
|
|
1484
|
+
|
|
1485
|
+
emit('after-convert', payload);
|
|
1486
|
+
offer.edit(block);
|
|
1487
|
+
|
|
1488
|
+
return true;
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
/**
|
|
1493
|
+
* The text types offered, as a strip under the plain content's
|
|
1494
|
+
* drawer, when there is more than one to choose from.
|
|
1495
|
+
*/
|
|
1496
|
+
function openConvertPicker(block, offers) {
|
|
1497
|
+
var textBlock = block.parent('.ge-text-block');
|
|
1498
|
+
|
|
1499
|
+
openPicker(textBlock.children('.ge-tools-drawer'), offers.map(function(offer) {
|
|
1500
|
+
return {
|
|
1501
|
+
label: offer.label,
|
|
1502
|
+
title: t('tool.convert_type', { editor: offer.label }),
|
|
1503
|
+
attributes: { 'data-ge-content-type': offer.type },
|
|
1504
|
+
choose: function() { convertPlain(block, offer); },
|
|
1505
|
+
};
|
|
1506
|
+
}), 'ge-text-picker ge-convert-picker', textBlock);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
/**
|
|
1510
|
+
* A choice as a strip under `anchor` - a tool, or a drawer - one
|
|
1511
|
+
* button per `{ label, title, attributes, choose }`. Leaving `hover`
|
|
1512
|
+
* (the anchor by default) withdraws it, and so does closeSizePicker.
|
|
1513
|
+
*/
|
|
1514
|
+
function openPicker(anchor, choices, className, hover) {
|
|
1515
|
+
closeSizePicker();
|
|
1516
|
+
|
|
1517
|
+
anchor.closest('.ge-tools-drawer').addClass('ge-picker-open');
|
|
1518
|
+
sizePicker = $('<div class="ge-size-picker" />').addClass(className || '').appendTo(anchor);
|
|
1519
|
+
|
|
1520
|
+
choices.forEach(function(choice) {
|
|
1521
|
+
$('<a class="ge-size ge-size-flex" />')
|
|
1522
|
+
.attr(choice.attributes || {})
|
|
1523
|
+
.attr('title', choice.title || choice.label)
|
|
1524
|
+
.text(choice.label)
|
|
1525
|
+
.on('click', function(e) {
|
|
1526
|
+
e.preventDefault();
|
|
1527
|
+
e.stopPropagation();
|
|
1528
|
+
|
|
1529
|
+
closeSizePicker();
|
|
1530
|
+
choice.choose();
|
|
1531
|
+
})
|
|
1532
|
+
.appendTo(sizePicker)
|
|
1533
|
+
;
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
(hover || anchor).one('mouseleave', function() {
|
|
1537
|
+
window.setTimeout(function() {
|
|
1538
|
+
if (sizePicker && !sizePicker.is(':hover')) { closeSizePicker(); }
|
|
1539
|
+
}, 400);
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
/**
|
|
1544
|
+
* Every text type the feature plugins declare, in the order they
|
|
1545
|
+
* were registered: the first plugin to declare a type owns it.
|
|
1546
|
+
*/
|
|
1547
|
+
function textTypes() {
|
|
1548
|
+
var owners = {};
|
|
1549
|
+
var entries = [];
|
|
1550
|
+
|
|
1551
|
+
$.each(FEATURES, function(name, feature) {
|
|
1552
|
+
if (!feature.textTypes) { return; }
|
|
1553
|
+
|
|
1554
|
+
(feature.textTypes() || []).forEach(function(entry) {
|
|
1555
|
+
if (owners[entry.type]) {
|
|
1556
|
+
if (owners[entry.type] !== name) {
|
|
1557
|
+
warnOnceHere('text-type:' + entry.type, 'the "' + name + '" plugin declares the ' +
|
|
1558
|
+
'text type "' + entry.type + '", which the "' + owners[entry.type] +
|
|
1559
|
+
'" plugin already declares: ignored');
|
|
1560
|
+
}
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
owners[entry.type] = name;
|
|
1565
|
+
entries.push(entry);
|
|
1566
|
+
});
|
|
1567
|
+
});
|
|
1568
|
+
|
|
1569
|
+
return entries;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
/** The types plain content can be made, in order: the ones not marked `offered: false`. */
|
|
1573
|
+
function textOffers() {
|
|
1574
|
+
return textTypes().filter(function(entry) { return entry.offered !== false; });
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
/** Whether a plugin declares this text type. */
|
|
1578
|
+
function hasTextOwner(type) {
|
|
1579
|
+
return textTypes().some(function(entry) { return entry.type === type; });
|
|
1488
1580
|
}
|
|
1489
1581
|
|
|
1490
1582
|
function reset() {
|
|
@@ -1521,9 +1613,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1521
1613
|
// Its panel goes home to its drawer first, and both go together
|
|
1522
1614
|
closeSettings();
|
|
1523
1615
|
canvas.removeClass('ge-editing ge-drag-drawer ge-dropping');
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1616
|
+
// Before the drawers and the text blocks come off: an editor
|
|
1617
|
+
// plugin closes its editors here, and finds them where it left them
|
|
1618
|
+
plugins('onBeforeDeinit');
|
|
1527
1619
|
closeSizePicker();
|
|
1528
1620
|
hideDropMarker();
|
|
1529
1621
|
canvas.find('.ge-tools-drawer').remove();
|
|
@@ -1576,7 +1668,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1576
1668
|
mainControls.remove();
|
|
1577
1669
|
htmlTextArea.remove();
|
|
1578
1670
|
$(window).off('scroll', onScroll);
|
|
1579
|
-
canvas.off('click', '.ge-content',
|
|
1671
|
+
canvas.off('click', '.ge-content', onContentClick);
|
|
1580
1672
|
canvas.off('ge-rte-ready', '.ge-content');
|
|
1581
1673
|
canvas.removeData('grideditor');
|
|
1582
1674
|
}
|
|
@@ -1627,30 +1719,27 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1627
1719
|
return !settings.plugins || settings.plugins.indexOf(name) !== -1;
|
|
1628
1720
|
};
|
|
1629
1721
|
|
|
1722
|
+
// What the plugins setting does not choose: the text editors,
|
|
1723
|
+
// which content_types chooses. A page that names its containers
|
|
1724
|
+
// there has named no editor, and still wants the one it uses.
|
|
1725
|
+
var featureWanted = function(name, factory) {
|
|
1726
|
+
return factory.always === true || wanted(name);
|
|
1727
|
+
};
|
|
1728
|
+
|
|
1630
1729
|
$.each($.fn.gridEditor.containers, function(type, factory) {
|
|
1631
1730
|
if (wanted(type)) { CONTAINERS[type] = factory(api); }
|
|
1632
1731
|
});
|
|
1633
1732
|
|
|
1634
1733
|
$.each($.fn.gridEditor.features, function(name, factory) {
|
|
1635
|
-
if (
|
|
1734
|
+
if (featureWanted(name, factory)) { FEATURES[name] = factory(api); }
|
|
1636
1735
|
});
|
|
1637
1736
|
|
|
1638
|
-
//
|
|
1639
|
-
//
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
}
|
|
1644
|
-
|
|
1645
|
-
// 5.x's registry, for an integration a host wrote itself. One the
|
|
1646
|
-
// plugins above already provide is theirs.
|
|
1647
|
-
$.each($.fn.gridEditor.RTEs, function(type, rte) {
|
|
1648
|
-
if (TEXTS[type]) { return; }
|
|
1649
|
-
|
|
1650
|
-
warnOnceHere('rtes:' + type, '$.fn.gridEditor.RTEs is deprecated and will be removed ' +
|
|
1651
|
-
'in 7.0: register "' + type + '" under $.fn.gridEditor.texts, see docs/plugins.md');
|
|
1652
|
-
TEXTS[type] = legacyText(rte);
|
|
1653
|
-
});
|
|
1737
|
+
// 5.x's registry of text editors is gone: an editor of a host's
|
|
1738
|
+
// own is a plugin of its own since 6.0
|
|
1739
|
+
if (!$.isEmptyObject($.fn.gridEditor.RTEs || {})) {
|
|
1740
|
+
warnOnceHere('rtes', '$.fn.gridEditor.RTEs was removed in 6.0 and what is registered there ' +
|
|
1741
|
+
'is ignored: write the editor as a plugin, see docs/plugins.md');
|
|
1742
|
+
}
|
|
1654
1743
|
|
|
1655
1744
|
$.each($.fn.gridEditor.utilities, function(name, factory) {
|
|
1656
1745
|
if (!wanted(name)) { return; }
|
|
@@ -1731,6 +1820,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1731
1820
|
// A text editor has rewritten a content area, so whatever the
|
|
1732
1821
|
// editor and its plugins had put in there goes back in
|
|
1733
1822
|
textReady: function(block) { block.trigger('ge-rte-ready'); },
|
|
1823
|
+
// A choice under a tool, offered by holding it
|
|
1824
|
+
attachPicker: attachPicker,
|
|
1825
|
+
openPicker: openPicker,
|
|
1826
|
+
closePicker: closeSizePicker,
|
|
1734
1827
|
// A node's settings panel, in its drawer or open outside it
|
|
1735
1828
|
detailsOf: detailsOf,
|
|
1736
1829
|
// A node's drawer: its first child, or for a content area the
|
|
@@ -1804,6 +1897,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1804
1897
|
* name the ones it means.
|
|
1805
1898
|
*/
|
|
1806
1899
|
function appliesTo(family, kind) {
|
|
1900
|
+
// The host's plain content reads and previews its utilities as a
|
|
1901
|
+
// text does; with no gear, nothing in its drawer writes them
|
|
1902
|
+
if (kind === 'plain') { kind = 'text'; }
|
|
1807
1903
|
if (family.appliesTo.indexOf(kind) !== -1) { return true; }
|
|
1808
1904
|
|
|
1809
1905
|
return !!CONTAINERS[kind] && family.appliesTo.indexOf('container') !== -1;
|
|
@@ -2273,7 +2369,6 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2273
2369
|
* -------------------------------------------------------------- */
|
|
2274
2370
|
|
|
2275
2371
|
var CONTAINERS = {}; // The container plugins in use, by the type each builds
|
|
2276
|
-
var TEXTS = {}; // The text editor plugins, by the content type each edits
|
|
2277
2372
|
var FEATURES = {}; // The feature plugins in use, by name
|
|
2278
2373
|
var UTILITIES = {}; // The utility plugins in use, by name
|
|
2279
2374
|
var featureMethods = {}; // The methods those features contribute
|
|
@@ -2724,22 +2819,6 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2724
2819
|
});
|
|
2725
2820
|
});
|
|
2726
2821
|
|
|
2727
|
-
// A text block of the first editor offered; held, the tool
|
|
2728
|
-
// offers each of them when there is more than one
|
|
2729
|
-
var texts = offeredTexts();
|
|
2730
|
-
if (texts.length) {
|
|
2731
|
-
createTool(drawer, t('tool.add_text'), 'ge-add-text', 'bi bi-type', function() {
|
|
2732
|
-
if (closeSizePicker()) { return; } // The picker was open: that was the answer
|
|
2733
|
-
|
|
2734
|
-
addTextTo(col, texts[0]);
|
|
2735
|
-
});
|
|
2736
|
-
|
|
2737
|
-
if (texts.length > 1) {
|
|
2738
|
-
var textTool = drawer.find('> .ge-add-text');
|
|
2739
|
-
attachPicker(textTool, function() { openTextPicker(textTool, col); });
|
|
2740
|
-
}
|
|
2741
|
-
}
|
|
2742
|
-
|
|
2743
2822
|
createTool(drawer, t('tool.add_row'), 'ge-add-row', 'bi bi-plus-circle', function() {
|
|
2744
2823
|
// An empty row: the columns in it are the next decision,
|
|
2745
2824
|
// and its drawer's add column tool is where that is made
|
|
@@ -4202,7 +4281,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4202
4281
|
|
|
4203
4282
|
var column = createColumn(size, options.offset);
|
|
4204
4283
|
if (options.content !== undefined) {
|
|
4205
|
-
column.
|
|
4284
|
+
column.append(contentFor(options.content));
|
|
4206
4285
|
}
|
|
4207
4286
|
|
|
4208
4287
|
return place(column, 'column', options);
|
|
@@ -4270,10 +4349,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4270
4349
|
* the all view. `offset` indents it, within the same 12 unit budget.
|
|
4271
4350
|
*/
|
|
4272
4351
|
function createColumn(size, offset) {
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
;
|
|
4352
|
+
// Empty: what goes in it is the next decision, and the tools of
|
|
4353
|
+
// the column and the toolbar are where it is made
|
|
4354
|
+
var column = $('<div class="column"/>');
|
|
4277
4355
|
|
|
4278
4356
|
// The tier being edited, or the base class in the all view
|
|
4279
4357
|
var tier = tiersFor(curView)[0];
|
|
@@ -4367,8 +4445,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4367
4445
|
return;
|
|
4368
4446
|
} else if (kept) {
|
|
4369
4447
|
// Of the same type, or of none if it had none
|
|
4370
|
-
placed =
|
|
4371
|
-
.append(piece.text);
|
|
4448
|
+
placed = createDefaultContentWrapper(type).append(piece.text);
|
|
4372
4449
|
} else {
|
|
4373
4450
|
// The content area itself, moved along if an
|
|
4374
4451
|
// element came before the first text
|
|
@@ -4424,7 +4501,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4424
4501
|
}
|
|
4425
4502
|
|
|
4426
4503
|
/**
|
|
4427
|
-
* Wrap a run of loose column content in a content area
|
|
4504
|
+
* Wrap a run of loose column content in a content area of no type -
|
|
4505
|
+
* the host's plain content - and hand back
|
|
4428
4506
|
* an empty set: the caller has to forget what it just wrapped, or the
|
|
4429
4507
|
* next boundary wraps the same nodes again and leaves the first
|
|
4430
4508
|
* wrapper behind, empty.
|
|
@@ -4439,12 +4517,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4439
4517
|
}
|
|
4440
4518
|
|
|
4441
4519
|
/**
|
|
4442
|
-
* A content area
|
|
4443
|
-
*
|
|
4444
|
-
* type to name.
|
|
4520
|
+
* A content area of a text type, or with none the host's plain
|
|
4521
|
+
* content: a content area and nothing more.
|
|
4445
4522
|
*/
|
|
4446
4523
|
function createDefaultContentWrapper(type) {
|
|
4447
|
-
type = type || settings.content_types[0];
|
|
4448
4524
|
var contentArea = $('<div class="ge-content"/>');
|
|
4449
4525
|
|
|
4450
4526
|
if (type) {
|
|
@@ -4455,22 +4531,23 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4455
4531
|
}
|
|
4456
4532
|
|
|
4457
4533
|
/* --------------------------------------------------------------
|
|
4458
|
-
*
|
|
4534
|
+
* Content blocks: a content area as a block of its own, with a drawer.
|
|
4459
4535
|
*
|
|
4460
4536
|
* The drawer cannot go inside the content area, as every other
|
|
4461
|
-
* block's does: what is inside
|
|
4462
|
-
* the drawer editable text, copy it into its own document or
|
|
4463
|
-
* away on an undo. So while editing, each content area in a
|
|
4464
|
-
* sits in a .ge-text-block beside its drawer, and that wrapper
|
|
4465
|
-
* block the column moves. deinit takes it off again: it is
|
|
4466
|
-
* of the markup.
|
|
4537
|
+
* block's does: what is inside may be a text editor's, which would
|
|
4538
|
+
* make the drawer editable text, copy it into its own document or
|
|
4539
|
+
* take it away on an undo. So while editing, each content area in a
|
|
4540
|
+
* column sits in a .ge-text-block beside its drawer, and that wrapper
|
|
4541
|
+
* is the block the column moves. deinit takes it off again: it is
|
|
4542
|
+
* never part of the markup.
|
|
4543
|
+
*
|
|
4544
|
+
* A content area with no type is the host's plain content, and its
|
|
4545
|
+
* drawer is the editor's: move and delete, nothing else. One whose
|
|
4546
|
+
* type a plugin declares is that plugin's text, and the plugin gives
|
|
4547
|
+
* it its drawer. One whose type nobody declares is a text whose
|
|
4548
|
+
* editor is not loaded: a block to move and delete, not to edit.
|
|
4467
4549
|
* -------------------------------------------------------------- */
|
|
4468
4550
|
|
|
4469
|
-
/** The text editors this editor offers, in content_types order: the ones loaded. */
|
|
4470
|
-
function offeredTexts() {
|
|
4471
|
-
return settings.content_types.filter(function(type) { return !!TEXTS[type]; });
|
|
4472
|
-
}
|
|
4473
|
-
|
|
4474
4551
|
function wrapTexts() {
|
|
4475
4552
|
canvas.find('.column > .ge-content').each(function() {
|
|
4476
4553
|
$(this).wrap('<div class="ge-text-block" />');
|
|
@@ -4478,7 +4555,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4478
4555
|
|
|
4479
4556
|
canvas.find('.ge-text-block').each(function() {
|
|
4480
4557
|
var textBlock = $(this);
|
|
4481
|
-
if (
|
|
4558
|
+
if (textBlock.children('.ge-tools-drawer').length) { return; }
|
|
4559
|
+
|
|
4560
|
+
var type = textBlock.children('.ge-content').attr('data-ge-content-type');
|
|
4561
|
+
|
|
4562
|
+
if (!type) {
|
|
4563
|
+
createPlainControls(textBlock);
|
|
4564
|
+
} else if (!hasTextOwner(type)) {
|
|
4565
|
+
createOrphanControls(textBlock, type);
|
|
4566
|
+
}
|
|
4482
4567
|
});
|
|
4483
4568
|
}
|
|
4484
4569
|
|
|
@@ -4489,41 +4574,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4489
4574
|
});
|
|
4490
4575
|
}
|
|
4491
4576
|
|
|
4492
|
-
|
|
4577
|
+
/** The host's plain content: moved and deleted here, edited in the source. */
|
|
4578
|
+
function createPlainControls(textBlock) {
|
|
4493
4579
|
var block = textBlock.children('.ge-content');
|
|
4494
|
-
var
|
|
4495
|
-
|
|
4580
|
+
var drawer = $('<div class="ge-tools-drawer ge-text-drawer ge-plain-drawer" />').prependTo(textBlock);
|
|
4581
|
+
textBlock.addClass('ge-plain-block');
|
|
4496
4582
|
|
|
4497
4583
|
createMoveTool(drawer);
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
// still a block to move and delete, but not to edit
|
|
4501
|
-
if (type && !TEXTS[type]) {
|
|
4502
|
-
createTool(drawer, t('text.no_editor', { type: type }), 'ge-text-info ge-text-missing',
|
|
4503
|
-
'bi bi-exclamation-triangle');
|
|
4504
|
-
}
|
|
4505
|
-
|
|
4506
|
-
var details = addSettingsTool(drawer, block, settings.text_classes);
|
|
4507
|
-
|
|
4508
|
-
// Which editor edits it, first in its settings: something to
|
|
4509
|
-
// know about it, not something to do with it
|
|
4510
|
-
if (type && TEXTS[type]) {
|
|
4511
|
-
$('<div class="ge-field ge-text-editor" />')
|
|
4512
|
-
.append($('<span class="ge-field-label" />').text(t('panel.editor')))
|
|
4513
|
-
.append($('<span class="ge-field-value" />').text(textLabel(type)))
|
|
4514
|
-
.prependTo(details.children('.ge-details-general'));
|
|
4515
|
-
}
|
|
4516
|
-
|
|
4517
|
-
settings.text_tools.forEach(function(hostTool) {
|
|
4518
|
-
createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
4519
|
-
hostTool.iconClass || 'bi bi-wrench', hostTool.on);
|
|
4520
|
-
});
|
|
4521
|
-
|
|
4522
|
-
createTool(drawer, t('tool.delete_text'), 'ge-delete-text', 'bi bi-trash', function() {
|
|
4523
|
-
deleteNode('text', block, t('confirm.delete_text'), function(removed) {
|
|
4524
|
-
// Its editor lets go first: removed while open, it would
|
|
4525
|
-
// be left behind, attached to nothing
|
|
4526
|
-
closeText(block);
|
|
4584
|
+
createTool(drawer, t('tool.delete_plain'), 'ge-delete-plain', 'bi bi-trash', function() {
|
|
4585
|
+
deleteNode('plain', block, t('confirm.delete_plain'), function(removed) {
|
|
4527
4586
|
textBlock.slideUp(function() {
|
|
4528
4587
|
textBlock.remove();
|
|
4529
4588
|
removed();
|
|
@@ -4533,162 +4592,34 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4533
4592
|
}
|
|
4534
4593
|
|
|
4535
4594
|
/**
|
|
4536
|
-
*
|
|
4537
|
-
*
|
|
4538
|
-
*
|
|
4539
|
-
* An editor adds attributes of its own while it is open, and takes
|
|
4540
|
-
* them off again, more or less: CKEditor leaves aria-readonly behind.
|
|
4541
|
-
* tinyMCE does worse, and puts back every attribute as it was when it
|
|
4542
|
-
* opened, so an id, a class or a plugin's attribute given while it was
|
|
4543
|
-
* open is lost. So the attributes are read three times - before the
|
|
4544
|
-
* editor opens, once it has opened, and before it closes - and what
|
|
4545
|
-
* changed between the second and the third, the host's doing, is
|
|
4546
|
-
* played back onto the first, the host's markup. What the editor did
|
|
4547
|
-
* is left out either way.
|
|
4595
|
+
* A text whose editor is not loaded: still a block to move and delete,
|
|
4596
|
+
* and its drawer says why it cannot be edited.
|
|
4548
4597
|
*/
|
|
4549
|
-
function
|
|
4550
|
-
var
|
|
4551
|
-
var
|
|
4552
|
-
var open = before ? attributesOf(block[0]) : null;
|
|
4553
|
-
|
|
4554
|
-
// Every content area is told, as in 5.x: one whose editor never
|
|
4555
|
-
// started is the plugin's to ignore
|
|
4556
|
-
if (text) { text.stop(block); }
|
|
4557
|
-
|
|
4558
|
-
// After stop, not before: an editor that restores the class
|
|
4559
|
-
// attribute it snapshotted would put ge-rte-active back
|
|
4560
|
-
block.removeClass('ge-rte-active');
|
|
4561
|
-
|
|
4562
|
-
if (before) {
|
|
4563
|
-
restoreAttributes(block, before, block.data('ge-text-ready') || before, open);
|
|
4564
|
-
block.removeData('ge-text-before').removeData('ge-text-ready');
|
|
4565
|
-
}
|
|
4566
|
-
}
|
|
4567
|
-
|
|
4568
|
-
/** What a text editor puts on a content area while it is open, whenever it likes. */
|
|
4569
|
-
var EDITOR_CLASS = /^(mce-|cke|note-)|^(active|ge-rte-active)$/;
|
|
4570
|
-
var EDITOR_ATTRIBUTE = /^(data-mce-|contenteditable$|spellcheck$)/;
|
|
4571
|
-
|
|
4572
|
-
function attributesOf(element) {
|
|
4573
|
-
var found = {};
|
|
4574
|
-
$.each($.makeArray(element.attributes), function(i, attribute) {
|
|
4575
|
-
found[attribute.name] = attribute.value;
|
|
4576
|
-
});
|
|
4577
|
-
return found;
|
|
4578
|
-
}
|
|
4579
|
-
|
|
4580
|
-
function classesIn(value) {
|
|
4581
|
-
return (value || '').split(/\s+/).filter(function(name) {
|
|
4582
|
-
return name !== '' && !EDITOR_CLASS.test(name);
|
|
4583
|
-
});
|
|
4584
|
-
}
|
|
4585
|
-
|
|
4586
|
-
/** The host's markup, with what changed from `ready` to `open` played back onto it. */
|
|
4587
|
-
function restoreAttributes(block, before, ready, open) {
|
|
4588
|
-
var result = $.extend({}, before);
|
|
4589
|
-
|
|
4590
|
-
$.each($.extend({}, ready, open), function(name) {
|
|
4591
|
-
if (name === 'class' || EDITOR_ATTRIBUTE.test(name) || ready[name] === open[name]) { return; }
|
|
4592
|
-
|
|
4593
|
-
if (open[name] === undefined) {
|
|
4594
|
-
delete result[name];
|
|
4595
|
-
} else {
|
|
4596
|
-
result[name] = open[name];
|
|
4597
|
-
}
|
|
4598
|
-
});
|
|
4598
|
+
function createOrphanControls(textBlock, type) {
|
|
4599
|
+
var block = textBlock.children('.ge-content');
|
|
4600
|
+
var drawer = $('<div class="ge-tools-drawer ge-text-drawer" />').prependTo(textBlock);
|
|
4599
4601
|
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4602
|
+
createMoveTool(drawer);
|
|
4603
|
+
createTool(drawer, t('text.no_editor', { type: type }), 'ge-text-info ge-text-missing',
|
|
4604
|
+
'bi bi-exclamation-triangle');
|
|
4605
|
+
createTool(drawer, t('tool.delete_text'), 'ge-delete-text', 'bi bi-trash', function() {
|
|
4606
|
+
deleteNode('text', block, t('confirm.delete_text'), function(removed) {
|
|
4607
|
+
textBlock.slideUp(function() {
|
|
4608
|
+
textBlock.remove();
|
|
4609
|
+
removed();
|
|
4610
|
+
});
|
|
4611
|
+
});
|
|
4607
4612
|
});
|
|
4608
|
-
|
|
4609
|
-
// In the host's order, class where it was: getHtml should not
|
|
4610
|
-
// shuffle a node's attributes because it was edited
|
|
4611
|
-
if (classes.length) { result['class'] = classes.join(' '); } else { delete result['class']; }
|
|
4612
|
-
|
|
4613
|
-
$.each(attributesOf(block[0]), function(name) { block.removeAttr(name); });
|
|
4614
|
-
$.each(result, function(name, value) { block.attr(name, value); });
|
|
4615
|
-
}
|
|
4616
|
-
|
|
4617
|
-
/** What a text editor is called: its plugin's label, or its type. */
|
|
4618
|
-
function textLabel(type) {
|
|
4619
|
-
var text = TEXTS[type];
|
|
4620
|
-
return text && text.labelKey ? t(text.labelKey) : type;
|
|
4621
|
-
}
|
|
4622
|
-
|
|
4623
|
-
/** A detached content area of `type`, holding `content` or the editor's initial content. */
|
|
4624
|
-
function makeText(type, content) {
|
|
4625
|
-
var text = TEXTS[type];
|
|
4626
|
-
return createDefaultContentWrapper(type)
|
|
4627
|
-
.html(content !== undefined ? content : (text && text.initialContent) || '');
|
|
4628
|
-
}
|
|
4629
|
-
|
|
4630
|
-
/** A text block at the end of a column, through the add events. */
|
|
4631
|
-
function addTextTo(col, type) {
|
|
4632
|
-
var block = makeText(type);
|
|
4633
|
-
|
|
4634
|
-
return addNode('text', block, function() {
|
|
4635
|
-
col.append(block);
|
|
4636
|
-
}, { parent: col, source: 'tool' });
|
|
4637
4613
|
}
|
|
4638
4614
|
|
|
4639
4615
|
/**
|
|
4640
|
-
*
|
|
4641
|
-
*
|
|
4642
|
-
* offered by default. `options.content` is its html.
|
|
4616
|
+
* A detached content area holding `content`: a text of the first type
|
|
4617
|
+
* offered, or the host's plain content when no editor is offered.
|
|
4643
4618
|
*/
|
|
4644
|
-
function
|
|
4645
|
-
|
|
4646
|
-
options = type;
|
|
4647
|
-
type = undefined;
|
|
4648
|
-
}
|
|
4649
|
-
options = options || {};
|
|
4650
|
-
type = type || offeredTexts()[0];
|
|
4651
|
-
|
|
4652
|
-
if (!type || !TEXTS[type]) {
|
|
4653
|
-
warnOnceHere('createText:' + type, 'createText: no text editor "' + type + '" is loaded; ' +
|
|
4654
|
-
'load its plugin and name it in content_types');
|
|
4655
|
-
return null;
|
|
4656
|
-
}
|
|
4657
|
-
|
|
4658
|
-
return place(makeText(type, options.content), 'text', options);
|
|
4659
|
-
}
|
|
4660
|
-
|
|
4661
|
-
/**
|
|
4662
|
-
* The text editors offered, as a strip under the add text tool, when
|
|
4663
|
-
* there is more than one to choose from.
|
|
4664
|
-
*/
|
|
4665
|
-
function openTextPicker(tool, col) {
|
|
4666
|
-
closeSizePicker();
|
|
4667
|
-
|
|
4668
|
-
tool.closest('.ge-tools-drawer').addClass('ge-picker-open');
|
|
4669
|
-
sizePicker = $('<div class="ge-size-picker ge-text-picker" />').appendTo(tool);
|
|
4670
|
-
|
|
4671
|
-
offeredTexts().forEach(function(type) {
|
|
4672
|
-
$('<a class="ge-size ge-size-flex" />')
|
|
4673
|
-
.attr('data-ge-content-type', type)
|
|
4674
|
-
.attr('title', t('tool.add_text_type', { editor: textLabel(type) }))
|
|
4675
|
-
.text(textLabel(type))
|
|
4676
|
-
.on('click', function(e) {
|
|
4677
|
-
e.preventDefault();
|
|
4678
|
-
e.stopPropagation();
|
|
4679
|
-
|
|
4680
|
-
closeSizePicker();
|
|
4681
|
-
addTextTo(col, type);
|
|
4682
|
-
})
|
|
4683
|
-
.appendTo(sizePicker)
|
|
4684
|
-
;
|
|
4685
|
-
});
|
|
4619
|
+
function contentFor(content) {
|
|
4620
|
+
var offers = textOffers();
|
|
4686
4621
|
|
|
4687
|
-
|
|
4688
|
-
window.setTimeout(function() {
|
|
4689
|
-
if (sizePicker && !sizePicker.is(':hover')) { closeSizePicker(); }
|
|
4690
|
-
}, 400);
|
|
4691
|
-
});
|
|
4622
|
+
return createDefaultContentWrapper(offers.length ? offers[0].type : null).html(content);
|
|
4692
4623
|
}
|
|
4693
4624
|
|
|
4694
4625
|
/**
|
|
@@ -4745,23 +4676,6 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4745
4676
|
return curView;
|
|
4746
4677
|
}
|
|
4747
4678
|
|
|
4748
|
-
/** The text editor plugin for a content type, or null. */
|
|
4749
|
-
function textFor(type) {
|
|
4750
|
-
return TEXTS[type] || null;
|
|
4751
|
-
}
|
|
4752
|
-
|
|
4753
|
-
/**
|
|
4754
|
-
* An integration written to 5.x's contract - init and deinit over a
|
|
4755
|
-
* set of content areas - as a text editor plugin.
|
|
4756
|
-
*/
|
|
4757
|
-
function legacyText(rte) {
|
|
4758
|
-
return {
|
|
4759
|
-
initialContent: rte.initialContent,
|
|
4760
|
-
start: function(block) { rte.init(settings, block); },
|
|
4761
|
-
stop: function(block) { rte.deinit(settings, block); },
|
|
4762
|
-
};
|
|
4763
|
-
}
|
|
4764
|
-
|
|
4765
4679
|
/**
|
|
4766
4680
|
* The instance handle, documented API as of 3.0: the methods the
|
|
4767
4681
|
* plugin dispatches, plus the settings and the canvas. A host holding
|
|
@@ -4781,7 +4695,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4781
4695
|
getView: getView,
|
|
4782
4696
|
createRow: apiCreateRow,
|
|
4783
4697
|
createColumn: apiCreateColumn,
|
|
4784
|
-
createText:
|
|
4698
|
+
createText: function(type, options) {
|
|
4699
|
+
if (!featureMethods.createText) {
|
|
4700
|
+
warnOnceHere('plugin:text', 'createText needs a text editor plugin: include ' +
|
|
4701
|
+
'dist/plugins/grideditor.tinymce.js, or another editor\'s, after the editor');
|
|
4702
|
+
return null;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
return featureMethods.createText(type, options);
|
|
4706
|
+
},
|
|
4785
4707
|
createElement: function(content, options) {
|
|
4786
4708
|
if (!featureMethods.createElement) {
|
|
4787
4709
|
warnOnceHere('plugin:elements', 'createElement needs the elements plugin: ' +
|
|
@@ -4826,6 +4748,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4826
4748
|
baseElem.data('grideditor', handle);
|
|
4827
4749
|
|
|
4828
4750
|
loadPlugins();
|
|
4751
|
+
// Again, with what the plugins filled in: the text editors'
|
|
4752
|
+
// content_types when the host gave none
|
|
4753
|
+
handle.settings = settingsCopy();
|
|
4829
4754
|
setup();
|
|
4830
4755
|
init();
|
|
4831
4756
|
|
|
@@ -4836,14 +4761,10 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4836
4761
|
};
|
|
4837
4762
|
|
|
4838
4763
|
/**
|
|
4839
|
-
*
|
|
4840
|
-
*
|
|
4841
|
-
*
|
|
4842
|
-
* { labelKey, initialContent, available, missingKey, start, stop }.
|
|
4764
|
+
* 5.x's registry of text editors, removed in 6.0: still there to register
|
|
4765
|
+
* into, so a page written for 5.x does not throw, but what it holds is
|
|
4766
|
+
* ignored with a warning. The text editors are plugins since 6.0.
|
|
4843
4767
|
*/
|
|
4844
|
-
$.fn.gridEditor.texts = {};
|
|
4845
|
-
|
|
4846
|
-
/** 5.x's registry of text editors, adapted with a warning. Removed in 7.0. */
|
|
4847
4768
|
$.fn.gridEditor.RTEs = {};
|
|
4848
4769
|
|
|
4849
4770
|
/**
|
|
@@ -4899,11 +4820,9 @@ $.fn.gridEditor.locales = {
|
|
|
4899
4820
|
'tool.move': 'Move',
|
|
4900
4821
|
'tool.settings': 'Settings',
|
|
4901
4822
|
'tool.add_row': 'Add row',
|
|
4902
|
-
'tool.add_text': 'Add text',
|
|
4903
|
-
'tool.add_text_type': 'Add {editor} text',
|
|
4904
4823
|
'tool.delete_text': 'Remove text',
|
|
4905
|
-
'
|
|
4906
|
-
'
|
|
4824
|
+
'tool.delete_plain': 'Remove content',
|
|
4825
|
+
'tool.convert_type': 'Edit as {editor} text',
|
|
4907
4826
|
'text.no_editor': 'No text editor "{type}" is loaded: this text can be moved and deleted, not edited',
|
|
4908
4827
|
'tool.add_column': 'Add column\n(hold to choose the width)',
|
|
4909
4828
|
'tool.column_size': '{size} of 12',
|
|
@@ -4925,10 +4844,8 @@ $.fn.gridEditor.locales = {
|
|
|
4925
4844
|
'panel.done': 'Done',
|
|
4926
4845
|
'panel.id': 'Id',
|
|
4927
4846
|
'panel.classes': 'Classes',
|
|
4928
|
-
'panel.editor': 'Editor',
|
|
4929
4847
|
'panel.kind_row': 'Row',
|
|
4930
4848
|
'panel.kind_column': 'Column',
|
|
4931
|
-
'panel.kind_text': 'Text',
|
|
4932
4849
|
'panel.kind_element': 'Element',
|
|
4933
4850
|
'panel.kind_section': 'Section',
|
|
4934
4851
|
'panel.kind_tab': 'Tab',
|
|
@@ -4946,6 +4863,7 @@ $.fn.gridEditor.locales = {
|
|
|
4946
4863
|
'confirm.delete_row': 'Delete row?',
|
|
4947
4864
|
'confirm.delete_column': 'Delete column?',
|
|
4948
4865
|
'confirm.delete_text': 'Delete this text?',
|
|
4866
|
+
'confirm.delete_plain': 'Delete this content?',
|
|
4949
4867
|
'confirm.delete_container': 'Delete this container and everything in it?',
|
|
4950
4868
|
'view.all': 'All sizes',
|
|
4951
4869
|
'view.xs': 'Phone',
|