@themarioga/grid-editor 6.0.0-beta.3 → 6.0.0-beta.5

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 (50) hide show
  1. package/BUILDING.md +3 -1
  2. package/CHANGELOG.md +74 -1
  3. package/README.md +71 -5
  4. package/UPGRADING.md +36 -7
  5. package/dist/grideditor.css +60 -0
  6. package/dist/grideditor.min.css +1 -1
  7. package/dist/grideditor.min.css.map +1 -1
  8. package/dist/jquery.grideditor.bundle.min.js +2 -2
  9. package/dist/jquery.grideditor.js +353 -402
  10. package/dist/jquery.grideditor.min.js +1 -1
  11. package/dist/jquery.grideditor.min.js.map +1 -1
  12. package/dist/locales/grideditor.es.js +7 -0
  13. package/dist/locales/grideditor.es.min.js +1 -1
  14. package/dist/locales/grideditor.es.min.js.map +1 -1
  15. package/dist/plugins/grideditor.ckeditor.js +397 -3
  16. package/dist/plugins/grideditor.ckeditor.min.js +1 -1
  17. package/dist/plugins/grideditor.ckeditor.min.js.map +1 -1
  18. package/dist/plugins/grideditor.codemirror-inline.js +190 -0
  19. package/dist/plugins/grideditor.codemirror-inline.min.js +2 -0
  20. package/dist/plugins/grideditor.codemirror-inline.min.js.map +1 -0
  21. package/dist/plugins/grideditor.codemirror.js +79 -0
  22. package/dist/plugins/grideditor.codemirror.min.js +2 -0
  23. package/dist/plugins/grideditor.codemirror.min.js.map +1 -0
  24. package/dist/plugins/grideditor.summernote.js +397 -3
  25. package/dist/plugins/grideditor.summernote.min.js +1 -1
  26. package/dist/plugins/grideditor.summernote.min.js.map +1 -1
  27. package/dist/plugins/grideditor.tinymce.js +397 -3
  28. package/dist/plugins/grideditor.tinymce.min.js +1 -1
  29. package/dist/plugins/grideditor.tinymce.min.js.map +1 -1
  30. package/dist/plugins/grideditor.visibility.js +1 -1
  31. package/dist/plugins/grideditor.visibility.min.js +1 -1
  32. package/dist/plugins/grideditor.visibility.min.js.map +1 -1
  33. package/docs/events.md +17 -2
  34. package/docs/locale-keys.md +25 -3
  35. package/docs/plugins.md +124 -46
  36. package/example/codemirror.html +103 -0
  37. package/example/custom_editor.html +193 -0
  38. package/example/index.html +16 -0
  39. package/example/wrap_content.html +5 -3
  40. package/package.json +1 -1
  41. package/src/js/jquery.grideditor.js +353 -402
  42. package/src/js/locales/grideditor.es.js +7 -0
  43. package/src/js/plugins/grideditor.ckeditor.js +7 -3
  44. package/src/js/plugins/grideditor.codemirror-inline.js +190 -0
  45. package/src/js/plugins/grideditor.codemirror.js +79 -0
  46. package/src/js/plugins/grideditor.summernote.js +7 -3
  47. package/src/js/plugins/grideditor.tinymce.js +7 -3
  48. package/src/js/plugins/grideditor.visibility.js +1 -1
  49. package/src/js/text/grideditor.text.js +389 -0
  50. package/src/less/grideditor.less +71 -0
package/docs/plugins.md CHANGED
@@ -14,15 +14,18 @@ the one to read first if you are about to write your own.
14
14
  <script src="dist/plugins/grideditor.elements.min.js"></script>
15
15
  ```
16
16
 
17
- There are four kinds. A **container plugin** builds a type of container — it
17
+ There are three kinds. A **container plugin** builds a type of container — it
18
18
  registers under `$.fn.gridEditor.containers`, and the toolbar offers a button
19
19
  for it. A **utility plugin** declares families of Bootstrap's responsive
20
20
  utility classes — `$.fn.gridEditor.utilities` — and the editor edits them per
21
- breakpoint. A **text editor plugin** edits content areas with a rich text
22
- editor — `$.fn.gridEditor.texts`, one per editor: tinyMCE, CKEditor,
23
- summernote. A **feature plugin** is anything else the editor can do —
21
+ breakpoint. A **feature plugin** is anything else the editor can do —
24
22
  `$.fn.gridEditor.features`, hooks into the canvas, and may contribute methods.
25
- All four are factories called once per editor with the same handle.
23
+ All three are factories called once per editor with the same handle.
24
+
25
+ Text is a feature plugin too. The core knows the grid and the host's *plain
26
+ content* - the markup it found that is not the grid's - and nothing of text:
27
+ the text editors, tinyMCE, CKEditor and summernote, are plugins, and so is an
28
+ editor a host writes itself. See [Text](#text).
26
29
 
27
30
  The `plugins` setting names which of the loaded ones to use:
28
31
 
@@ -60,6 +63,7 @@ $.fn.gridEditor.containers.carousel = function(ge) {
60
63
 
61
64
  return {
62
65
  labelKey: 'container.add_carousel', // the toolbar button's label
66
+ iconClass: 'bi bi-images', // optional: the button shows it in place of the label
63
67
  addPaneKey: 'container.add_slide', // the drawer's add pane tool
64
68
  paneKind: 'slide', // the kind its panes report
65
69
 
@@ -77,6 +81,9 @@ $.fn.gridEditor.containers.carousel = function(ge) {
77
81
  })(jQuery);
78
82
  ```
79
83
 
84
+ - **`iconClass`**, when given, is the toolbar button's face: the icon alone,
85
+ with the label as its title. Without one the button shows a plus and the
86
+ label.
80
87
  - **`create(options)`** returns a detached container. It must carry
81
88
  `data-ge-container="<type>"`: that attribute, and never a class, is how the
82
89
  editor recognises one.
@@ -129,6 +136,9 @@ not change without a major version.
129
136
  | `ge.rowFromLayout(layout)` | A detached row from a layout: `[8, 4]`, `['auto', 'equal']` or `{ row_cols, columns }` |
130
137
  | `ge.drawerOf(node)` | A node's drawer: its first child, or for a content area the one beside it in its text block |
131
138
  | `ge.textReady(block)` | A text editor has rewritten a content area: whatever the editor and its plugins put in there goes back in |
139
+ | `ge.attachPicker(tool, open)` | Hold a tool, or rest the pointer on it, and `open` is called: how a tool offers a choice |
140
+ | `ge.openPicker(anchor, choices, className?)` | The choice itself, as a strip under `anchor`: one button per `{ label, title, attributes, choose }` |
141
+ | `ge.closePicker()` | Close it; true when one was open, which is also a click's answer |
132
142
  | `ge.nodeHtml(node)` | One node's markup as `getHtml` would give it. The canvas leaves editing to read it and comes back, as it does for `getHtml` |
133
143
  | `ge.toolbarItems(name)` | The toolbar buttons the feature plugin `name` declared, for showing and hiding them |
134
144
  | `ge.bareStyle(node, family, property)` | A css property's value on the node with none of the family's classes: what a preview shows when no class applies and that is not a constant |
@@ -150,7 +160,13 @@ $.fn.gridEditor.features.elements = function(ge) {
150
160
  kindOf: function(node) { … }, // what an event calls this node
151
161
  onInit: function() { … }, // every init: put the furniture in
152
162
  onDeinit: function() { … }, // every deinit: take it out again
163
+ onBeforeDeinit: function() { … }, // every deinit, before the drawers come off: close what you opened
164
+ onSourceOpen: function(textarea) { … }, // the source view opened: the canvas's html is in the textarea
165
+ onSourceClose: function(textarea) { … }, // and is closing: put what you edited back in the textarea
153
166
  onContentReady: function(area) { … }, // a rich text editor just took over, or rewrote a text
167
+ textTypes: function() { … }, // the text types this plugin edits, see "Text"
168
+ plainTools: function(drawer, block) { … }, // tools for the host's plain content, which has no drawerTools
169
+
154
170
  cuts: '[data-my-block]', // what cuts a text: a block of the column, never part of a text
155
171
  onSortable: function(sortable) { … }, // declare your own sortable lists
156
172
  blocks: '.ge-section', // more blocks the canvas and the columns move
@@ -211,10 +227,17 @@ animation for rows, columns, containers and elements, kept in a
211
227
 
212
228
  A node's drawer is built again on every `init`, so a tool reads the node
213
229
  rather than remembering anything about it.
214
- - A **`toolbar`** item can also have an `iconClass`, `bi bi-plus` otherwise,
230
+ - A **`toolbar`** item can also have an `iconClass`, which it shows alone,
231
+ with the label as its title, where one without shows a plus and the label;
215
232
  and a `source` for the add events, `tool` or `dragdrop` otherwise. With
216
233
  `align: 'end'` it goes on the right of the toolbar, beside the source and
217
- preview buttons, as its icon alone, with the label as its title.
234
+ preview buttons, always as an icon - `bi bi-plus` when it has none.
235
+ `label`, a string or a function called whenever the toolbar is built, stands
236
+ in for `labelKey` when the label takes parameters; `className` goes on the
237
+ button. With `inColumn: true` what it makes belongs in a column, as a
238
+ container or a text does: a click puts it in a row and a column of its own
239
+ at the end of the canvas, and a drop anywhere but in a column does the
240
+ same where it was dropped.
218
241
 
219
242
  - **`onSortable(sortable)`** is handed the function the editor makes all of its
220
243
  own lists with. A plugin describes a list; it never touches the drag toolkit
@@ -233,6 +256,17 @@ rather than remembering anything about it.
233
256
  Leaving `group` out makes a list that sorts only within itself, which is what
234
257
  a tab strip wants. Group names are scoped to the editor instance, so two
235
258
  editors on one page never drag into each other.
259
+ - **`onSourceOpen(textarea)`** and **`onSourceClose(textarea)`** are the
260
+ toolbar's source view: it opens with the canvas's html in the textarea, and
261
+ closing it makes the canvas of what is in the textarea then. A code editor
262
+ goes over the textarea on open and puts its value back in it on close, which
263
+ is all the codemirror plugin does; `destroy` with the source open closes it
264
+ first.
265
+ - **`plainTools(drawer, block)`** puts tools in the drawer of the host's plain
266
+ content, between move and delete. That drawer has no gear, so
267
+ `drawerTools` never runs for it: plain content gets no utility, no copy and
268
+ no host tool, only what a plugin gives it here - the codemirror-inline
269
+ plugin's </> tool.
236
270
  - **`methods`** are added to the instance handle. A method the editor
237
271
  documents but a plugin implements — `createElement` — warns and returns null
238
272
  when the plugin is not loaded.
@@ -257,53 +291,97 @@ plugin knows which of its parts move: the tabs plugin makes its strip sortable
257
291
  and puts the panes back in strip order in `afterPaneMove`.
258
292
 
259
293
 
260
- Text editor plugins
261
- -------------------
294
+ Text
295
+ ----
296
+
297
+ ### Plain content
298
+
299
+ What the editor finds in a column that is not the grid's - loose markup, the
300
+ page it was started on before it had a row - it wraps in a content area with
301
+ no type: the host's **plain content**, `<div class="ge-content">`. While
302
+ editing it is a block with a drawer of move and delete - and what a plugin's
303
+ `plainTools` add between them - and no gear; it is edited in the source, with
304
+ the toolbar's code button or the codemirror-inline plugin's </> tool, and
305
+ nothing in the editor makes a new one. `getHtml` saves it as it is, and it is plain
306
+ content again when the page comes back. Events call it `kind: 'plain'`.
262
307
 
263
- A text editor plugin edits content areas with a rich text editor. It is
264
- registered under the content type it edits - the name `content_types` uses -
265
- and the three that ship, `grideditor.tinymce.js`, `grideditor.ckeditor.js` and
266
- `grideditor.summernote.js`, are the ones to read:
308
+ A text is a content area with a type on it - `data-ge-content-type` and the
309
+ class `ge-content-type-<type>` - and belongs to the plugin that declares the
310
+ type. A text whose type no plugin declares is a block to move and delete, and
311
+ its drawer says no editor for it is loaded.
312
+
313
+ ### textTypes
314
+
315
+ A feature plugin that edits text declares its types, and that is all the
316
+ core asks of it:
267
317
 
268
318
  ```javascript
269
- $.fn.gridEditor.texts.mytext = function(ge) {
319
+ $.fn.gridEditor.features.mytext = function(ge) {
270
320
  return {
271
- labelKey: 'text.mytext', // its name, in the toolbar and the drawer, optional
272
- initialContent: '<p>Write here</p>', // what a new text holds
273
- missingKey: 'error.mytext_missing', // the error when the library is not loaded, optional
274
- available: function() { return !!window.MyText; }, // optional, true otherwise
275
-
276
- start: function(block) { … }, // open the editor on this content area
277
- stop: function(block) { … }, // close it, and leave the content area as it was
321
+ textTypes: function() {
322
+ return [{
323
+ type: 'mytext', // what data-ge-content-type says
324
+ label: 'My text', // what the choice of editor shows
325
+ available: function() { … }, // optional: false, and missingKey is logged instead
326
+ missingKey: 'error.mytext_missing', // optional
327
+ offered: true, // optional: false owns the type without offering it
328
+ edit: function(block) { … }, // the type is on it: take it over, open the editor
329
+ }];
330
+ },
278
331
  };
279
332
  };
280
333
  ```
281
334
 
282
- - **`start(block)`** is called when the user clicks a content area of this
283
- type. The editor marks it `ge-rte-active` first, and does not call `start`
284
- again until it has been stopped. Once the library has taken the content
285
- area over, call **`ge.textReady(block)`**: it rewrote what was inside, and
286
- the editor and its plugins put their own furniture back - an element's
287
- drawer, for one. Call it again whenever the library rewrites the content
288
- area again, as tinyMCE's undo does.
289
- - **`stop(block)`** is called for every content area of this type on each
290
- `deinit`, which `getHtml` runs: a content area whose editor never started is
291
- the plugin's to ignore. Whatever the library and `start` added - classes,
292
- `contenteditable`, inline styles, ids - comes off here.
293
- - **`available()`** false and the editor logs `missingKey`'s message and
294
- starts nothing, without marking the content area, so a later click tries
295
- again once the library is there.
296
-
297
- A text editor is chosen by `content_types`, never by the `plugins` setting: a
298
- page that names its containers there has named no editor.
299
-
300
- Up to 5.x the main bundle carried a copy of the three shipped ones; since 6.0
301
- a page loads the plugin of the editor it uses, as it loads any other.
302
-
303
- 5.x's `$.fn.gridEditor.RTEs.mytext = { init, deinit, initialContent }` still
304
- works: `init(settings, contentAreas)` and `deinit(settings, contentAreas)` are
305
- wrapped as `start` and `stop`, with a warning that `RTEs` is deprecated. It goes
306
- in 7.0.
335
+ The core uses them three ways:
336
+
337
+ - **Whose a text is.** A content area of a type declared here is the plugin's:
338
+ the core wraps it in a `.ge-text-block` while editing, as it does plain
339
+ content, and leaves the drawer to the plugin - put one in on `onInit`. Two
340
+ plugins declaring one type: the first one registered has it, and the second
341
+ is warned about once.
342
+ - **What plain content can become.** A click on plain content, with one type
343
+ offered, makes it a text of that type; with several, it offers them, in the
344
+ order the plugins were registered. The core fires `before-convert`, which
345
+ can cancel it, puts the type on the content area - nothing else about it
346
+ changes - takes its plain drawer off, fires `after-convert` and calls
347
+ `edit(block)`. See [events.md](events.md).
348
+ - **What `createColumn(size, { content })` holds.** A text of the first type
349
+ offered, or plain content when there is none.
350
+
351
+ A plugin opens its editor on a click on its own texts - the core only handles
352
+ clicks on plain content - and closes it in `onBeforeDeinit`, which every
353
+ `deinit` runs while the drawers and the text blocks are still there, before
354
+ `getHtml` reads the markup. Whatever the editor put on the content area comes
355
+ off there.
356
+
357
+ ### The shipped text editors
358
+
359
+ `grideditor.tinymce.js`, `grideditor.ckeditor.js` and
360
+ `grideditor.summernote.js` each carry what text is to the editor - the text
361
+ block's drawer, the *Text* buttons in the toolbar and the *Add text* tool in
362
+ each column, `createText`, opening an editor on a click and closing it with
363
+ the host's attributes put back, and `textTypes` - from
364
+ `src/js/text/grideditor.text.js`, which the build puts at the top of each.
365
+ However many a page loads, that is installed once.
366
+
367
+ The editors offered are `content_types`, every one loaded by default, in the
368
+ order the page loaded them; the `plugins` setting does not choose them. A
369
+ text of an editor that is loaded but not offered is still edited.
370
+
371
+ ### A text editor of your own
372
+
373
+ A feature plugin with `textTypes`, a drawer for its texts, a toolbar item
374
+ with `inColumn: true` if it makes new ones, a click handler that opens its
375
+ editor, and `onBeforeDeinit` to close it.
376
+ [example/custom_editor.html](../example/custom_editor.html) is one, in full,
377
+ on the browser's `contenteditable`, on a page that loads none of the shipped
378
+ editors.
379
+
380
+ Up to 5.x an editor of a host's own registered under
381
+ `$.fn.gridEditor.RTEs`, and in 5.x and the 6.0 betas under
382
+ `$.fn.gridEditor.texts`. 6.0 removes the first - what is registered there is
383
+ ignored, with a warning - and `texts` is the shipped editors' own registry,
384
+ not a contract.
307
385
 
308
386
 
309
387
  Utility plugins
@@ -0,0 +1,103 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+
6
+ <!-- CSS dependencies -->
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.css">
9
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/codemirror@5.65.21/lib/codemirror.min.css">
10
+
11
+ <!-- Javascript dependencies -->
12
+ <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
13
+ <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>
14
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/6.8.6/tinymce.min.js"></script>
15
+
16
+ <!-- CodeMirror 5 and its html mode, which is made of the xml, javascript
17
+ and css modes -->
18
+ <script src="https://cdn.jsdelivr.net/npm/codemirror@5.65.21/lib/codemirror.min.js"></script>
19
+ <script src="https://cdn.jsdelivr.net/npm/codemirror@5.65.21/mode/xml/xml.min.js"></script>
20
+ <script src="https://cdn.jsdelivr.net/npm/codemirror@5.65.21/mode/javascript/javascript.min.js"></script>
21
+ <script src="https://cdn.jsdelivr.net/npm/codemirror@5.65.21/mode/css/css.min.js"></script>
22
+ <script src="https://cdn.jsdelivr.net/npm/codemirror@5.65.21/mode/htmlmixed/htmlmixed.min.js"></script>
23
+
24
+ <!-- Grid editor CSS -->
25
+ <link rel="stylesheet" type="text/css" href="../dist/grideditor.css" />
26
+ <!-- Grid editor javascript -->
27
+ <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
28
+ <script src="../dist/jquery.grideditor.min.js"></script>
29
+ <script src="../dist/plugins/grideditor.tinymce.min.js"></script>
30
+ <!-- The source view in CodeMirror, a plugin of its own -->
31
+ <script src="../dist/plugins/grideditor.codemirror.min.js"></script>
32
+ <!-- And each block's html, in place, from the </> tool in its drawer -->
33
+ <script src="../dist/plugins/grideditor.codemirror-inline.min.js"></script>
34
+
35
+ <script>
36
+ $(function() {
37
+ function start() {
38
+ if ($('#myGrid').data('grideditor')) { $('#myGrid').gridEditor('destroy'); }
39
+
40
+ $('#myGrid').gridEditor({
41
+ new_row_layouts: [[12], [6, 6], [4, 4, 4]],
42
+ // false leaves the toolbar's source button out
43
+ edit_source: $('#editSource').prop('checked'),
44
+ // Anything CodeMirror.fromTextArea takes, over the
45
+ // plugin's own defaults
46
+ codemirror: {
47
+ config: { lineNumbers: true },
48
+ },
49
+ });
50
+ }
51
+
52
+ $('#editSource').on('change', start);
53
+ start();
54
+ });
55
+ </script>
56
+
57
+ <title>Grid Editor example - the source in CodeMirror</title>
58
+ </head>
59
+ <body>
60
+ <!-- Back to the demo index -->
61
+ <div class="container pt-3">
62
+ <a class="link-secondary" href="index.html"><i class="bi bi-arrow-left"></i> All demos</a>
63
+ </div>
64
+
65
+ <div class="container py-3">
66
+ <h2>The source in CodeMirror</h2>
67
+ <p class="text-body-secondary">
68
+ The toolbar's <i class="bi bi-code-slash"></i> button turns the
69
+ canvas into its html, to edit by hand. With the codemirror plugin
70
+ loaded that html is in <a href="https://codemirror.net/5/">CodeMirror</a>,
71
+ highlighted and with line numbers, instead of a plain textarea; the
72
+ same button brings the canvas back with what you wrote.
73
+ <code>edit_source: false</code> leaves the button out.
74
+ </p>
75
+ <p class="text-body-secondary">
76
+ The codemirror-inline plugin puts a <i class="bi bi-code-slash"></i>
77
+ tool in the drawer of every row, column, text, element and
78
+ container, and of the page's plain content: it opens that block's
79
+ html, the block itself and all that is in it, in CodeMirror where
80
+ the block was. <em>Apply</em> puts what you wrote in its place.
81
+ </p>
82
+
83
+ <div class="form-check mb-3">
84
+ <input class="form-check-input" type="checkbox" id="editSource" checked>
85
+ <label class="form-check-label" for="editSource"><code>edit_source</code></label>
86
+ </div>
87
+
88
+ <div id="myGrid">
89
+ <div class="row">
90
+ <div class="col-lg-6">
91
+ <h3>Edit me as html</h3>
92
+ <p>Press the code button in the toolbar and this is CodeMirror.</p>
93
+ </div>
94
+ <div class="col-lg-6">
95
+ <div class="ge-content ge-content-type-tinymce" data-ge-content-type="tinymce">
96
+ <p>A text, saved as one: a click edits it in tinyMCE.</p>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </body>
103
+ </html>
@@ -0,0 +1,193 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+
6
+ <!-- CSS dependencies -->
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.css">
9
+
10
+ <!-- Javascript dependencies -->
11
+ <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
12
+ <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>
13
+
14
+ <!-- Grid editor CSS -->
15
+ <link rel="stylesheet" type="text/css" href="../dist/grideditor.css" />
16
+
17
+ <!-- The editor, and no text editor of the shipped ones: the one this page
18
+ edits text with is written below -->
19
+ <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.6/Sortable.min.js"></script>
20
+ <script src="../dist/jquery.grideditor.min.js"></script>
21
+
22
+ <!-- A text editor of the page's own. It is a feature plugin like any
23
+ other: the core knows nothing of text, and asks the plugins through
24
+ textTypes which types there are. This one edits with the browser's
25
+ own contenteditable. -->
26
+ <script id="simpletext-plugin">
27
+ (function($) {
28
+
29
+ $.extend($.fn.gridEditor.locales.en, {
30
+ 'simpletext.label': 'Simple text',
31
+ 'simpletext.add': 'Simple text',
32
+ });
33
+
34
+ var TYPE = 'simpletext';
35
+
36
+ $.fn.gridEditor.features.simpletext = function(ge) {
37
+
38
+ /** A content area of this plugin's: its type is on it. */
39
+ function isOurs(area) {
40
+ return area.attr('data-ge-content-type') === TYPE;
41
+ }
42
+
43
+ function start(area) {
44
+ if (area.hasClass('ge-rte-active')) { return; }
45
+
46
+ area.addClass('ge-rte-active').attr('contenteditable', 'true').trigger('focus');
47
+ }
48
+
49
+ // Whatever start put on the content area comes off: what is
50
+ // left is what getHtml saves
51
+ function stop(area) {
52
+ area.removeClass('ge-rte-active').removeAttr('contenteditable');
53
+ }
54
+
55
+ /**
56
+ * A text's drawer. The editor wraps each content area of a
57
+ * column in a .ge-text-block while editing, and leaves the
58
+ * drawer of a type a plugin declares to that plugin.
59
+ */
60
+ function createDrawer(textBlock) {
61
+ var area = textBlock.children('.ge-content');
62
+ var drawer = $('<div class="ge-tools-drawer ge-text-drawer" />').prependTo(textBlock);
63
+
64
+ ge.createMoveTool(drawer);
65
+ ge.createTool(drawer, ge.t('tool.delete_text'), 'ge-delete-text', 'bi bi-trash', function() {
66
+ ge.deleteNode('text', area, ge.t('confirm.delete_text'), function(removed) {
67
+ stop(area);
68
+ textBlock.slideUp(function() {
69
+ textBlock.remove();
70
+ removed();
71
+ });
72
+ });
73
+ });
74
+ }
75
+
76
+ function onClick() {
77
+ if (isOurs($(this))) { start($(this)); }
78
+ }
79
+
80
+ return {
81
+ // The types this plugin edits. The core uses them to know
82
+ // whose a content area is, and to offer them when the
83
+ // host's plain content is clicked: edit() is handed the
84
+ // content area once the core has written the type on it
85
+ textTypes: function() {
86
+ return [{
87
+ type: TYPE,
88
+ label: ge.t('simpletext.label'),
89
+ edit: function(area) {
90
+ var textBlock = area.parent('.ge-text-block');
91
+ if (textBlock.length && !textBlock.children('.ge-tools-drawer').length) {
92
+ createDrawer(textBlock);
93
+ }
94
+
95
+ start(area);
96
+ },
97
+ }];
98
+ },
99
+
100
+ // A button to make a new text, in a row of its own or
101
+ // where it is dropped in a column
102
+ toolbar: [{
103
+ labelKey: 'simpletext.add',
104
+ iconClass: 'bi bi-fonts',
105
+ kind: 'text',
106
+ inColumn: true,
107
+ create: function() {
108
+ return $('<div class="ge-content" />')
109
+ .addClass('ge-content-type-' + TYPE)
110
+ .attr('data-ge-content-type', TYPE)
111
+ .html('<p>Write here</p>');
112
+ },
113
+ }],
114
+
115
+ onInit: function() {
116
+ ge.canvas.find('.ge-text-block').each(function() {
117
+ var textBlock = $(this);
118
+ if (textBlock.children('.ge-tools-drawer').length) { return; }
119
+ if (isOurs(textBlock.children('.ge-content'))) { createDrawer(textBlock); }
120
+ });
121
+
122
+ ge.canvas.off('click.simpletext').on('click.simpletext', '.ge-content', onClick);
123
+ },
124
+
125
+ // Before the drawers and the text blocks come off
126
+ onBeforeDeinit: function() {
127
+ ge.canvas.find('.ge-content').each(function() {
128
+ if (isOurs($(this))) { stop($(this)); }
129
+ });
130
+ },
131
+
132
+ onDeinit: function() {
133
+ ge.canvas.off('click.simpletext');
134
+ },
135
+ };
136
+ };
137
+
138
+ })(jQuery);
139
+ </script>
140
+
141
+ <script>
142
+ $(function() {
143
+ $('#myGrid').gridEditor({
144
+ new_row_layouts: [[12], [6, 6], [4, 4, 4]],
145
+ });
146
+
147
+ $('#output').on('click', function() {
148
+ $('#html').text($('#myGrid').gridEditor('getHtml'));
149
+ });
150
+ });
151
+ </script>
152
+
153
+ <title>Grid Editor example - a text editor of your own</title>
154
+ </head>
155
+ <body>
156
+ <!-- Back to the demo index -->
157
+ <div class="container pt-3">
158
+ <a class="link-secondary" href="index.html"><i class="bi bi-arrow-left"></i> All demos</a>
159
+ </div>
160
+
161
+ <div class="container py-3">
162
+ <h2>A text editor of your own</h2>
163
+ <p class="text-body-secondary">
164
+ No tinyMCE, CKEditor or summernote on this page: its text editor is
165
+ the plugin in the page's source, a few dozen lines on the browser's
166
+ <code>contenteditable</code>. The markup below had no text editor's
167
+ type on it, so the editor took it for the host's <em>plain
168
+ content</em>: it can be moved and deleted, and a click makes it a
169
+ text of this editor. The second column was saved as one already.
170
+ See <a href="../docs/plugins.md">docs/plugins.md</a>.
171
+ </p>
172
+
173
+ <div id="myGrid">
174
+ <div class="row">
175
+ <div class="col-lg-6">
176
+ <h3>Plain content</h3>
177
+ <p>Loose markup of the page's own. Click it and it is a simple text.</p>
178
+ </div>
179
+ <div class="col-lg-6">
180
+ <div class="ge-content ge-content-type-simpletext" data-ge-content-type="simpletext">
181
+ <p>A simple text, saved as one: a click edits it.</p>
182
+ </div>
183
+ </div>
184
+ </div>
185
+ </div>
186
+
187
+ <p class="mt-4">
188
+ <button type="button" class="btn btn-outline-primary btn-sm" id="output">Show getHtml</button>
189
+ </p>
190
+ <pre class="bg-body-tertiary border rounded p-3 small"><code id="html"></code></pre>
191
+ </div>
192
+ </body>
193
+ </html>
@@ -61,6 +61,22 @@
61
61
  <span class="text-body-secondary">The plugin model, with a container plugin written in the page itself</span>
62
62
  </a>
63
63
 
64
+ <a class="list-group-item list-group-item-action" href="codemirror.html">
65
+ <div class="d-flex justify-content-between">
66
+ <strong>The source in CodeMirror</strong>
67
+ <code class="text-body-secondary">codemirror.html</code>
68
+ </div>
69
+ <span class="text-body-secondary">The source button's html in a code editor, and edit_source to leave the button out</span>
70
+ </a>
71
+
72
+ <a class="list-group-item list-group-item-action" href="custom_editor.html">
73
+ <div class="d-flex justify-content-between">
74
+ <strong>A text editor of your own</strong>
75
+ <code class="text-body-secondary">custom_editor.html</code>
76
+ </div>
77
+ <span class="text-body-secondary">No shipped text editor: one written in the page as a plugin, on the textTypes hook</span>
78
+ </a>
79
+
64
80
  <a class="list-group-item list-group-item-action" href="attributes.html">
65
81
  <div class="d-flex justify-content-between">
66
82
  <strong>A plugin with a modal</strong>
@@ -63,9 +63,11 @@
63
63
  <code>.col-*</code> anywhere. Grid editor does not refuse it: it
64
64
  wraps all of it into one row with a single
65
65
  <code>col-lg-12</code> column, and from there it is an ordinary
66
- grid. Add rows, split the column, edit the text, then press
67
- <em>Refresh</em> to see the html that comes out: as
68
- <code>getHtml</code> returns it, to save and edit again, and as
66
+ grid. What was in there is the page's <em>plain content</em>: a
67
+ block to move and delete, edited in the source, until a click
68
+ makes it a text of tinyMCE's. Add rows, split the column, edit the
69
+ text, then press <em>Refresh</em> to see the html that comes out:
70
+ as <code>getHtml</code> returns it, to save and edit again, and as
69
71
  <code>getPlainHtml</code> returns it, to publish.
70
72
  </p>
71
73
 
package/package.json CHANGED
@@ -34,7 +34,7 @@
34
34
  "comment": "A scoped package publishes restricted unless it is told otherwise.",
35
35
  "access": "public"
36
36
  },
37
- "version": "6.0.0-beta.3",
37
+ "version": "6.0.0-beta.5",
38
38
  "main": "dist/jquery.grideditor.js",
39
39
  "files": [
40
40
  "dist",