@themarioga/grid-editor 8.6.0 → 8.7.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/docs/plugins.md CHANGED
@@ -166,6 +166,7 @@ element, and where there may be several, an array.
166
166
  | `ge.snapshotHtml()` | The canvas's markup as `getHtml` gives it, read on a copy so the canvas never leaves editing: what `getHtml({ keepEditing: true })` is. See [Reading on a copy](#reading-on-a-copy) |
167
167
  | `ge.setHtml(html)` | The canvas made of other markup, and edited again: the source view closed if it is open, `deinit`, the markup in, `init`. No add or delete events: it is replaced as a whole. A `<script>` in it does not run in the editor |
168
168
  | `ge.confirm(message, options, answer)` | A question in the editor's confirm modal, the one deleting asks in. `options`: `title`, `ok`, `cancel` - the texts, the locale's by default - and `danger`, a red ok button. `answer(true)` for ok, `answer(false)` for cancel, the close button or Escape, `answer(null)` when the modal is taken away unanswered: `setLocale`, `destroy`, or another question. The browser's `confirm` without Bootstrap's javascript |
169
+ | `ge.refreshToolbar()` | The toolbar built again, from what the feature plugins' `toolbar`s hold now: for a plugin whose buttons come and go. The category shown with `toolbar_groups`, the preview and the source view stay as they are. Does nothing before the toolbar is first built, and after `destroy` |
169
170
  | `ge.toolbarItems(name)` | An array of the toolbar buttons the feature plugin `name` declared, for showing and hiding them |
170
171
  | `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 |
171
172
  | `ge.hostStyle(node, property?)` | `{ value, priority }` of one property of the node's own style, as the host wrote it: never a breakpoint preview's. With no property, the whole of it as css text |
@@ -231,6 +232,37 @@ needs to put a new kind of block on the canvas:
231
232
  was dropped, or, when that region will not have it, on the canvas just after
232
233
  the block it was dropped in. A `create()` that returns `null` adds nothing:
233
234
  that is how a plugin says it could not make one this time.
235
+ - **`toolbar`** can also be a function returning those items, called whenever
236
+ the toolbar is built - when the editor starts, on `setLocale`, and on
237
+ `ge.refreshToolbar()`. That is how a plugin offers buttons that change: a
238
+ user's saved widgets, each a button that adds it again. Change the list,
239
+ then call `ge.refreshToolbar()`. A button not yet built again still makes
240
+ what it was built from.
241
+
242
+ ```javascript
243
+ GridEditor.features.widgets = function(ge) {
244
+ var saved = loadWidgets(); // the plugin's own: wherever it keeps them
245
+ return {
246
+ methods: {
247
+ saveWidget: function(widget) {
248
+ saved.push(widget);
249
+ ge.refreshToolbar();
250
+ },
251
+ },
252
+ toolbar: function() {
253
+ return saved.map(function(widget) {
254
+ return {
255
+ label: widget.name,
256
+ kind: 'element',
257
+ group: 'widgets',
258
+ inColumn: true,
259
+ create: function() { return widgetFrom(widget.html); },
260
+ };
261
+ });
262
+ },
263
+ };
264
+ };
265
+ ```
234
266
 
235
267
  - **`drawerTools(drawer, node, kind)`** runs for every drawer that has a gear,
236
268
  as a utility plugin's does, so a tool can go on any node. The clipboard
package/package.json CHANGED
@@ -30,10 +30,9 @@
30
30
  },
31
31
  "homepage": "https://github.com/themarioga/grid-editor#readme",
32
32
  "publishConfig": {
33
- "comment": "A scoped package publishes restricted unless it is told otherwise.",
34
33
  "access": "public"
35
34
  },
36
- "version": "8.6.0",
35
+ "version": "8.7.0",
37
36
  "main": "dist/grideditor.js",
38
37
  "module": "dist/grideditor.esm.js",
39
38
  "types": "dist/grideditor.d.ts",
@@ -437,6 +437,7 @@ function build(instance, baseElem, optionsOrMethod) {
437
437
  var closeOverflowMenu = function() {}; // Folds the toolbar's overflow menu away, when it has one
438
438
  var refitToolbar = function() {}; // Works out again what the toolbar's overflow menu holds, when it has one
439
439
  var addButtons = []; // The toolbar's add buttons, in toolbar order: { button, home, group }
440
+ var shownToolbar = {}; // Each feature plugin's toolbar items, as the toolbar was last built with them
440
441
  var toolbarGroup = null; // The category shown, with toolbar_groups. Kept when the toolbar is rebuilt
441
442
  var warnedHere = {}; // Some warnings are worth saying once per instance, not once per call
442
443
  var sortables = []; // Every list made sortable, so deinit destroys exactly those
@@ -1189,8 +1190,10 @@ function build(instance, baseElem, optionsOrMethod) {
1189
1190
  // One with align 'end' goes on the right instead, as an icon,
1190
1191
  // beside the source and preview buttons.
1191
1192
  var endItems = [];
1193
+ shownToolbar = {};
1192
1194
  Object.keys(FEATURES).forEach(function(name) {
1193
- (FEATURES[name].toolbar || []).forEach(function(item, index) {
1195
+ shownToolbar[name] = toolbarOf(FEATURES[name]);
1196
+ shownToolbar[name].forEach(function(item, index) {
1194
1197
  var button = featureButton(name, item, index);
1195
1198
 
1196
1199
  if (item.align === 'end') {
@@ -1355,6 +1358,34 @@ function build(instance, baseElem, optionsOrMethod) {
1355
1358
  }
1356
1359
 
1357
1360
  /** The toolbar off the page, with what keeps its overflow menu up to date. */
1361
+ /** A feature plugin's toolbar items: its array, or what its function returns now. */
1362
+ function toolbarOf(feature) {
1363
+ var items = typeof feature.toolbar === 'function' ? feature.toolbar() : feature.toolbar;
1364
+ return Array.isArray(items) ? items : [];
1365
+ }
1366
+
1367
+ /**
1368
+ * ge.refreshToolbar(): the toolbar built again, from what the plugins'
1369
+ * toolbars hold now - a plugin whose buttons come and go calls it when
1370
+ * they have. The category shown, the preview and the source view stay
1371
+ * as they are; an open overflow menu folds away.
1372
+ */
1373
+ function refreshToolbar() {
1374
+ // Not built yet - the first one reads the toolbars as they are
1375
+ // then - or taken away for good
1376
+ if (!mainControls || destroyed) { return; }
1377
+
1378
+ var previewing = !!dom.one(mainControls, '.gm-preview.active');
1379
+
1380
+ removeMainControls();
1381
+ createMainControls();
1382
+
1383
+ if (previewing) {
1384
+ dom.addClass(dom.one(mainControls, '.gm-preview'), 'active btn-danger');
1385
+ }
1386
+ onScroll();
1387
+ }
1388
+
1358
1389
  function removeMainControls() {
1359
1390
  if (toolbarLifetime) { toolbarLifetime.abort(); }
1360
1391
  toolbarLifetime = null;
@@ -1655,7 +1686,10 @@ function build(instance, baseElem, optionsOrMethod) {
1655
1686
  * to the canvas, just after the top level block the pointer was in.
1656
1687
  */
1657
1688
  function insertFeatureFromToolbar(button, where, source) {
1658
- var item = FEATURES[button.getAttribute('data-ge-feature')].toolbar[parseInt(button.getAttribute('data-ge-item'), 10)];
1689
+ // The item the button was built from, whatever the plugin's list
1690
+ // says now: it may have changed since, and the toolbar not yet
1691
+ var item = (shownToolbar[button.getAttribute('data-ge-feature')] || [])[parseInt(button.getAttribute('data-ge-item'), 10)];
1692
+ if (!item) { return null; }
1659
1693
  var made = item.create();
1660
1694
  if (!made) { return null; }
1661
1695
  var placed = made;
@@ -2470,6 +2504,8 @@ function build(instance, baseElem, optionsOrMethod) {
2470
2504
  // A node's drawer: its first child, or for a content area the
2471
2505
  // one beside it in its text block
2472
2506
  drawerOf: drawerOf,
2507
+ // The toolbar built again, from the plugins' toolbars as they are now
2508
+ refreshToolbar: refreshToolbar,
2473
2509
  toolbarItems: function(name) {
2474
2510
  return mainControls
2475
2511
  ? dom.all(mainControls, '[data-ge-toolbar="feature"][data-ge-feature="' + name + '"]')