@themarioga/grid-editor 8.4.0 → 8.6.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 (105) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +105 -5
  3. package/dist/grideditor.bundle.min.js +3 -3
  4. package/dist/grideditor.css +15 -4
  5. package/dist/grideditor.d.ts +76 -4
  6. package/dist/grideditor.esm.js +212 -38
  7. package/dist/grideditor.js +212 -38
  8. package/dist/grideditor.min.css +1 -1
  9. package/dist/grideditor.min.css.map +1 -1
  10. package/dist/grideditor.min.js +2 -2
  11. package/dist/grideditor.min.js.map +3 -3
  12. package/dist/locales/grideditor.es.esm.js +5 -0
  13. package/dist/locales/grideditor.es.js +5 -0
  14. package/dist/locales/grideditor.es.min.js +1 -1
  15. package/dist/locales/grideditor.es.min.js.map +2 -2
  16. package/dist/plugins/grideditor.accordion.esm.js +7 -0
  17. package/dist/plugins/grideditor.accordion.js +7 -0
  18. package/dist/plugins/grideditor.accordion.min.js +1 -1
  19. package/dist/plugins/grideditor.accordion.min.js.map +3 -3
  20. package/dist/plugins/grideditor.autosave.esm.js +309 -0
  21. package/dist/plugins/grideditor.autosave.js +316 -0
  22. package/dist/plugins/grideditor.autosave.min.js +1 -0
  23. package/dist/plugins/grideditor.autosave.min.js.map +7 -0
  24. package/dist/plugins/grideditor.card.esm.js +10 -0
  25. package/dist/plugins/grideditor.card.js +10 -0
  26. package/dist/plugins/grideditor.card.min.js +1 -1
  27. package/dist/plugins/grideditor.card.min.js.map +3 -3
  28. package/dist/plugins/grideditor.ckeditor.esm.js +30 -1
  29. package/dist/plugins/grideditor.ckeditor.js +30 -1
  30. package/dist/plugins/grideditor.ckeditor.min.js +1 -1
  31. package/dist/plugins/grideditor.ckeditor.min.js.map +3 -3
  32. package/dist/plugins/grideditor.clipboard.esm.js +3 -0
  33. package/dist/plugins/grideditor.clipboard.js +3 -0
  34. package/dist/plugins/grideditor.clipboard.min.js +1 -1
  35. package/dist/plugins/grideditor.clipboard.min.js.map +2 -2
  36. package/dist/plugins/grideditor.codemirror-inline.esm.js +11 -0
  37. package/dist/plugins/grideditor.codemirror-inline.js +11 -0
  38. package/dist/plugins/grideditor.codemirror-inline.min.js +1 -1
  39. package/dist/plugins/grideditor.codemirror-inline.min.js.map +3 -3
  40. package/dist/plugins/grideditor.elements.esm.js +78 -4
  41. package/dist/plugins/grideditor.elements.js +78 -4
  42. package/dist/plugins/grideditor.elements.min.js +1 -1
  43. package/dist/plugins/grideditor.elements.min.js.map +3 -3
  44. package/dist/plugins/grideditor.gutters.esm.js +5 -0
  45. package/dist/plugins/grideditor.gutters.js +5 -0
  46. package/dist/plugins/grideditor.gutters.min.js +1 -1
  47. package/dist/plugins/grideditor.gutters.min.js.map +3 -3
  48. package/dist/plugins/grideditor.inline-style.esm.js +18 -10
  49. package/dist/plugins/grideditor.inline-style.js +18 -10
  50. package/dist/plugins/grideditor.inline-style.min.js +3 -3
  51. package/dist/plugins/grideditor.inline-style.min.js.map +3 -3
  52. package/dist/plugins/grideditor.order.esm.js +5 -0
  53. package/dist/plugins/grideditor.order.js +5 -0
  54. package/dist/plugins/grideditor.order.min.js +1 -1
  55. package/dist/plugins/grideditor.order.min.js.map +3 -3
  56. package/dist/plugins/grideditor.popup.esm.js +17 -6
  57. package/dist/plugins/grideditor.popup.js +17 -6
  58. package/dist/plugins/grideditor.popup.min.js +1 -1
  59. package/dist/plugins/grideditor.popup.min.js.map +3 -3
  60. package/dist/plugins/grideditor.sections.esm.js +6 -3
  61. package/dist/plugins/grideditor.sections.js +6 -3
  62. package/dist/plugins/grideditor.sections.min.js +1 -1
  63. package/dist/plugins/grideditor.sections.min.js.map +3 -3
  64. package/dist/plugins/grideditor.summernote.esm.js +40 -1
  65. package/dist/plugins/grideditor.summernote.js +40 -1
  66. package/dist/plugins/grideditor.summernote.min.js +1 -1
  67. package/dist/plugins/grideditor.summernote.min.js.map +3 -3
  68. package/dist/plugins/grideditor.tabs.esm.js +7 -0
  69. package/dist/plugins/grideditor.tabs.js +7 -0
  70. package/dist/plugins/grideditor.tabs.min.js +1 -1
  71. package/dist/plugins/grideditor.tabs.min.js.map +3 -3
  72. package/dist/plugins/grideditor.tinymce.esm.js +32 -1
  73. package/dist/plugins/grideditor.tinymce.js +32 -1
  74. package/dist/plugins/grideditor.tinymce.min.js +1 -1
  75. package/dist/plugins/grideditor.tinymce.min.js.map +3 -3
  76. package/docs/events.md +8 -0
  77. package/docs/locale-keys.md +16 -1
  78. package/docs/plugins.md +60 -7
  79. package/example/autosave.html +39 -22
  80. package/example/index.html +1 -1
  81. package/example/plugins.html +10 -0
  82. package/package.json +1 -2
  83. package/src/js/grideditor.js +248 -28
  84. package/src/js/inline-style/display.js +4 -3
  85. package/src/js/inline-style/drawerflow.js +10 -5
  86. package/src/js/locales/grideditor.es.js +5 -0
  87. package/src/js/plugins/grideditor.accordion.js +6 -0
  88. package/src/js/plugins/grideditor.autosave.js +349 -0
  89. package/src/js/plugins/grideditor.card.js +6 -0
  90. package/src/js/plugins/grideditor.ckeditor.js +6 -0
  91. package/src/js/plugins/grideditor.clipboard.js +3 -0
  92. package/src/js/plugins/grideditor.codemirror-inline.js +7 -0
  93. package/src/js/plugins/grideditor.elements.js +98 -4
  94. package/src/js/plugins/grideditor.gutters.js +4 -0
  95. package/src/js/plugins/grideditor.inline-style.js +2 -0
  96. package/src/js/plugins/grideditor.order.js +4 -0
  97. package/src/js/plugins/grideditor.popup.js +15 -6
  98. package/src/js/plugins/grideditor.sections.js +4 -3
  99. package/src/js/plugins/grideditor.summernote.js +14 -0
  100. package/src/js/plugins/grideditor.tabs.js +6 -0
  101. package/src/js/plugins/grideditor.tinymce.js +8 -0
  102. package/src/js/text/grideditor.text.js +27 -1
  103. package/src/less/grideditor.less +16 -8
  104. package/types/grideditor.d.ts +76 -4
  105. package/AUTO_SAVE.md +0 -30
@@ -140,6 +140,14 @@ GridEditor.texts.tinymce = function(ge) {
140
140
  });
141
141
  },
142
142
 
143
+ // What remove() leaves in the content area: tinyMCE writes its
144
+ // content back as it removes an inline editor. Null while it is
145
+ // still starting, when there is nothing to ask
146
+ read: function(contentArea) {
147
+ var editor = editors.get(contentArea);
148
+ return editor ? editor.getContent() : null;
149
+ },
150
+
143
151
  stop: function(contentAreas) {
144
152
  contentAreas.filter(function(contentArea) {
145
153
  return dom.hasClass(contentArea, 'active');
@@ -321,7 +321,7 @@ if (!GridEditor.features.text) {
321
321
  iconClass: TEXTS[type].iconClass,
322
322
  className: 'ge-add-text-button',
323
323
  kind: 'text',
324
- group: 'content',
324
+ group: 'elements',
325
325
  inColumn: true,
326
326
  create: function() { return makeText(type); },
327
327
  };
@@ -347,6 +347,32 @@ if (!GridEditor.features.text) {
347
347
  clicks = null;
348
348
  },
349
349
 
350
+ // What closing the editors does, on a copy of the canvas: each
351
+ // open text holds what its editor says it holds, and the
352
+ // attributes the host gave it, as closeText leaves them. An
353
+ // editor that cannot say - no read, or not started yet - and the
354
+ // canvas has to leave editing to be read
355
+ cleanMarkup: function(root, liveOf) {
356
+ var blocks = dom.all(root, '.ge-content.ge-rte-active').filter(isOurs);
357
+
358
+ for (var i = 0; i < blocks.length; i++) {
359
+ var copy = blocks[i];
360
+ var block = liveOf(copy);
361
+ var text = TEXTS[copy.getAttribute('data-ge-content-type')];
362
+ var before = block && readBefore.get(block);
363
+ var html = before && text.read ? text.read(block) : null;
364
+
365
+ if (typeof html !== 'string') { return false; }
366
+
367
+ dom.setHtml(copy, html);
368
+ restoreAttributes(copy, before, readReady.get(block) || before, attributesOf(block));
369
+ // What the editor put beside the content area, its frame
370
+ if (text.cleanCopy) { text.cleanCopy(copy, block); }
371
+ }
372
+
373
+ return true;
374
+ },
375
+
350
376
  // The first time only: an undo says ready again, and by then the
351
377
  // host may have changed the content area itself
352
378
  onContentReady: function(area) {
@@ -31,17 +31,25 @@
31
31
  top: 0;
32
32
  }
33
33
 
34
+ /* The add buttons on the left are grey, so the blue is left to the
35
+ source, preview and layout buttons on the right */
36
+ .ge-addRowGroup .btn.btn-light,
37
+ .ge-addContainerGroup .btn.btn-light,
38
+ .ge-toolbar-more > .btn.btn-light {
39
+ background: #f4f4f4;
40
+ color: @rowTextColor;
41
+ border-color: #999;
42
+
43
+ &:hover,
44
+ &:active {
45
+ background: #E3E3E3;
46
+ }
47
+ }
48
+
34
49
  .ge-addRowGroup {
35
- .btn.btn-primary {
36
- background: #f4f4f4;
37
- color: @rowTextColor;
38
- border-color: #999;
50
+ .btn.btn-light {
39
51
  display: flex;
40
52
  align-items: center;
41
-
42
- &:hover {
43
- background: #E3E3E3;
44
- }
45
53
  }
46
54
 
47
55
  .ge-row-icon {
@@ -125,7 +125,9 @@ export interface GridEditorOptions {
125
125
  inline_style?: InlineStyleOptions;
126
126
  /** The tabs plugin: the variant of the tabs containers made new. */
127
127
  tabs?: TabsOptions;
128
- elements?: { enabled?: boolean | 'auto'; selector?: string; auto?: boolean };
128
+ elements?: { enabled?: boolean | 'auto'; selector?: string; auto?: boolean; types?: ElementType[] };
129
+ /** The autosave plugin: what is edited, kept in the browser's storage as it changes. */
130
+ autosave?: AutosaveOptions;
129
131
  custom_filter?: CustomFilter | CustomFilter[] | '';
130
132
  valid_col_sizes?: ColumnSize[];
131
133
  valid_col_offsets?: number[];
@@ -151,6 +153,50 @@ export interface GridEditorOptions {
151
153
  [plugin: string]: unknown;
152
154
  }
153
155
 
156
+ /** The autosave plugin's options. */
157
+ export interface AutosaveOptions {
158
+ /** Saving from the start; the methods turn it on and off. Default true. */
159
+ enabled?: boolean;
160
+ /** localStorage or sessionStorage. Default 'local'. */
161
+ storage?: 'local' | 'session';
162
+ /** Where the draft is kept. Default 'grideditor.autosave:' + the page's path + '#' + the canvas's id. One per document on a page that loads several. */
163
+ key?: string | null;
164
+ /** Milliseconds after the last change. Default 1000. */
165
+ delay?: number;
166
+ /** Milliseconds a draft is offered for; null, the default, for ever. */
167
+ maxAge?: number | null;
168
+ }
169
+
170
+ /** A draft the autosave plugin kept. */
171
+ export interface AutosaveDraft {
172
+ html: string;
173
+ /** When, as an ISO 8601 date. */
174
+ savedAt: string;
175
+ }
176
+
177
+ export interface GetHtmlOptions {
178
+ /** Read the canvas without it leaving editing: open texts and settings panels stay open. */
179
+ keepEditing?: boolean;
180
+ }
181
+
182
+ export interface AutosavePayload {
183
+ canvas: HTMLElement;
184
+ html: string;
185
+ savedAt: string;
186
+ source: 'change' | 'pagehide' | 'api' | 'destroy';
187
+ }
188
+
189
+ export interface RestoreDraftPayload {
190
+ canvas: HTMLElement;
191
+ html: string;
192
+ savedAt: string;
193
+ }
194
+
195
+ export interface AutosaveErrorPayload {
196
+ canvas: HTMLElement;
197
+ error: unknown;
198
+ }
199
+
154
200
  /** Where a node was, or went: its parent and its index among the blocks there. */
155
201
  export interface Position {
156
202
  parent: HTMLElement;
@@ -271,6 +317,9 @@ export interface GridEditorEventMap {
271
317
  'grideditor:popup-orphan': PopupOrphanPayload;
272
318
  'grideditor:view-change': ViewChangePayload;
273
319
  'grideditor:target-change': TargetChangePayload;
320
+ 'grideditor:after-autosave': AutosavePayload;
321
+ 'grideditor:after-restore-draft': RestoreDraftPayload;
322
+ 'grideditor:autosave-error': AutosaveErrorPayload;
274
323
  }
275
324
 
276
325
  /** An event the editor dispatches on its canvas: a CustomEvent whose detail is the payload. */
@@ -286,6 +335,22 @@ export type GridEditorCallbacks = {
286
335
  };
287
336
 
288
337
  /** A plugin's factory: called once per editor with the handle in docs/plugins.md. */
338
+ /** An element the toolbar offers, from elements.types. */
339
+ export interface ElementType {
340
+ /** What it is: its data-ge-element. */
341
+ type: string;
342
+ /** Its markup: html, or a function called for each one made that returns html or a node. */
343
+ html: string | (() => string | Node);
344
+ /** Its button's label, as it is. */
345
+ label?: string;
346
+ /** Its button's label, a locale key: wins over label, and follows setLocale. */
347
+ labelKey?: string;
348
+ /** The button shows this icon alone, with the label as its title. */
349
+ iconClass?: string;
350
+ /** Its toolbar_groups category. Default 'elements'. */
351
+ group?: string;
352
+ }
353
+
289
354
  export type PluginFactory = ((ge: any) => Record<string, unknown>) & { always?: boolean };
290
355
 
291
356
  export interface CreateColumnOptions extends Placement {
@@ -346,10 +411,10 @@ export declare class GridEditor {
346
411
  /** A read-only copy of the settings the editor runs with. */
347
412
  readonly settings: Readonly<GridEditorOptions>;
348
413
 
349
- /** The html to save: no drawers, no editor classes, no inline styles. */
350
- getHtml(): string;
414
+ /** The html to save: no drawers, no editor classes, no inline styles. keepEditing reads it without the canvas leaving editing. */
415
+ getHtml(options?: GetHtmlOptions): string;
351
416
  /** getHtml without grid-editor's marking, for publishing. It cannot be edited again as it was. */
352
- getPlainHtml(): string;
417
+ getPlainHtml(options?: GetHtmlOptions): string;
353
418
  /** Run the editing pass over the canvas again, after markup was put in. */
354
419
  init(): this;
355
420
  /** Take the editing furniture off, leaving the markup. */
@@ -379,6 +444,13 @@ export declare class GridEditor {
379
444
  getUtility(node: Target, family: string, view?: View): string | null;
380
445
  /** Write one through the events; null is inherit. False when canceled or nothing changed. */
381
446
  setUtility(node: Target, family: string, value: string | number | null, view?: View): boolean;
447
+ /** The autosave plugin's, when it is loaded: false when the browser gives it no storage. */
448
+ enableAutosave?(): boolean;
449
+ disableAutosave?(): boolean;
450
+ /** Save now, if it changed: true when it was written. */
451
+ saveDraft?(): boolean;
452
+ getDraft?(): AutosaveDraft | null;
453
+ clearDraft?(): boolean;
382
454
  }
383
455
 
384
456
  export default GridEditor;
package/AUTO_SAVE.md DELETED
@@ -1,30 +0,0 @@
1
- ## Auto save and layout import/export
2
-
3
- The `example/autosave.html` demo shows how to add **auto save** and
4
- **import/export** on top of Grid Editor, using only the editor's public API
5
- (`getHtml()` and `destroy()` on the `GridEditor` instance).
6
-
7
- ### Features
8
-
9
- - **Auto save**
10
- Saves the layout to `localStorage` every 5 seconds, so work is not lost on
11
- an accidental refresh. The saved draft is restored on page load.
12
-
13
- - **Import a saved layout**
14
- Load a previously exported `.html` file back into the editor.
15
-
16
- - **Export HTML**
17
- Download the edited layout as an HTML file for saving or sharing.
18
-
19
- - **Clear draft**
20
- Remove the stored layout from `localStorage` and start over.
21
-
22
- ### Demo
23
-
24
- Build the `dist/` files first, then open the example:
25
-
26
- ```bash
27
- npm install
28
- npm run build
29
- open example/autosave.html
30
- ```