@themarioga/grid-editor 5.1.1 → 5.2.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 +45 -0
- package/README.md +18 -8
- package/UPGRADING.md +25 -0
- package/dist/grideditor.css +3 -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 +374 -218
- package/dist/jquery.grideditor.min.js +1 -1
- package/dist/jquery.grideditor.min.js.map +1 -1
- package/dist/plugins/grideditor.ckeditor.js +115 -0
- package/dist/plugins/grideditor.ckeditor.min.js +2 -0
- package/dist/plugins/grideditor.ckeditor.min.js.map +1 -0
- package/dist/plugins/grideditor.summernote.js +93 -0
- package/dist/plugins/grideditor.summernote.min.js +2 -0
- package/dist/plugins/grideditor.summernote.min.js.map +1 -0
- package/dist/plugins/grideditor.tinymce.js +157 -0
- package/dist/plugins/grideditor.tinymce.min.js +2 -0
- package/dist/plugins/grideditor.tinymce.min.js.map +1 -0
- package/docs/plugins.md +86 -3
- package/example/attributes.html +364 -0
- 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/index.html +8 -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 +73 -14
- package/src/js/plugins/grideditor.ckeditor.js +115 -0
- package/src/js/plugins/grideditor.summernote.js +93 -0
- package/src/js/plugins/grideditor.tinymce.js +157 -0
- package/src/less/grideditor.less +4 -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 -135
|
@@ -894,7 +894,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
894
894
|
|
|
895
895
|
// Add row
|
|
896
896
|
addRowGroup = $('<div class="ge-addRowGroup btn-group" />').appendTo(wrapper);
|
|
897
|
-
addContainerGroup = $('<div class="ge-addContainerGroup btn-group" />');
|
|
897
|
+
addContainerGroup = $('<div class="ge-addContainerGroup btn-group ms-1" />');
|
|
898
898
|
$.each(settings.new_row_layouts, function(j, layout) {
|
|
899
899
|
var grouped = !Array.isArray(layout);
|
|
900
900
|
var btn = $('<a class="btn btn-sm btn-primary" />')
|
|
@@ -1040,9 +1040,11 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1040
1040
|
;
|
|
1041
1041
|
|
|
1042
1042
|
// Floated right after the source and preview buttons, so it
|
|
1043
|
-
// stands to their left
|
|
1043
|
+
// stands to their left. Not a btn-group: its buttons show one at
|
|
1044
|
+
// a time, and a hidden one still counts as a neighbour to
|
|
1045
|
+
// Bootstrap, which squares off the corners they would share.
|
|
1044
1046
|
if (endItems.length) {
|
|
1045
|
-
$('<div class="
|
|
1047
|
+
$('<div class="pull-right ge-toolbar-end" />')
|
|
1046
1048
|
.append(endItems)
|
|
1047
1049
|
.appendTo(wrapper)
|
|
1048
1050
|
;
|
|
@@ -1402,11 +1404,25 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1402
1404
|
// its toolbar out against, and nothing anyone can type into
|
|
1403
1405
|
if (!$(this).is(':visible')) { return; }
|
|
1404
1406
|
|
|
1405
|
-
var
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1407
|
+
var type = $(this).data('ge-content-type');
|
|
1408
|
+
var text = textFor(type);
|
|
1409
|
+
if (!text) { return; }
|
|
1410
|
+
|
|
1411
|
+
// Not marked active, so the next click tries again: the library
|
|
1412
|
+
// may be loaded by then
|
|
1413
|
+
if (text.available && !text.available()) {
|
|
1414
|
+
if (text.missingKey) { console.error(t(text.missingKey)); }
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if (text.bundled) {
|
|
1419
|
+
warnOnceHere('text-bundled:' + type, 'the ' + type + ' text editor is the copy in the ' +
|
|
1420
|
+
'main bundle, which 6.0 will not include: load dist/plugins/grideditor.' + type +
|
|
1421
|
+
'.js after the editor');
|
|
1409
1422
|
}
|
|
1423
|
+
|
|
1424
|
+
$(this).addClass('ge-rte-active');
|
|
1425
|
+
text.start($(this));
|
|
1410
1426
|
}
|
|
1411
1427
|
|
|
1412
1428
|
function reset() {
|
|
@@ -1434,9 +1450,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1434
1450
|
canvas.removeClass('ge-editing ge-drag-drawer ge-dropping');
|
|
1435
1451
|
var contents = canvas.find('.ge-content').each(function() {
|
|
1436
1452
|
var content = $(this);
|
|
1437
|
-
var
|
|
1438
|
-
if (
|
|
1439
|
-
|
|
1453
|
+
var text = textFor(content.data('ge-content-type'));
|
|
1454
|
+
if (text) {
|
|
1455
|
+
text.stop(content);
|
|
1440
1456
|
}
|
|
1441
1457
|
// Cleared after rte.deinit, not before: an editor can restore the
|
|
1442
1458
|
// class attribute it snapshotted when it was created, which would
|
|
@@ -1553,6 +1569,23 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1553
1569
|
if (wanted(name)) { FEATURES[name] = factory(api); }
|
|
1554
1570
|
});
|
|
1555
1571
|
|
|
1572
|
+
// Text editors are chosen by content_types rather than by the
|
|
1573
|
+
// plugins setting: a page that names its containers there has
|
|
1574
|
+
// named no editor, and still wants the one it uses
|
|
1575
|
+
$.each($.fn.gridEditor.texts, function(type, factory) {
|
|
1576
|
+
TEXTS[type] = $.extend({ bundled: !!factory.bundled }, factory(api));
|
|
1577
|
+
});
|
|
1578
|
+
|
|
1579
|
+
// 5.x's registry, for an integration a host wrote itself. One the
|
|
1580
|
+
// plugins above already provide is theirs.
|
|
1581
|
+
$.each($.fn.gridEditor.RTEs, function(type, rte) {
|
|
1582
|
+
if (TEXTS[type]) { return; }
|
|
1583
|
+
|
|
1584
|
+
warnOnceHere('rtes:' + type, '$.fn.gridEditor.RTEs is deprecated and will be removed ' +
|
|
1585
|
+
'in 7.0: register "' + type + '" under $.fn.gridEditor.texts, see docs/plugins.md');
|
|
1586
|
+
TEXTS[type] = legacyText(rte);
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1556
1589
|
$.each($.fn.gridEditor.utilities, function(name, factory) {
|
|
1557
1590
|
if (!wanted(name)) { return; }
|
|
1558
1591
|
|
|
@@ -1629,6 +1662,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1629
1662
|
bareStyle: bareStyle,
|
|
1630
1663
|
rowFromLayout: rowFromLayoutValue,
|
|
1631
1664
|
nodeHtml: nodeHtml,
|
|
1665
|
+
// A text editor has rewritten a content area, so whatever the
|
|
1666
|
+
// editor and its plugins had put in there goes back in
|
|
1667
|
+
textReady: function(block) { block.trigger('ge-rte-ready'); },
|
|
1632
1668
|
toolbarItems: function(name) {
|
|
1633
1669
|
return mainControls
|
|
1634
1670
|
? mainControls.find('[data-ge-toolbar="feature"][data-ge-feature="' + name + '"]')
|
|
@@ -2162,6 +2198,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
2162
2198
|
* -------------------------------------------------------------- */
|
|
2163
2199
|
|
|
2164
2200
|
var CONTAINERS = {}; // The container plugins in use, by the type each builds
|
|
2201
|
+
var TEXTS = {}; // The text editor plugins, by the content type each edits
|
|
2165
2202
|
var FEATURES = {}; // The feature plugins in use, by name
|
|
2166
2203
|
var UTILITIES = {}; // The utility plugins in use, by name
|
|
2167
2204
|
var featureMethods = {}; // The methods those features contribute
|
|
@@ -3768,9 +3805,9 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3768
3805
|
* the all view. `offset` indents it, within the same 12 unit budget.
|
|
3769
3806
|
*/
|
|
3770
3807
|
function createColumn(size, offset) {
|
|
3771
|
-
var
|
|
3808
|
+
var text = textFor(settings.content_types[0]);
|
|
3772
3809
|
var column = $('<div class="column"/>')
|
|
3773
|
-
.append(createDefaultContentWrapper().html(
|
|
3810
|
+
.append(createDefaultContentWrapper().html(text ? text.initialContent : ''))
|
|
3774
3811
|
;
|
|
3775
3812
|
|
|
3776
3813
|
// The tier being edited, or the base class in the all view
|
|
@@ -3913,8 +3950,21 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3913
3950
|
return curView;
|
|
3914
3951
|
}
|
|
3915
3952
|
|
|
3916
|
-
|
|
3917
|
-
|
|
3953
|
+
/** The text editor plugin for a content type, or null. */
|
|
3954
|
+
function textFor(type) {
|
|
3955
|
+
return TEXTS[type] || null;
|
|
3956
|
+
}
|
|
3957
|
+
|
|
3958
|
+
/**
|
|
3959
|
+
* An integration written to 5.x's contract - init and deinit over a
|
|
3960
|
+
* set of content areas - as a text editor plugin.
|
|
3961
|
+
*/
|
|
3962
|
+
function legacyText(rte) {
|
|
3963
|
+
return {
|
|
3964
|
+
initialContent: rte.initialContent,
|
|
3965
|
+
start: function(block) { rte.init(settings, block); },
|
|
3966
|
+
stop: function(block) { rte.deinit(settings, block); },
|
|
3967
|
+
};
|
|
3918
3968
|
}
|
|
3919
3969
|
|
|
3920
3970
|
/**
|
|
@@ -3989,6 +4039,15 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
3989
4039
|
|
|
3990
4040
|
};
|
|
3991
4041
|
|
|
4042
|
+
/**
|
|
4043
|
+
* Text editor plugins: tinyMCE, CKEditor, summernote, and whatever a host
|
|
4044
|
+
* writes. A factory registered under the content type it edits, called once
|
|
4045
|
+
* per editor with the handle described in docs/plugins.md, returning
|
|
4046
|
+
* { labelKey, initialContent, available, missingKey, start, stop }.
|
|
4047
|
+
*/
|
|
4048
|
+
$.fn.gridEditor.texts = {};
|
|
4049
|
+
|
|
4050
|
+
/** 5.x's registry of text editors, adapted with a warning. Removed in 7.0. */
|
|
3992
4051
|
$.fn.gridEditor.RTEs = {};
|
|
3993
4052
|
|
|
3994
4053
|
/**
|
|
@@ -4099,30 +4158,225 @@ $.fn.gridEditor.locales = {
|
|
|
4099
4158
|
};
|
|
4100
4159
|
|
|
4101
4160
|
})( jQuery );
|
|
4161
|
+
/**
|
|
4162
|
+
* tinyMCE for grid-editor's content areas.
|
|
4163
|
+
*
|
|
4164
|
+
* A text editor plugin: load this file after the editor, and tinyMCE 6
|
|
4165
|
+
* after or before it, and content_types: ['tinymce'] edits each content area
|
|
4166
|
+
* with an inline tinyMCE. What it can ask the editor for is the handle its
|
|
4167
|
+
* factory is called with, described in docs/plugins.md.
|
|
4168
|
+
*
|
|
4169
|
+
* <script src="tinymce/tinymce.min.js"></script>
|
|
4170
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
4171
|
+
* <script src="dist/plugins/grideditor.tinymce.min.js"></script>
|
|
4172
|
+
*
|
|
4173
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
4174
|
+
*/
|
|
4102
4175
|
(function($) {
|
|
4103
|
-
$.fn.gridEditor.RTEs.ckeditor = {
|
|
4104
4176
|
|
|
4105
|
-
|
|
4177
|
+
// tinyMCE snapshots the target element's attributes when an inline editor is
|
|
4178
|
+
// created and restores them on remove(), so this has to run *after* remove()
|
|
4179
|
+
// to keep the grid editor's own class and tinyMCE's leftovers off the element.
|
|
4180
|
+
function cleanUp(contentArea) {
|
|
4181
|
+
contentArea
|
|
4182
|
+
.removeClass('active')
|
|
4183
|
+
.removeClass('ge-rte-active')
|
|
4184
|
+
.removeAttr('id')
|
|
4185
|
+
.removeAttr('style')
|
|
4186
|
+
.removeAttr('spellcheck')
|
|
4187
|
+
.removeAttr('contenteditable')
|
|
4188
|
+
.removeAttr('data-mce-style')
|
|
4189
|
+
;
|
|
4190
|
+
}
|
|
4191
|
+
|
|
4192
|
+
var INITIAL_CONTENT = '<p>Lorem ipsum dolores</p>';
|
|
4106
4193
|
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4194
|
+
$.fn.gridEditor.texts.tinymce = function(ge) {
|
|
4195
|
+
return {
|
|
4196
|
+
initialContent: INITIAL_CONTENT,
|
|
4197
|
+
missingKey: 'error.tinymce_missing',
|
|
4198
|
+
|
|
4199
|
+
available: function() { return !!window.tinymce; },
|
|
4200
|
+
|
|
4201
|
+
start: function(contentAreas) {
|
|
4202
|
+
var settings = ge.settings;
|
|
4203
|
+
var userConfig = (settings.tinymce && settings.tinymce.config) ? settings.tinymce.config : {};
|
|
4204
|
+
|
|
4205
|
+
contentAreas.each(function() {
|
|
4206
|
+
var contentArea = $(this);
|
|
4207
|
+
if (contentArea.hasClass('active')) { return; }
|
|
4110
4208
|
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
var contentArea = $(this);
|
|
4114
|
-
if (!contentArea.hasClass('active')) {
|
|
4115
|
-
if (contentArea.html() == self.initialContent) {
|
|
4116
|
-
// CKEditor kills this ' ' creating a non usable box :/
|
|
4117
|
-
contentArea.html(' ');
|
|
4209
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
4210
|
+
contentArea.html('');
|
|
4118
4211
|
}
|
|
4119
|
-
|
|
4212
|
+
contentArea.addClass('active');
|
|
4213
|
+
|
|
4214
|
+
var configuration = $.extend({
|
|
4215
|
+
// tinyMCE's own "Upgrade" badge in the menubar. Off by
|
|
4216
|
+
// default because an inline editor here is a column of
|
|
4217
|
+
// someone's page, not tinyMCE's own interface; a host that
|
|
4218
|
+
// wants it back passes promotion: true.
|
|
4219
|
+
promotion: false,
|
|
4220
|
+
}, userConfig, {
|
|
4221
|
+
target: this,
|
|
4222
|
+
inline: true,
|
|
4223
|
+
init_instance_callback: function(editor) {
|
|
4224
|
+
// deinit ran before this init finished, so tear it down again
|
|
4225
|
+
if (contentArea.data('ge-tinymce-pending-remove')) {
|
|
4226
|
+
contentArea.removeData('ge-tinymce-pending-remove');
|
|
4227
|
+
editor.remove();
|
|
4228
|
+
// deinit already ran and cannot clean up after this
|
|
4229
|
+
// late remove(), so do it here instead
|
|
4230
|
+
cleanUp(contentArea);
|
|
4231
|
+
return;
|
|
4232
|
+
}
|
|
4233
|
+
|
|
4234
|
+
contentArea.data('ge-tinymce', editor);
|
|
4235
|
+
|
|
4236
|
+
// The editor rewrote what is inside this content area
|
|
4237
|
+
// while it took it over, so whatever the grid editor
|
|
4238
|
+
// had in there is gone. Saying so lets it put its own
|
|
4239
|
+
// furniture back.
|
|
4240
|
+
ge.textReady(contentArea);
|
|
4241
|
+
|
|
4242
|
+
// Undo and redo rewrite it too, from snapshots that
|
|
4243
|
+
// leave out whatever is marked data-mce-bogus - an
|
|
4244
|
+
// element's drawer among them - so it goes back in
|
|
4245
|
+
// after each of those as well
|
|
4246
|
+
editor.on('Undo Redo', function() {
|
|
4247
|
+
ge.textReady(contentArea);
|
|
4248
|
+
});
|
|
4249
|
+
|
|
4250
|
+
// The inline toolbar is laid out against the element's
|
|
4251
|
+
// geometry at the moment tinyMCE draws it, and an
|
|
4252
|
+
// element that has just appeared - a tab pane, an
|
|
4253
|
+
// accordion body, a column whose width is still
|
|
4254
|
+
// settling - may not have its own width yet. Asking
|
|
4255
|
+
// for the ui again once the browser has laid the frame
|
|
4256
|
+
// out measures it as it now is, instead of leaving a
|
|
4257
|
+
// toolbar wrapped into a narrow column.
|
|
4258
|
+
window.requestAnimationFrame(function() {
|
|
4259
|
+
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
4260
|
+
|
|
4261
|
+
editor.ui.show();
|
|
4262
|
+
});
|
|
4263
|
+
|
|
4264
|
+
// And again whenever the user comes back to this
|
|
4265
|
+
// editor: by then the element may have been resized,
|
|
4266
|
+
// hidden and shown again - a tab switched away from
|
|
4267
|
+
// and back, a column made narrower - and the toolbar
|
|
4268
|
+
// is only ever as right as its last measurement.
|
|
4269
|
+
editor.on('focus', function() {
|
|
4270
|
+
window.requestAnimationFrame(function() {
|
|
4271
|
+
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
4272
|
+
|
|
4273
|
+
editor.ui.show();
|
|
4274
|
+
});
|
|
4275
|
+
});
|
|
4276
|
+
|
|
4277
|
+
// Bring focus to text field
|
|
4278
|
+
editor.focus();
|
|
4279
|
+
|
|
4280
|
+
// Call the original callbacks, if any were passed in the config
|
|
4281
|
+
if (userConfig.init_instance_callback) {
|
|
4282
|
+
userConfig.init_instance_callback.call(this, editor);
|
|
4283
|
+
}
|
|
4284
|
+
// 'oninit' is the pre-6 name, honoured so existing configs keep working
|
|
4285
|
+
if (userConfig.oninit) {
|
|
4286
|
+
userConfig.oninit.call(this, editor);
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
});
|
|
4290
|
+
// We always edit the element we were handed, so a selector in the
|
|
4291
|
+
// user config would only fight with target
|
|
4292
|
+
delete configuration.selector;
|
|
4293
|
+
|
|
4294
|
+
window.tinymce.init(configuration);
|
|
4295
|
+
});
|
|
4296
|
+
},
|
|
4297
|
+
|
|
4298
|
+
stop: function(contentAreas) {
|
|
4299
|
+
contentAreas.filter('.active').each(function() {
|
|
4300
|
+
var contentArea = $(this);
|
|
4301
|
+
var editor = contentArea.data('ge-tinymce');
|
|
4302
|
+
|
|
4303
|
+
if (editor) {
|
|
4304
|
+
contentArea.removeData('ge-tinymce');
|
|
4305
|
+
editor.remove();
|
|
4306
|
+
} else {
|
|
4307
|
+
// tinymce.init() is asynchronous, so the editor may not exist
|
|
4308
|
+
// yet. Leave a note for init_instance_callback to remove it.
|
|
4309
|
+
contentArea.data('ge-tinymce-pending-remove', true);
|
|
4310
|
+
}
|
|
4311
|
+
|
|
4312
|
+
cleanUp(contentArea);
|
|
4313
|
+
});
|
|
4314
|
+
},
|
|
4315
|
+
};
|
|
4316
|
+
};
|
|
4317
|
+
})(jQuery);
|
|
4318
|
+
|
|
4319
|
+
/**
|
|
4320
|
+
* CKEditor for grid-editor's content areas.
|
|
4321
|
+
*
|
|
4322
|
+
* A text editor plugin: load this file after the editor, and CKEditor 4
|
|
4323
|
+
* after or before it, and content_types: ['ckeditor'] edits each content area
|
|
4324
|
+
* with an inline CKEditor. What it can ask the editor for is the handle its
|
|
4325
|
+
* factory is called with, described in docs/plugins.md.
|
|
4326
|
+
*
|
|
4327
|
+
* <script src="ckeditor/ckeditor.js"></script>
|
|
4328
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
4329
|
+
* <script src="dist/plugins/grideditor.ckeditor.min.js"></script>
|
|
4330
|
+
*
|
|
4331
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
4332
|
+
*/
|
|
4333
|
+
(function($) {
|
|
4334
|
+
|
|
4335
|
+
var INITIAL_CONTENT = '<p>Lorem initius... </p>';
|
|
4336
|
+
|
|
4337
|
+
$.fn.gridEditor.texts.ckeditor = function(ge) {
|
|
4338
|
+
|
|
4339
|
+
/**
|
|
4340
|
+
* The instance editing this content area. Kept in jQuery data when it
|
|
4341
|
+
* is made, and looked for among CKEditor's own as a fallback, since
|
|
4342
|
+
* an instance made by another version of this file has no data.
|
|
4343
|
+
*/
|
|
4344
|
+
function instanceOf(contentArea) {
|
|
4345
|
+
var kept = contentArea.data('ge-ckeditor');
|
|
4346
|
+
if (kept) { return kept; }
|
|
4347
|
+
|
|
4348
|
+
var found = null;
|
|
4349
|
+
$.each(window.CKEDITOR.instances, function(name, instance) {
|
|
4350
|
+
if (instance.element && instance.element.$ === contentArea[0]) { found = instance; }
|
|
4351
|
+
});
|
|
4352
|
+
|
|
4353
|
+
return found;
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4356
|
+
return {
|
|
4357
|
+
initialContent: INITIAL_CONTENT,
|
|
4358
|
+
missingKey: 'error.ckeditor_missing',
|
|
4359
|
+
|
|
4360
|
+
available: function() { return !!window.CKEDITOR; },
|
|
4361
|
+
|
|
4362
|
+
start: function(contentAreas) {
|
|
4363
|
+
var settings = ge.settings;
|
|
4364
|
+
|
|
4365
|
+
contentAreas.each(function() {
|
|
4366
|
+
var contentArea = $(this);
|
|
4367
|
+
if (contentArea.hasClass('active')) { return; }
|
|
4368
|
+
|
|
4369
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
4370
|
+
// CKEditor kills this ' ' creating a non usable box :/
|
|
4371
|
+
contentArea.html(' ');
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4120
4374
|
// Add the .attr('contenteditable',''true') or CKEditor loads readonly
|
|
4121
4375
|
contentArea.addClass('active').attr('contenteditable', 'true');
|
|
4122
|
-
|
|
4376
|
+
|
|
4123
4377
|
var configuration = $.extend(
|
|
4124
4378
|
{},
|
|
4125
|
-
(settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
|
|
4379
|
+
(settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
|
|
4126
4380
|
{
|
|
4127
4381
|
// Focus editor on creation
|
|
4128
4382
|
on: {
|
|
@@ -4141,56 +4395,81 @@ $.fn.gridEditor.locales = {
|
|
|
4141
4395
|
// The editor owns what is inside the
|
|
4142
4396
|
// content area now, so the grid editor is
|
|
4143
4397
|
// told to put its own furniture back
|
|
4144
|
-
|
|
4398
|
+
ge.textReady(contentArea);
|
|
4145
4399
|
|
|
4146
4400
|
instance.focus();
|
|
4147
4401
|
}
|
|
4148
4402
|
}
|
|
4149
4403
|
}
|
|
4150
4404
|
);
|
|
4151
|
-
var instance = CKEDITOR.inline(contentArea.get(0), configuration);
|
|
4152
|
-
|
|
4153
|
-
});
|
|
4154
|
-
},
|
|
4155
|
-
|
|
4156
|
-
deinit: function(settings, contentAreas) {
|
|
4157
|
-
contentAreas.filter('.active').each(function() {
|
|
4158
|
-
var contentArea = $(this);
|
|
4159
|
-
|
|
4160
|
-
// Destroy all CKEditor instances
|
|
4161
|
-
$.each(CKEDITOR.instances, function(_, instance) {
|
|
4162
|
-
instance.destroy();
|
|
4405
|
+
var instance = window.CKEDITOR.inline(contentArea.get(0), configuration);
|
|
4406
|
+
contentArea.data('ge-ckeditor', instance);
|
|
4163
4407
|
});
|
|
4408
|
+
},
|
|
4164
4409
|
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
.
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4410
|
+
stop: function(contentAreas) {
|
|
4411
|
+
contentAreas.filter('.active').each(function() {
|
|
4412
|
+
var contentArea = $(this);
|
|
4413
|
+
|
|
4414
|
+
// This content area's instance, and no other: up to 5.x
|
|
4415
|
+
// closing one content area destroyed every CKEditor on
|
|
4416
|
+
// the page, other editors' and the host's own included
|
|
4417
|
+
var instance = window.CKEDITOR ? instanceOf(contentArea) : null;
|
|
4418
|
+
if (instance) { instance.destroy(); }
|
|
4419
|
+
contentArea.removeData('ge-ckeditor');
|
|
4420
|
+
|
|
4421
|
+
// Cleanup
|
|
4422
|
+
contentArea
|
|
4423
|
+
.removeClass('active cke_focus')
|
|
4424
|
+
.removeAttr('id')
|
|
4425
|
+
.removeAttr('style')
|
|
4426
|
+
.removeAttr('spellcheck')
|
|
4427
|
+
.removeAttr('contenteditable')
|
|
4428
|
+
;
|
|
4429
|
+
});
|
|
4430
|
+
},
|
|
4431
|
+
};
|
|
4177
4432
|
};
|
|
4178
4433
|
})(jQuery);
|
|
4434
|
+
|
|
4435
|
+
/**
|
|
4436
|
+
* Summernote for grid-editor's content areas.
|
|
4437
|
+
*
|
|
4438
|
+
* A text editor plugin: load this file after the editor, and summernote
|
|
4439
|
+
* after or before it, and content_types: ['summernote'] edits each content
|
|
4440
|
+
* area with summernote in air mode. What it can ask the editor for is the
|
|
4441
|
+
* handle its factory is called with, described in docs/plugins.md.
|
|
4442
|
+
*
|
|
4443
|
+
* <script src="summernote/summernote-bs5.min.js"></script>
|
|
4444
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
4445
|
+
* <script src="dist/plugins/grideditor.summernote.min.js"></script>
|
|
4446
|
+
*
|
|
4447
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
4448
|
+
*/
|
|
4179
4449
|
(function($) {
|
|
4180
4450
|
|
|
4181
|
-
|
|
4451
|
+
var INITIAL_CONTENT = '<p>Lorem ipsum dolores</p>';
|
|
4182
4452
|
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
}
|
|
4453
|
+
$.fn.gridEditor.texts.summernote = function(ge) {
|
|
4454
|
+
return {
|
|
4455
|
+
initialContent: INITIAL_CONTENT,
|
|
4456
|
+
missingKey: 'error.summernote_missing',
|
|
4188
4457
|
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4458
|
+
available: function() { return !!$.fn.summernote; },
|
|
4459
|
+
|
|
4460
|
+
start: function(contentAreas) {
|
|
4461
|
+
var settings = ge.settings;
|
|
4462
|
+
|
|
4463
|
+
// Summernote 0.9.1 calls $.now(), which jQuery 4 removed, and
|
|
4464
|
+
// cannot open without it. Given back only where it is missing,
|
|
4465
|
+
// and only once summernote is actually used.
|
|
4466
|
+
if (!$.now) { $.now = Date.now; }
|
|
4467
|
+
|
|
4468
|
+
contentAreas.each(function() {
|
|
4469
|
+
var contentArea = $(this);
|
|
4470
|
+
if (contentArea.hasClass('active')) { return; }
|
|
4471
|
+
|
|
4472
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
4194
4473
|
contentArea.html('');
|
|
4195
4474
|
}
|
|
4196
4475
|
contentArea.addClass('active');
|
|
@@ -4205,7 +4484,7 @@ $.fn.gridEditor.locales = {
|
|
|
4205
4484
|
// Focus editor on creation
|
|
4206
4485
|
callbacks: {
|
|
4207
4486
|
onInit: function() {
|
|
4208
|
-
|
|
4487
|
+
|
|
4209
4488
|
// Call original oninit function, if one was passed in the config
|
|
4210
4489
|
var callback;
|
|
4211
4490
|
try {
|
|
@@ -4220,167 +4499,44 @@ $.fn.gridEditor.locales = {
|
|
|
4220
4499
|
// The editor owns what is inside the
|
|
4221
4500
|
// content area now, so the grid editor is
|
|
4222
4501
|
// told to put its own furniture back
|
|
4223
|
-
|
|
4224
|
-
|
|
4502
|
+
ge.textReady(contentArea);
|
|
4503
|
+
|
|
4225
4504
|
contentArea.summernote('focus');
|
|
4226
4505
|
}
|
|
4227
4506
|
}
|
|
4228
4507
|
}
|
|
4229
4508
|
);
|
|
4230
4509
|
contentArea.summernote(configuration);
|
|
4231
|
-
}
|
|
4232
|
-
}
|
|
4233
|
-
},
|
|
4234
|
-
|
|
4235
|
-
deinit: function(settings, contentAreas) {
|
|
4236
|
-
contentAreas.filter('.active').each(function() {
|
|
4237
|
-
var contentArea = $(this);
|
|
4238
|
-
contentArea.summernote('destroy');
|
|
4239
|
-
contentArea
|
|
4240
|
-
.removeClass('active')
|
|
4241
|
-
.removeAttr('id')
|
|
4242
|
-
.removeAttr('style')
|
|
4243
|
-
.removeAttr('spellcheck')
|
|
4244
|
-
;
|
|
4245
|
-
});
|
|
4246
|
-
},
|
|
4510
|
+
});
|
|
4511
|
+
},
|
|
4247
4512
|
|
|
4248
|
-
|
|
4513
|
+
stop: function(contentAreas) {
|
|
4514
|
+
contentAreas.filter('.active').each(function() {
|
|
4515
|
+
var contentArea = $(this);
|
|
4516
|
+
contentArea.summernote('destroy');
|
|
4517
|
+
contentArea
|
|
4518
|
+
.removeClass('active')
|
|
4519
|
+
.removeAttr('id')
|
|
4520
|
+
.removeAttr('style')
|
|
4521
|
+
.removeAttr('spellcheck')
|
|
4522
|
+
;
|
|
4523
|
+
});
|
|
4524
|
+
},
|
|
4525
|
+
};
|
|
4249
4526
|
};
|
|
4250
4527
|
})(jQuery);
|
|
4251
4528
|
|
|
4529
|
+
/**
|
|
4530
|
+
* Up to 6.0 the main bundle carries a copy of each text editor plugin, so a
|
|
4531
|
+
* page that loaded only the editor keeps the editor it had. This marks those
|
|
4532
|
+
* copies, and the editor warns once when a content area is edited with one:
|
|
4533
|
+
* 6.0 leaves them out. Loaded on its own, a plugin's file registers itself
|
|
4534
|
+
* again, unmarked, and is the one used.
|
|
4535
|
+
*
|
|
4536
|
+
* Only ever concatenated after the plugins it marks, never built on its own.
|
|
4537
|
+
*/
|
|
4252
4538
|
(function($) {
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
// to keep the grid editor's own class and tinyMCE's leftovers off the element.
|
|
4257
|
-
function cleanUp(contentArea) {
|
|
4258
|
-
contentArea
|
|
4259
|
-
.removeClass('active')
|
|
4260
|
-
.removeClass('ge-rte-active')
|
|
4261
|
-
.removeAttr('id')
|
|
4262
|
-
.removeAttr('style')
|
|
4263
|
-
.removeAttr('spellcheck')
|
|
4264
|
-
.removeAttr('contenteditable')
|
|
4265
|
-
.removeAttr('data-mce-style')
|
|
4266
|
-
;
|
|
4267
|
-
}
|
|
4268
|
-
|
|
4269
|
-
$.fn.gridEditor.RTEs.tinymce = {
|
|
4270
|
-
|
|
4271
|
-
init: function(settings, contentAreas) {
|
|
4272
|
-
|
|
4273
|
-
if (!window.tinymce) {
|
|
4274
|
-
console.error($.fn.gridEditor.t(settings, 'error.tinymce_missing'));
|
|
4275
|
-
return;
|
|
4276
|
-
}
|
|
4277
|
-
|
|
4278
|
-
var self = this;
|
|
4279
|
-
var userConfig = (settings.tinymce && settings.tinymce.config) ? settings.tinymce.config : {};
|
|
4280
|
-
|
|
4281
|
-
contentAreas.each(function() {
|
|
4282
|
-
var contentArea = $(this);
|
|
4283
|
-
if (contentArea.hasClass('active')) { return; }
|
|
4284
|
-
|
|
4285
|
-
if (contentArea.html() == self.initialContent) {
|
|
4286
|
-
contentArea.html('');
|
|
4287
|
-
}
|
|
4288
|
-
contentArea.addClass('active');
|
|
4289
|
-
|
|
4290
|
-
var configuration = $.extend({
|
|
4291
|
-
// tinyMCE's own "Upgrade" badge in the menubar. Off by
|
|
4292
|
-
// default because an inline editor here is a column of
|
|
4293
|
-
// someone's page, not tinyMCE's own interface; a host that
|
|
4294
|
-
// wants it back passes promotion: true.
|
|
4295
|
-
promotion: false,
|
|
4296
|
-
}, userConfig, {
|
|
4297
|
-
target: this,
|
|
4298
|
-
inline: true,
|
|
4299
|
-
init_instance_callback: function(editor) {
|
|
4300
|
-
// deinit ran before this init finished, so tear it down again
|
|
4301
|
-
if (contentArea.data('ge-tinymce-pending-remove')) {
|
|
4302
|
-
contentArea.removeData('ge-tinymce-pending-remove');
|
|
4303
|
-
editor.remove();
|
|
4304
|
-
// deinit already ran and cannot clean up after this
|
|
4305
|
-
// late remove(), so do it here instead
|
|
4306
|
-
cleanUp(contentArea);
|
|
4307
|
-
return;
|
|
4308
|
-
}
|
|
4309
|
-
|
|
4310
|
-
contentArea.data('ge-tinymce', editor);
|
|
4311
|
-
|
|
4312
|
-
// The editor rewrote what is inside this content area
|
|
4313
|
-
// while it took it over, so whatever the grid editor
|
|
4314
|
-
// had in there is gone. Saying so lets it put its own
|
|
4315
|
-
// furniture back (see RTE_READY in the core).
|
|
4316
|
-
contentArea.trigger('ge-rte-ready');
|
|
4317
|
-
|
|
4318
|
-
// The inline toolbar is laid out against the element's
|
|
4319
|
-
// geometry at the moment tinyMCE draws it, and an
|
|
4320
|
-
// element that has just appeared - a tab pane, an
|
|
4321
|
-
// accordion body, a column whose width is still
|
|
4322
|
-
// settling - may not have its own width yet. Asking
|
|
4323
|
-
// for the ui again once the browser has laid the frame
|
|
4324
|
-
// out measures it as it now is, instead of leaving a
|
|
4325
|
-
// toolbar wrapped into a narrow column.
|
|
4326
|
-
window.requestAnimationFrame(function() {
|
|
4327
|
-
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
4328
|
-
|
|
4329
|
-
editor.ui.show();
|
|
4330
|
-
});
|
|
4331
|
-
|
|
4332
|
-
// And again whenever the user comes back to this
|
|
4333
|
-
// editor: by then the element may have been resized,
|
|
4334
|
-
// hidden and shown again - a tab switched away from
|
|
4335
|
-
// and back, a column made narrower - and the toolbar
|
|
4336
|
-
// is only ever as right as its last measurement.
|
|
4337
|
-
editor.on('focus', function() {
|
|
4338
|
-
window.requestAnimationFrame(function() {
|
|
4339
|
-
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
4340
|
-
|
|
4341
|
-
editor.ui.show();
|
|
4342
|
-
});
|
|
4343
|
-
});
|
|
4344
|
-
|
|
4345
|
-
// Bring focus to text field
|
|
4346
|
-
editor.focus();
|
|
4347
|
-
|
|
4348
|
-
// Call the original callbacks, if any were passed in the config
|
|
4349
|
-
if (userConfig.init_instance_callback) {
|
|
4350
|
-
userConfig.init_instance_callback.call(this, editor);
|
|
4351
|
-
}
|
|
4352
|
-
// 'oninit' is the pre-6 name, honoured so existing configs keep working
|
|
4353
|
-
if (userConfig.oninit) {
|
|
4354
|
-
userConfig.oninit.call(this, editor);
|
|
4355
|
-
}
|
|
4356
|
-
}
|
|
4357
|
-
});
|
|
4358
|
-
// We always edit the element we were handed, so a selector in the
|
|
4359
|
-
// user config would only fight with target
|
|
4360
|
-
delete configuration.selector;
|
|
4361
|
-
|
|
4362
|
-
window.tinymce.init(configuration);
|
|
4363
|
-
});
|
|
4364
|
-
},
|
|
4365
|
-
|
|
4366
|
-
deinit: function(settings, contentAreas) {
|
|
4367
|
-
contentAreas.filter('.active').each(function() {
|
|
4368
|
-
var contentArea = $(this);
|
|
4369
|
-
var editor = contentArea.data('ge-tinymce');
|
|
4370
|
-
|
|
4371
|
-
if (editor) {
|
|
4372
|
-
contentArea.removeData('ge-tinymce');
|
|
4373
|
-
editor.remove();
|
|
4374
|
-
} else {
|
|
4375
|
-
// tinymce.init() is asynchronous, so the editor may not exist
|
|
4376
|
-
// yet. Leave a note for init_instance_callback to remove it.
|
|
4377
|
-
contentArea.data('ge-tinymce-pending-remove', true);
|
|
4378
|
-
}
|
|
4379
|
-
|
|
4380
|
-
cleanUp(contentArea);
|
|
4381
|
-
});
|
|
4382
|
-
},
|
|
4383
|
-
|
|
4384
|
-
initialContent: '<p>Lorem ipsum dolores</p>',
|
|
4385
|
-
};
|
|
4539
|
+
['tinymce', 'ckeditor', 'summernote'].forEach(function(type) {
|
|
4540
|
+
if ($.fn.gridEditor.texts[type]) { $.fn.gridEditor.texts[type].bundled = true; }
|
|
4541
|
+
});
|
|
4386
4542
|
})(jQuery);
|