@themarioga/grid-editor 7.1.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +117 -19
  3. package/UPGRADING.md +72 -0
  4. package/dist/grideditor.bundle.min.js +3 -3
  5. package/dist/grideditor.css +102 -0
  6. package/dist/grideditor.d.ts +18 -0
  7. package/dist/grideditor.esm.js +292 -32
  8. package/dist/grideditor.js +292 -32
  9. package/dist/grideditor.min.css +1 -1
  10. package/dist/grideditor.min.css.map +1 -1
  11. package/dist/grideditor.min.js +2 -2
  12. package/dist/grideditor.min.js.map +3 -3
  13. package/dist/locales/grideditor.es.esm.js +70 -1
  14. package/dist/locales/grideditor.es.js +70 -1
  15. package/dist/locales/grideditor.es.min.js +1 -1
  16. package/dist/locales/grideditor.es.min.js.map +2 -2
  17. package/dist/plugins/grideditor.ckeditor.esm.js +123 -48
  18. package/dist/plugins/grideditor.ckeditor.js +123 -48
  19. package/dist/plugins/grideditor.ckeditor.min.js +1 -1
  20. package/dist/plugins/grideditor.ckeditor.min.js.map +3 -3
  21. package/dist/plugins/grideditor.float.esm.js +10 -1
  22. package/dist/plugins/grideditor.float.js +8 -2
  23. package/dist/plugins/grideditor.float.min.js +1 -1
  24. package/dist/plugins/grideditor.float.min.js.map +4 -4
  25. package/dist/plugins/grideditor.spacing.esm.js +12 -3
  26. package/dist/plugins/grideditor.spacing.js +9 -3
  27. package/dist/plugins/grideditor.spacing.min.js +1 -1
  28. package/dist/plugins/grideditor.spacing.min.js.map +4 -4
  29. package/dist/plugins/grideditor.style.esm.js +1593 -0
  30. package/dist/plugins/grideditor.style.js +1592 -0
  31. package/dist/plugins/grideditor.style.min.js +2 -0
  32. package/dist/plugins/grideditor.style.min.js.map +7 -0
  33. package/dist/plugins/grideditor.summernote.esm.js +1 -1
  34. package/dist/plugins/grideditor.summernote.js +1 -1
  35. package/dist/plugins/grideditor.summernote.min.js +1 -1
  36. package/dist/plugins/grideditor.summernote.min.js.map +2 -2
  37. package/dist/plugins/grideditor.textalign.esm.js +10 -1
  38. package/dist/plugins/grideditor.textalign.js +8 -2
  39. package/dist/plugins/grideditor.textalign.min.js +1 -1
  40. package/dist/plugins/grideditor.textalign.min.js.map +4 -4
  41. package/dist/plugins/grideditor.tinymce.esm.js +1 -1
  42. package/dist/plugins/grideditor.tinymce.js +1 -1
  43. package/dist/plugins/grideditor.tinymce.min.js +1 -1
  44. package/dist/plugins/grideditor.tinymce.min.js.map +2 -2
  45. package/dist/plugins/grideditor.visibility.esm.js +12 -3
  46. package/dist/plugins/grideditor.visibility.js +9 -3
  47. package/dist/plugins/grideditor.visibility.min.js +1 -1
  48. package/dist/plugins/grideditor.visibility.min.js.map +4 -4
  49. package/docs/locale-keys.md +89 -8
  50. package/docs/plugins.md +49 -5
  51. package/example/ckeditor.html +9 -4
  52. package/example/index.html +15 -1
  53. package/example/style.html +151 -0
  54. package/example/utilities.html +15 -11
  55. package/package.json +1 -1
  56. package/src/js/grideditor.js +366 -28
  57. package/src/js/locales/grideditor.es.js +70 -1
  58. package/src/js/plugins/grideditor.ckeditor.js +129 -65
  59. package/src/js/plugins/grideditor.float.js +8 -33
  60. package/src/js/plugins/grideditor.spacing.js +8 -273
  61. package/src/js/plugins/grideditor.style.js +179 -0
  62. package/src/js/plugins/grideditor.textalign.js +8 -39
  63. package/src/js/plugins/grideditor.visibility.js +8 -147
  64. package/src/js/style/accordion.js +157 -0
  65. package/src/js/style/catalog.js +76 -0
  66. package/src/js/style/custom.js +84 -0
  67. package/src/js/style/fields.js +382 -0
  68. package/src/js/style/float.js +46 -0
  69. package/src/js/style/options.js +75 -0
  70. package/src/js/style/sections.js +271 -0
  71. package/src/js/style/spacing.js +286 -0
  72. package/src/js/style/textalign.js +52 -0
  73. package/src/js/style/visibility.js +160 -0
  74. package/src/js/text/grideditor.text.js +1 -1
  75. package/src/less/grideditor.less +111 -0
  76. package/types/grideditor.d.ts +18 -0
@@ -160,6 +160,73 @@ GridEditor.locales.es = {
160
160
  'utility.float_end': 'Fin',
161
161
  'utility.float_none': 'Ninguno',
162
162
  'utility.spacing_gutter': 'El relleno lateral de una columna es su espaciado: cambiarlo cambia el espacio entre columnas',
163
+ 'style.section_title': 'Estilo',
164
+ 'style.dialog_title': 'Estilo: {kind}',
165
+ 'style.section_size': 'Tamaño',
166
+ 'style.section_spacing': 'Espaciado',
167
+ 'style.section_border': 'Borde',
168
+ 'style.section_background': 'Fondo',
169
+ 'style.section_text': 'Texto',
170
+ 'style.section_typography': 'Tipografía',
171
+ 'style.section_display': 'Visualización',
172
+ 'style.section_position': 'Posición',
173
+ 'style.section_custom': 'CSS libre',
174
+ 'style.all_sizes': 'Se aplica a todos los tamaños',
175
+ 'style.overridden': 'La clase {class} tiene prioridad sobre este valor',
176
+ 'style.invalid': 'Esta propiedad no acepta ese valor',
177
+ 'style.catalog': 'Clases de Bootstrap',
178
+ 'style.shadow_x': 'X',
179
+ 'style.shadow_y': 'Y',
180
+ 'style.shadow_blur': 'Desenfoque',
181
+ 'style.shadow_spread': 'Extensión',
182
+ 'style.shadow_color': 'Color',
183
+ 'style.shadow_inset': 'Interior',
184
+ 'style.shadow_text_mode': 'Editar como texto',
185
+ 'style.prop_width': 'Ancho',
186
+ 'style.prop_height': 'Alto',
187
+ 'style.prop_min_width': 'Ancho mínimo',
188
+ 'style.prop_min_height': 'Alto mínimo',
189
+ 'style.prop_max_width': 'Ancho máximo',
190
+ 'style.prop_max_height': 'Alto máximo',
191
+ 'style.prop_margin_top': 'Margen superior',
192
+ 'style.prop_margin_right': 'Margen derecho',
193
+ 'style.prop_margin_bottom': 'Margen inferior',
194
+ 'style.prop_margin_left': 'Margen izquierdo',
195
+ 'style.prop_padding_top': 'Relleno superior',
196
+ 'style.prop_padding_right': 'Relleno derecho',
197
+ 'style.prop_padding_bottom': 'Relleno inferior',
198
+ 'style.prop_padding_left': 'Relleno izquierdo',
199
+ 'style.prop_border_width': 'Grosor del borde',
200
+ 'style.prop_border_style': 'Estilo del borde',
201
+ 'style.prop_border_color': 'Color del borde',
202
+ 'style.prop_border_radius': 'Radio del borde',
203
+ 'style.prop_box_shadow': 'Sombra',
204
+ 'style.prop_background_color': 'Color de fondo',
205
+ 'style.prop_background_image': 'Imagen de fondo',
206
+ 'style.prop_background_size': 'Tamaño del fondo',
207
+ 'style.prop_background_position': 'Posición del fondo',
208
+ 'style.prop_background_repeat': 'Repetición del fondo',
209
+ 'style.prop_color': 'Color',
210
+ 'style.prop_font_size': 'Tamaño de letra',
211
+ 'style.prop_text_align': 'Alineación',
212
+ 'style.prop_text_shadow': 'Sombra del texto',
213
+ 'style.prop_font_family': 'Fuente',
214
+ 'style.prop_font_weight': 'Grosor de letra',
215
+ 'style.prop_font_style': 'Estilo de letra',
216
+ 'style.prop_line_height': 'Interlineado',
217
+ 'style.prop_letter_spacing': 'Espaciado entre letras',
218
+ 'style.prop_text_transform': 'Mayúsculas',
219
+ 'style.prop_text_decoration': 'Decoración',
220
+ 'style.prop_display': 'Display',
221
+ 'style.prop_opacity': 'Opacidad',
222
+ 'style.prop_overflow': 'Desbordamiento',
223
+ 'style.prop_visibility': 'Visibilidad',
224
+ 'style.prop_position': 'Posición',
225
+ 'style.prop_top': 'Arriba',
226
+ 'style.prop_right': 'Derecha',
227
+ 'style.prop_bottom': 'Abajo',
228
+ 'style.prop_left': 'Izquierda',
229
+ 'style.prop_z_index': 'Z-index',
163
230
  'error.sortable_missing': '¡SortableJS no está disponible! Asegúrate de haber cargado el archivo js de Sortable; sin él no se puede arrastrar.',
164
231
  'warning.setting_removed': 'El ajuste {setting} se eliminó en la 4.0. Usa {replacement} en su lugar.',
165
232
  'warning.already_editing': 'Este elemento ya tiene un editor: se devuelve ese, con las opciones con las que se creó.',
@@ -169,7 +236,9 @@ GridEditor.locales.es = {
169
236
  '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
237
  'warning.oninit_removed': 'La opción oninit de tinyMCE se eliminó en la 7.0 y se ignora: usa init_instance_callback.',
171
238
  '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 el archivo js de CKEditor.',
239
+ 'error.ckeditor_missing': '¡CKEditor 5 no está disponible! Asegúrate de haber cargado su archivo ckeditor5.umd.js: CKEditor 4 ya no está soportado.',
240
+ 'error.ckeditor_start': 'CKEditor no ha podido arrancar: {message}',
241
+ 'warning.ckeditor_plugin': 'CKEditor no tiene ningún plugin llamado {name}, así que se deja fuera.',
173
242
  '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
243
  'error.summernote_missing': '¡Summernote no está disponible! Asegúrate de haber cargado jQuery y el archivo js de Summernote.',
175
244
  };
@@ -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 4
5
- * after or before it, and a text of the ckeditor type is edited with an
6
- * inline CKEditor. What it can ask the editor for is the handle its
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
- * <script src="ckeditor/ckeditor.js"></script>
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
- // The instance each content area is edited with, as this file made it
30
- var instances = new WeakMap();
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
- * The instance editing this content area. Kept when it is made, and
36
- * looked for among CKEditor's own as a fallback, since an instance made
37
- * by another copy of this file is not in this one's record.
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 instanceOf(contentArea) {
40
- var kept = instances.get(contentArea);
41
- if (kept) { return kept; }
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
- return found;
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
- available: function() { return !!window.CKEDITOR; },
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
- // CKEditor kills this '&nbsp' creating a non usable box :/
67
- contentArea.innerHTML = '&nbsp;';
119
+ contentArea.innerHTML = '';
68
120
  }
69
-
70
- // contenteditable="true", or CKEditor loads readonly
71
121
  dom.addClass(contentArea, 'active');
72
- contentArea.setAttribute('contenteditable', 'true');
73
-
74
- var configuration = Object.assign(
75
- {},
76
- (settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
77
- {
78
- // Focus editor on creation
79
- on: {
80
- instanceReady: function( evt ) {
81
- // Call original instanceReady function, if one was passed in the config
82
- var callback;
83
- try {
84
- callback = settings.ckeditor.config.on.instanceReady;
85
- } catch (err) {
86
- // No callback passed
87
- }
88
- if (callback) {
89
- callback.call(this, evt);
90
- }
91
-
92
- // The editor owns what is inside the
93
- // content area now, so the grid editor is
94
- // told to put its own furniture back
95
- ge.textReady(contentArea);
96
-
97
- instance.focus();
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
- var instance = window.CKEDITOR.inline(contentArea, configuration);
103
- instances.set(contentArea, instance);
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 instance, and no other: up to 5.x
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 instance = window.CKEDITOR ? instanceOf(contentArea) : null;
115
- if (instance) { instance.destroy(); }
116
- instances.delete(contentArea);
117
-
118
- // Cleanup
119
- dom.removeClass(contentArea, 'active cke_focus');
120
- ['id', 'style', 'spellcheck', 'contenteditable'].forEach(function(name) {
121
- contentArea.removeAttribute(name);
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
  };
@@ -14,41 +14,16 @@
14
14
  *
15
15
  * Elements only. A floated row or column stops being part of the grid, and a
16
16
  * container sits beside the content areas rather than in their text.
17
+ *
18
+ * Deprecated since 7.3, and gone in 8.0: grideditor.style.js carries this
19
+ * plugin's families, and edits them in its own sections. This file is that
20
+ * part on its own, as it was, and says so once per editor. Loaded beside
21
+ * the style plugin, it stands down.
17
22
  */
18
23
  import { GridEditor } from '../grideditor.js';
19
-
20
- Object.assign(GridEditor.locales.en, {
21
- 'utility.float': 'Float',
22
- 'utility.float_start': 'Start',
23
- 'utility.float_end': 'End',
24
- 'utility.float_none': 'None',
25
- });
26
-
27
- /** Start and end are left and right: Bootstrap's css is left to right. */
28
- var CSS = { start: 'left', end: 'right', none: 'none' };
24
+ import { floatPart } from '../style/float.js';
29
25
 
30
26
  GridEditor.utilities.float = function(ge) {
31
-
32
- function label(value) {
33
- if (value === 'start') { return ge.t('utility.float_start'); }
34
- if (value === 'end') { return ge.t('utility.float_end'); }
35
-
36
- return ge.t('utility.float_none');
37
- }
38
-
39
- return {
40
- families: [{
41
- name: 'float',
42
- prefix: 'float',
43
- values: ['start', 'end', 'none'],
44
- appliesTo: ['element'],
45
- labelKey: 'utility.float',
46
- label: label,
47
-
48
- /** With no class applying here, whatever the host's css floats it as. */
49
- preview: function(value, node) {
50
- return { float: value === null ? ge.bareStyle(node, 'float', 'float') : CSS[value] };
51
- },
52
- }],
53
- };
27
+ ge.warn('the "float" plugin is deprecated and will be removed in 8.0: load grideditor.style.js');
28
+ return floatPart(ge);
54
29
  };