@themarioga/grid-editor 7.1.0 → 7.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/CHANGELOG.md +22 -0
- package/README.md +34 -5
- package/UPGRADING.md +41 -0
- package/dist/grideditor.bundle.min.js +3 -3
- package/dist/grideditor.esm.js +2 -2
- package/dist/grideditor.js +2 -2
- package/dist/grideditor.min.js +2 -2
- package/dist/grideditor.min.js.map +2 -2
- package/dist/locales/grideditor.es.esm.js +3 -1
- package/dist/locales/grideditor.es.js +3 -1
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +2 -2
- package/dist/plugins/grideditor.ckeditor.esm.js +123 -48
- package/dist/plugins/grideditor.ckeditor.js +123 -48
- package/dist/plugins/grideditor.ckeditor.min.js +1 -1
- package/dist/plugins/grideditor.ckeditor.min.js.map +3 -3
- package/dist/plugins/grideditor.summernote.esm.js +1 -1
- package/dist/plugins/grideditor.summernote.js +1 -1
- package/dist/plugins/grideditor.summernote.min.js +1 -1
- package/dist/plugins/grideditor.summernote.min.js.map +2 -2
- package/dist/plugins/grideditor.tinymce.esm.js +1 -1
- package/dist/plugins/grideditor.tinymce.js +1 -1
- package/dist/plugins/grideditor.tinymce.min.js +1 -1
- package/dist/plugins/grideditor.tinymce.min.js.map +2 -2
- package/docs/locale-keys.md +3 -1
- package/example/ckeditor.html +9 -4
- package/example/index.html +1 -1
- package/package.json +1 -1
- package/src/js/grideditor.js +1 -1
- package/src/js/locales/grideditor.es.js +3 -1
- package/src/js/plugins/grideditor.ckeditor.js +129 -65
- package/src/js/text/grideditor.text.js +1 -1
package/example/ckeditor.html
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
<!-- Javascript dependencies -->
|
|
11
11
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
|
|
12
12
|
|
|
13
|
-
<!--
|
|
14
|
-
<
|
|
13
|
+
<!-- CKEditor 5: its browser build, and its stylesheet -->
|
|
14
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ckeditor5@48.5.2/dist/browser/ckeditor5.css">
|
|
15
|
+
<script src="https://cdn.jsdelivr.net/npm/ckeditor5@48.5.2/dist/browser/ckeditor5.umd.js"></script>
|
|
15
16
|
|
|
16
17
|
<!-- Grid editor CSS -->
|
|
17
18
|
<link rel="stylesheet" type="text/css" href="../dist/grideditor.css" />
|
|
@@ -28,11 +29,15 @@
|
|
|
28
29
|
new_row_layouts: [[12], [6, 6], [9, 3]],
|
|
29
30
|
content_types: ['ckeditor'],
|
|
30
31
|
ckeditor: {
|
|
32
|
+
// Anything InlineEditor.create takes, over the plugin's
|
|
33
|
+
// own defaults: its plugins, toolbar and headings
|
|
31
34
|
config: {
|
|
35
|
+
// CKEditor 5 is GPL-2.0-or-later: 'GPL' accepts that
|
|
36
|
+
// licence. A commercial licence passes its own key.
|
|
37
|
+
licenseKey: 'GPL',
|
|
32
38
|
on: {
|
|
33
39
|
instanceReady: function(evt) {
|
|
34
|
-
|
|
35
|
-
console.log('instance ready', evt, instance);
|
|
40
|
+
console.log('instance ready', evt.editor);
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
}
|
package/example/index.html
CHANGED
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
<strong>CKEditor</strong>
|
|
145
145
|
<code class="text-body-secondary">ckeditor.html</code>
|
|
146
146
|
</div>
|
|
147
|
-
<span class="text-body-secondary">CKEditor in the content areas instead of tinyMCE</span>
|
|
147
|
+
<span class="text-body-secondary">CKEditor 5 in the content areas instead of tinyMCE</span>
|
|
148
148
|
</a>
|
|
149
149
|
|
|
150
150
|
<a class="list-group-item list-group-item-action" href="summernote.html">
|
package/package.json
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"comment": "A scoped package publishes restricted unless it is told otherwise.",
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
|
-
"version": "7.
|
|
36
|
+
"version": "7.2.0",
|
|
37
37
|
"main": "dist/grideditor.js",
|
|
38
38
|
"module": "dist/grideditor.esm.js",
|
|
39
39
|
"types": "dist/grideditor.d.ts",
|
package/src/js/grideditor.js
CHANGED
|
@@ -5078,7 +5078,7 @@ GridEditor.locales = {
|
|
|
5078
5078
|
'warning.plugin_6x': 'The "{name}" plugin is written for grid-editor 6 and is not loaded. Plugins register on GridEditor since 7.0: see UPGRADING.md.',
|
|
5079
5079
|
'warning.adapter_no_jquery': 'grideditor.jquery.js needs jQuery 4, and there is no jQuery on the page: the jQuery API is not there.',
|
|
5080
5080
|
'error.tinymce_missing': 'tinyMCE not available! Make sure you loaded the tinyMCE js file.',
|
|
5081
|
-
'error.ckeditor_missing': 'CKEditor not available! Make sure you loaded
|
|
5081
|
+
'error.ckeditor_missing': 'CKEditor 5 not available! Make sure you loaded its ckeditor5.umd.js file: CKEditor 4 is no longer supported.',
|
|
5082
5082
|
'error.summernote_missing': 'Summernote not available! Make sure you loaded jQuery and the Summernote js file.',
|
|
5083
5083
|
},
|
|
5084
5084
|
};
|
|
@@ -169,7 +169,9 @@ GridEditor.locales.es = {
|
|
|
169
169
|
'warning.adapter_no_jquery': 'grideditor.jquery.js necesita jQuery 4 y la página no tiene jQuery: la API de jQuery no está disponible.',
|
|
170
170
|
'warning.oninit_removed': 'La opción oninit de tinyMCE se eliminó en la 7.0 y se ignora: usa init_instance_callback.',
|
|
171
171
|
'error.tinymce_missing': '¡tinyMCE no está disponible! Asegúrate de haber cargado el archivo js de tinyMCE.',
|
|
172
|
-
'error.ckeditor_missing': '¡CKEditor no está disponible! Asegúrate de haber cargado
|
|
172
|
+
'error.ckeditor_missing': '¡CKEditor 5 no está disponible! Asegúrate de haber cargado su archivo ckeditor5.umd.js: CKEditor 4 ya no está soportado.',
|
|
173
|
+
'error.ckeditor_start': 'CKEditor no ha podido arrancar: {message}',
|
|
174
|
+
'warning.ckeditor_plugin': 'CKEditor no tiene ningún plugin llamado {name}, así que se deja fuera.',
|
|
173
175
|
'error.codemirror_missing': '¡CodeMirror no está disponible! Asegúrate de haber cargado el archivo js de CodeMirror; sin él el código se edita en un textarea normal.',
|
|
174
176
|
'error.summernote_missing': '¡Summernote no está disponible! Asegúrate de haber cargado jQuery y el archivo js de Summernote.',
|
|
175
177
|
};
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CKEditor for grid-editor's content areas.
|
|
3
3
|
*
|
|
4
|
-
* A text editor plugin: load this file after the editor, and CKEditor
|
|
5
|
-
* after or before it, and a text of the ckeditor type is
|
|
6
|
-
* inline CKEditor. What it can ask the editor for is the
|
|
7
|
-
* factory is called with, described in docs/plugins.md.
|
|
4
|
+
* A text editor plugin: load this file after the editor, and CKEditor 5's
|
|
5
|
+
* browser build after or before it, and a text of the ckeditor type is
|
|
6
|
+
* edited with an inline CKEditor. What it can ask the editor for is the
|
|
7
|
+
* handle its factory is called with, described in docs/plugins.md.
|
|
8
8
|
*
|
|
9
|
-
* <
|
|
9
|
+
* <link rel="stylesheet" href="ckeditor5/ckeditor5.css">
|
|
10
|
+
* <script src="ckeditor5/ckeditor5.umd.js"></script>
|
|
10
11
|
* <script src="dist/grideditor.min.js"></script>
|
|
11
12
|
* <script src="dist/plugins/grideditor.ckeditor.min.js"></script>
|
|
12
13
|
*
|
|
14
|
+
* Up to 7.1 this was CKEditor 4, whose last open source release has known
|
|
15
|
+
* vulnerabilities and no fixes to come. CKEditor 5 asks for a licenseKey:
|
|
16
|
+
* 'GPL', or a commercial key, is the host's to pass in ckeditor.config.
|
|
17
|
+
*
|
|
13
18
|
* Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
|
|
14
19
|
* loaded on its own, like every plugin. It imports what every text editor
|
|
15
20
|
* shares - text blocks, the Text button, createText, making the host's plain
|
|
@@ -22,31 +27,77 @@ import '../text/grideditor.text.js';
|
|
|
22
27
|
|
|
23
28
|
Object.assign(GridEditor.locales.en, {
|
|
24
29
|
'text.ckeditor': 'CKEditor',
|
|
30
|
+
'error.ckeditor_start': 'CKEditor could not start: {message}',
|
|
31
|
+
'warning.ckeditor_plugin': 'CKEditor has no plugin called {name}, so it is left out.',
|
|
25
32
|
});
|
|
26
33
|
|
|
27
34
|
var INITIAL_CONTENT = '<p>Lorem initius... </p>';
|
|
28
35
|
|
|
29
|
-
//
|
|
30
|
-
|
|
36
|
+
// What CKEditor 5 is started with when the host's config does not say. It
|
|
37
|
+
// has no plugins of its own, so these are what a text can do: much what the
|
|
38
|
+
// CKEditor 4 build 7.1 used offered. Names, looked up on window.CKEDITOR.
|
|
39
|
+
var PLUGINS = [
|
|
40
|
+
'Essentials', 'Autoformat', 'Paragraph', 'Heading', 'Bold', 'Italic', 'Underline', 'Strikethrough',
|
|
41
|
+
'Link', 'AutoLink', 'List', 'BlockQuote', 'Indent', 'HorizontalLine', 'Table', 'TableToolbar',
|
|
42
|
+
'PasteFromOffice',
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
var DEFAULTS = {
|
|
46
|
+
toolbar: [
|
|
47
|
+
'undo', 'redo', '|', 'heading', '|', 'bold', 'italic', 'underline', 'strikethrough', '|',
|
|
48
|
+
'link', 'bulletedList', 'numberedList', 'blockQuote', '|', 'insertTable', 'horizontalLine',
|
|
49
|
+
],
|
|
50
|
+
// CKEditor's own headings start at h2, and make every h1 in the content
|
|
51
|
+
// an h2: a column's text keeps the headings it has
|
|
52
|
+
heading: {
|
|
53
|
+
options: [
|
|
54
|
+
{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
|
|
55
|
+
].concat([1, 2, 3, 4, 5, 6].map(function(level) {
|
|
56
|
+
return {
|
|
57
|
+
model: 'heading' + level, view: 'h' + level,
|
|
58
|
+
title: 'Heading ' + level, class: 'ck-heading_heading' + level,
|
|
59
|
+
};
|
|
60
|
+
})),
|
|
61
|
+
},
|
|
62
|
+
table: { contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells'] },
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// What this file keeps about a content area: its editor once it is ready,
|
|
66
|
+
// the start that is still to have one, and a promise of the content area
|
|
67
|
+
// being free again, with no editor starting or being destroyed on it:
|
|
68
|
+
// CKEditor does both asynchronously, and two at once on one element clash
|
|
69
|
+
var editors = new WeakMap();
|
|
70
|
+
var starting = new WeakMap();
|
|
71
|
+
var busy = new WeakMap();
|
|
72
|
+
|
|
73
|
+
/** The plugins the config names, as CKEditor wants them: constructors. */
|
|
74
|
+
function pluginsFor(ge, names) {
|
|
75
|
+
return names.map(function(plugin) {
|
|
76
|
+
if (typeof plugin !== 'string') { return plugin; }
|
|
77
|
+
if (!window.CKEDITOR[plugin]) { ge.warn(ge.t('warning.ckeditor_plugin', { name: plugin })); }
|
|
78
|
+
return window.CKEDITOR[plugin];
|
|
79
|
+
}).filter(Boolean);
|
|
80
|
+
}
|
|
31
81
|
|
|
32
82
|
GridEditor.texts.ckeditor = function(ge) {
|
|
33
83
|
|
|
34
84
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
85
|
+
* Take the editor off a content area and leave its content behind, now:
|
|
86
|
+
* getHtml reads the content area the moment its editor is stopped.
|
|
87
|
+
*
|
|
88
|
+
* CKEditor puts the attributes back as destroy() is called, but its
|
|
89
|
+
* content only as it finishes, and then as nothing: it empties the
|
|
90
|
+
* element unless told otherwise. So the content goes back in twice, now
|
|
91
|
+
* and once CKEditor is done. The promise is of that.
|
|
38
92
|
*/
|
|
39
|
-
function
|
|
40
|
-
var
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
var found = null;
|
|
44
|
-
Object.keys(window.CKEDITOR.instances).forEach(function(name) {
|
|
45
|
-
var instance = window.CKEDITOR.instances[name];
|
|
46
|
-
if (instance.element && instance.element.$ === contentArea) { found = instance; }
|
|
93
|
+
function destroy(contentArea, editor) {
|
|
94
|
+
var data = editor.getData();
|
|
95
|
+
var done = editor.destroy().catch(function() {}).then(function() {
|
|
96
|
+
contentArea.innerHTML = data;
|
|
47
97
|
});
|
|
48
98
|
|
|
49
|
-
|
|
99
|
+
contentArea.innerHTML = data;
|
|
100
|
+
return done;
|
|
50
101
|
}
|
|
51
102
|
|
|
52
103
|
return {
|
|
@@ -54,53 +105,67 @@ GridEditor.texts.ckeditor = function(ge) {
|
|
|
54
105
|
initialContent: INITIAL_CONTENT,
|
|
55
106
|
missingKey: 'error.ckeditor_missing',
|
|
56
107
|
|
|
57
|
-
|
|
108
|
+
// CKEditor 4 is window.CKEDITOR too, without an InlineEditor
|
|
109
|
+
available: function() { return !!(window.CKEDITOR && window.CKEDITOR.InlineEditor); },
|
|
58
110
|
|
|
59
111
|
start: function(contentAreas) {
|
|
60
112
|
var settings = ge.settings;
|
|
113
|
+
var userConfig = (settings.ckeditor && settings.ckeditor.config) ? settings.ckeditor.config : {};
|
|
61
114
|
|
|
62
115
|
contentAreas.forEach(function(contentArea) {
|
|
63
116
|
if (dom.hasClass(contentArea, 'active')) { return; }
|
|
64
117
|
|
|
65
118
|
if (contentArea.innerHTML == INITIAL_CONTENT) {
|
|
66
|
-
|
|
67
|
-
contentArea.innerHTML = ' ';
|
|
119
|
+
contentArea.innerHTML = '';
|
|
68
120
|
}
|
|
69
|
-
|
|
70
|
-
// contenteditable="true", or CKEditor loads readonly
|
|
71
121
|
dom.addClass(contentArea, 'active');
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
122
|
+
|
|
123
|
+
var configuration = Object.assign({}, DEFAULTS, userConfig);
|
|
124
|
+
configuration.plugins = pluginsFor(ge, userConfig.plugins || PLUGINS);
|
|
125
|
+
// on.instanceReady is CKEditor 4's, and CKEditor 5 has no
|
|
126
|
+
// such option: this file calls it, as it did in 7.1
|
|
127
|
+
delete configuration.on;
|
|
128
|
+
|
|
129
|
+
var ticket = {};
|
|
130
|
+
starting.set(contentArea, ticket);
|
|
131
|
+
|
|
132
|
+
var run = (busy.get(contentArea) || Promise.resolve()).then(function() {
|
|
133
|
+
// Stopped again while it waited for the last editor to go
|
|
134
|
+
if (starting.get(contentArea) !== ticket) { return null; }
|
|
135
|
+
|
|
136
|
+
return window.CKEDITOR.InlineEditor.create(contentArea, configuration);
|
|
137
|
+
}).then(function(editor) {
|
|
138
|
+
if (!editor) { return null; }
|
|
139
|
+
|
|
140
|
+
// Stopped while it started, so it goes again
|
|
141
|
+
if (starting.get(contentArea) !== ticket) {
|
|
142
|
+
return destroy(contentArea, editor);
|
|
143
|
+
}
|
|
144
|
+
starting.delete(contentArea);
|
|
145
|
+
editors.set(contentArea, editor);
|
|
146
|
+
|
|
147
|
+
// Call the original instanceReady function, if one was
|
|
148
|
+
// passed in the config: 7.1's, with CKEditor 4's event
|
|
149
|
+
var callback = userConfig.on && userConfig.on.instanceReady;
|
|
150
|
+
if (callback) {
|
|
151
|
+
callback.call(editor, { editor: editor });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// The editor owns what is inside the content area now,
|
|
155
|
+
// so the grid editor is told to put its own furniture back
|
|
156
|
+
ge.textReady(contentArea);
|
|
157
|
+
|
|
158
|
+
editor.editing.view.focus();
|
|
159
|
+
return null;
|
|
160
|
+
}).catch(function(error) {
|
|
161
|
+
// A licenseKey missing is the likely one
|
|
162
|
+
if (starting.get(contentArea) === ticket) {
|
|
163
|
+
starting.delete(contentArea);
|
|
164
|
+
dom.removeClass(contentArea, 'active');
|
|
100
165
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
166
|
+
console.error(ge.t('error.ckeditor_start', { message: (error && error.message) || error }));
|
|
167
|
+
});
|
|
168
|
+
busy.set(contentArea, run);
|
|
104
169
|
});
|
|
105
170
|
},
|
|
106
171
|
|
|
@@ -108,18 +173,17 @@ GridEditor.texts.ckeditor = function(ge) {
|
|
|
108
173
|
contentAreas.filter(function(contentArea) {
|
|
109
174
|
return dom.hasClass(contentArea, 'active');
|
|
110
175
|
}).forEach(function(contentArea) {
|
|
111
|
-
// This content area's
|
|
176
|
+
// This content area's editor, and no other: up to 5.x
|
|
112
177
|
// closing one content area destroyed every CKEditor on
|
|
113
178
|
// the page, other editors' and the host's own included
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
});
|
|
179
|
+
var editor = editors.get(contentArea);
|
|
180
|
+
editors.delete(contentArea);
|
|
181
|
+
// One still starting sees this and goes as it is ready
|
|
182
|
+
starting.delete(contentArea);
|
|
183
|
+
|
|
184
|
+
if (editor) { busy.set(contentArea, destroy(contentArea, editor)); }
|
|
185
|
+
|
|
186
|
+
dom.removeClass(contentArea, 'active');
|
|
123
187
|
});
|
|
124
188
|
},
|
|
125
189
|
};
|
|
@@ -40,7 +40,7 @@ if (!GridEditor.features.text) {
|
|
|
40
40
|
var readReady = new WeakMap();
|
|
41
41
|
|
|
42
42
|
/** What a text editor puts on a content area while it is open, whenever it likes. */
|
|
43
|
-
var EDITOR_CLASS = /^(mce-|cke|note-)|^(active|ge-rte-active)$/;
|
|
43
|
+
var EDITOR_CLASS = /^(mce-|cke|ck-|note-)|^(ck|active|ge-rte-active)$/;
|
|
44
44
|
var EDITOR_ATTRIBUTE = /^(data-mce-|contenteditable$|spellcheck$)/;
|
|
45
45
|
|
|
46
46
|
function attributesOf(element) {
|