@themarioga/grid-editor 8.6.0 → 8.7.1
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 +21 -0
- package/README.md +1 -1
- package/dist/grideditor.bundle.min.js +3 -3
- package/dist/grideditor.esm.js +27 -3
- package/dist/grideditor.js +27 -3
- package/dist/grideditor.min.js +2 -2
- package/dist/grideditor.min.js.map +3 -3
- package/dist/plugins/grideditor.autosave.esm.js +15 -0
- package/dist/plugins/grideditor.autosave.js +15 -0
- package/dist/plugins/grideditor.autosave.min.js +1 -1
- package/dist/plugins/grideditor.autosave.min.js.map +2 -2
- package/docs/plugins.md +32 -0
- package/package.json +1 -2
- package/src/js/grideditor.js +38 -2
- package/src/js/plugins/grideditor.autosave.js +13 -0
|
@@ -297,11 +297,26 @@ GridEditor.features.autosave = function(ge) {
|
|
|
297
297
|
var found = readDraft(false);
|
|
298
298
|
return found ? { html: found.html, savedAt: found.savedAt } : null;
|
|
299
299
|
},
|
|
300
|
+
// What there is now is not a draft any more - a page calls this
|
|
301
|
+
// once it has saved to its server - so the save waiting does not
|
|
302
|
+
// write it back, and only a change from here makes a new draft
|
|
300
303
|
clearDraft: function() {
|
|
301
304
|
if (state === "unavailable") {
|
|
302
305
|
return false;
|
|
303
306
|
}
|
|
307
|
+
window.clearTimeout(timer);
|
|
308
|
+
timer = null;
|
|
304
309
|
remove();
|
|
310
|
+
if (base !== null && state !== "asking" && !sourceOpen) {
|
|
311
|
+
var watching = !!observer && state === "enabled";
|
|
312
|
+
if (watching) {
|
|
313
|
+
observer.disconnect();
|
|
314
|
+
}
|
|
315
|
+
last = ge.snapshotHtml();
|
|
316
|
+
if (watching) {
|
|
317
|
+
watch();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
305
320
|
return true;
|
|
306
321
|
}
|
|
307
322
|
}
|
|
@@ -303,11 +303,26 @@
|
|
|
303
303
|
var found = readDraft(false);
|
|
304
304
|
return found ? { html: found.html, savedAt: found.savedAt } : null;
|
|
305
305
|
},
|
|
306
|
+
// What there is now is not a draft any more - a page calls this
|
|
307
|
+
// once it has saved to its server - so the save waiting does not
|
|
308
|
+
// write it back, and only a change from here makes a new draft
|
|
306
309
|
clearDraft: function() {
|
|
307
310
|
if (state === "unavailable") {
|
|
308
311
|
return false;
|
|
309
312
|
}
|
|
313
|
+
window.clearTimeout(timer);
|
|
314
|
+
timer = null;
|
|
310
315
|
remove();
|
|
316
|
+
if (base !== null && state !== "asking" && !sourceOpen) {
|
|
317
|
+
var watching = !!observer && state === "enabled";
|
|
318
|
+
if (watching) {
|
|
319
|
+
observer.disconnect();
|
|
320
|
+
}
|
|
321
|
+
last = ge.snapshotHtml();
|
|
322
|
+
if (watching) {
|
|
323
|
+
watch();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
311
326
|
return true;
|
|
312
327
|
}
|
|
313
328
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{var
|
|
1
|
+
(()=>{var v=window.GridEditor;if(!v||typeof v.get!="function")throw new Error("grid-editor: load grideditor.js (or grideditor.bundle.min.js) before its plugins, its locales and grideditor.jquery.js");Object.assign(v.locales.en,{"autosave.restore_title":"Restore the draft?","autosave.restore_message":"There is a draft of this page saved on {date}, with changes that were not published. Restore it?","autosave.restore":"Restore","autosave.discard":"Discard"});var L=1,A={local:"localStorage",session:"sessionStorage"},k=1e3,D=new Set;function F(e){for(var s=2166136261,n=0;n<e.length;n++)s^=e.charCodeAt(n),s=Math.imul(s,16777619);return(s>>>0).toString(16).padStart(8,"0")}function G(e){return!!e&&typeof e=="object"&&e.version===L&&typeof e.html=="string"&&typeof e.base=="string"&&typeof e.savedAt=="string"&&!isNaN(Date.parse(e.savedAt))}v.features.autosave=function(e){var s=j(e.settings.autosave||{}),n=s.key||"grideditor.autosave:"+window.location.pathname+"#"+e.canvas.id,m=N(s.storage),r="disabled",p=!0,S=!1,u=null,f=null,d=null,l=null,o=null,h=!1,x=!1;m?D.has(n)?(e.warn('autosave: another editor on this page already saves to "'+n+'", so this one does not; give each its own autosave.key'),r="unavailable"):(D.add(n),s.enabled&&(r="enabled",u=E(!0))):(e.warn("autosave: the browser will not give this page its "+A[s.storage]+", so nothing is saved"),r="unavailable");function j(t){var a={enabled:t.enabled===void 0?!0:!!t.enabled,storage:t.storage===void 0?"local":t.storage,key:t.key===void 0?null:t.key,delay:t.delay===void 0?k:t.delay,maxAge:t.maxAge===void 0?null:t.maxAge};return A[a.storage]||(e.warn('autosave.storage "'+a.storage+'" is not local or session: local is used'),a.storage="local"),a.key!==null&&(typeof a.key!="string"||a.key==="")&&(e.warn("autosave.key must be a string: the page's own key is used"),a.key=null),(typeof a.delay!="number"||!Number.isInteger(a.delay)||a.delay<0)&&(e.warn("autosave.delay must be a whole number of milliseconds, 0 or more: "+k+" is used"),a.delay=k),a.maxAge!==null&&!(typeof a.maxAge=="number"&&isFinite(a.maxAge)&&a.maxAge>0)&&(e.warn("autosave.maxAge must be a number of milliseconds over 0, or null: drafts do not expire"),a.maxAge=null),a}function N(t){try{var a=window[A[t]];return a.getItem(n),a}catch(i){return null}}function E(t){var a;try{a=m.getItem(n)}catch(y){return null}if(a===null)return null;var i=null;try{i=JSON.parse(a)}catch(y){}return G(i)?t&&s.maxAge!==null&&Date.now()-Date.parse(i.savedAt)>s.maxAge?(b(),null):i:(t&&(e.warn('autosave: what is saved under "'+n+'" is not a draft this version can read: it is discarded'),b()),null)}function b(){try{m.removeItem(n)}catch(t){}}function w(t){if(window.clearTimeout(l),l=null,h||f===null)return!1;var a=!!o;a&&o.disconnect();var i=e.snapshotHtml();if(a&&c(),i===d)return!1;var y={version:L,html:i,savedAt:new Date().toISOString(),base:f};try{m.setItem(n,JSON.stringify(y))}catch(g){return x||(x=!0,e.warn("autosave: the draft could not be saved ("+(g&&g.message||g)+")")),e.emit("autosave-error",{canvas:e.canvas,error:g}),!1}return d=i,e.emit("after-autosave",{canvas:e.canvas,html:i,savedAt:y.savedAt,source:t}),!0}function H(){window.clearTimeout(l),l=window.setTimeout(function(){w("change")},s.delay)}function c(){o||(o=new MutationObserver(H)),o.observe(e.canvas,{subtree:!0,childList:!0,attributes:!0,characterData:!0})}function O(){window.clearTimeout(l),l=null,o&&o.disconnect()}function T(){r==="enabled"&&w("pagehide")}function R(){if(!(r==="destroyed"||r==="unavailable")){if(d=e.snapshotHtml(),f=F(d),window.addEventListener("pagehide",T),r==="enabled"&&u&&u.base===f&&u.html!==d){I(u);return}u=null,r==="enabled"&&c()}}function _(t){try{return new Date(t).toLocaleString(e.settings.locale||void 0)}catch(a){return new Date(t).toLocaleString()}}function I(t){r="asking",e.confirm(e.t("autosave.restore_message",{date:_(t.savedAt)}),{title:e.t("autosave.restore_title"),ok:e.t("autosave.restore"),cancel:e.t("autosave.discard")},function(a){if(r!=="destroyed"){if(a===null){window.setTimeout(function(){r==="asking"&&I(t)},0);return}u=null,a?(d=t.html,e.setHtml(t.html),e.emit("after-restore-draft",{canvas:e.canvas,html:t.html,savedAt:t.savedAt})):b(),r=p?"enabled":"disabled",r==="enabled"&&c()}})}return{onInit:function(){S||(S=!0,Promise.resolve().then(R))},onSourceOpen:function(){h=!0},onSourceClose:function(){h=!1},onDestroy:function(){r==="enabled"&&l&&w("destroy"),O(),o=null,window.removeEventListener("pagehide",T),r!=="unavailable"&&D.delete(n),r="destroyed"},methods:{enableAutosave:function(){return r==="unavailable"?!1:r==="asking"?(p=!0,!0):(r!=="enabled"&&(r="enabled",f!==null&&c()),!0)},disableAutosave:function(){return r==="unavailable"?!1:r==="asking"?(p=!1,!0):(O(),r="disabled",!0)},saveDraft:function(){return r==="unavailable"||r==="asking"?!1:w("api")},getDraft:function(){if(r==="unavailable")return null;var t=E(!1);return t?{html:t.html,savedAt:t.savedAt}:null},clearDraft:function(){if(r==="unavailable")return!1;if(window.clearTimeout(l),l=null,b(),f!==null&&r!=="asking"&&!h){var t=!!o&&r==="enabled";t&&o.disconnect(),d=e.snapshotHtml(),t&&c()}return!0}}}};})();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/js/register.js", "../../src/js/plugins/grideditor.autosave.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * What a plugin's or a locale's classic script imports in place of the\n * editor: the GridEditor the page already loaded.\n *\n * The build points `import { GridEditor } from '../grideditor.js'` here for\n * the classic scripts, so each registers on the editor the page has rather\n * than bringing its own. Loaded before the editor there is nothing to\n * register on, and saying so is better than a TypeError three calls later.\n */\nvar GridEditor = window.GridEditor;\n\nif (!GridEditor || typeof GridEditor.get !== 'function') {\n throw new Error('grid-editor: load grideditor.js (or grideditor.bundle.min.js) before its plugins, ' +\n 'its locales and grideditor.jquery.js');\n}\n\nexport { GridEditor };\nexport default GridEditor;\n", "/**\n * Autosave for grid-editor.\n *\n * A feature plugin: load this file after the editor and what is being edited\n * is kept in the browser's storage as it changes, and offered back the next\n * time an editor starts from the same html. What it can ask the editor for is\n * the handle its factory is called with, described in docs/plugins.md.\n *\n * <script src=\"dist/grideditor.min.js\"></script>\n * <script src=\"dist/plugins/grideditor.autosave.min.js\"></script>\n *\n * It reads the canvas with ge.snapshotHtml(), which leaves the canvas\n * editing: the text being typed into stays open, with its cursor. A save\n * comes `delay` ms after the last change, and when the page is left.\n *\n * A draft remembers the html its editor started from, and is only offered\n * to an editor that starts from the same html: a page that loads one\n * document after another is not offered one document's draft over another.\n * Such a page gives each document a key of its own, and each keeps its draft.\n *\n * new GridEditor('#myGrid', { autosave: { key: 'page-42', storage: 'session' } });\n */\nimport { GridEditor } from '../grideditor.js';\n\nObject.assign(GridEditor.locales.en, {\n 'autosave.restore_title': 'Restore the draft?',\n 'autosave.restore_message': 'There is a draft of this page saved on {date}, with changes that were not published. Restore it?',\n 'autosave.restore': 'Restore',\n 'autosave.discard': 'Discard',\n});\n\nvar VERSION = 1;\nvar STORAGES = { local: 'localStorage', session: 'sessionStorage' };\nvar DEFAULT_DELAY = 1000;\n\n/** The keys the editors on this page save to: one editor to a key. */\nvar liveKeys = new Set();\n\n/** FNV-1a, 32 bits, as hex: enough to tell one document's html from another's. */\nfunction fingerprint(text) {\n var hash = 0x811c9dc5;\n\n for (var i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n\n return (hash >>> 0).toString(16).padStart(8, '0');\n}\n\n/** A stored value that is a draft this file wrote, or null. */\nfunction validDraft(value) {\n return !!value && typeof value === 'object' && value.version === VERSION &&\n typeof value.html === 'string' && typeof value.base === 'string' &&\n typeof value.savedAt === 'string' && !isNaN(Date.parse(value.savedAt));\n}\n\nGridEditor.features.autosave = function(ge) {\n\n var options = optionsFrom(ge.settings.autosave || {});\n var key = options.key || 'grideditor.autosave:' + window.location.pathname + '#' + ge.canvas.id;\n var storage = storageFor(options.storage);\n\n // unavailable | disabled | asking | enabled | destroyed\n var state = 'disabled';\n var enabledAfterAsking = true; // What asking ends in: a method may have changed it meanwhile\n var started = false; // Whether the first init has been looked at\n var draft = null; // The draft found when the editor was made, while it may be offered\n var base = null; // The fingerprint of the html the editor started from\n var last = null; // The html saved last, or the one there was to start from\n var timer = null;\n var observer = null;\n var sourceOpen = false;\n var warnedWrite = false;\n\n if (!storage) {\n ge.warn('autosave: the browser will not give this page its ' + STORAGES[options.storage] +\n ', so nothing is saved');\n state = 'unavailable';\n } else if (liveKeys.has(key)) {\n ge.warn('autosave: another editor on this page already saves to \"' + key + '\", so this one does not; ' +\n 'give each its own autosave.key');\n state = 'unavailable';\n } else {\n liveKeys.add(key);\n if (options.enabled) {\n state = 'enabled';\n draft = readDraft(true);\n }\n }\n\n function optionsFrom(given) {\n var result = {\n enabled: given.enabled === undefined ? true : !!given.enabled,\n storage: given.storage === undefined ? 'local' : given.storage,\n key: given.key === undefined ? null : given.key,\n delay: given.delay === undefined ? DEFAULT_DELAY : given.delay,\n maxAge: given.maxAge === undefined ? null : given.maxAge,\n };\n\n if (!STORAGES[result.storage]) {\n ge.warn('autosave.storage \"' + result.storage + '\" is not local or session: local is used');\n result.storage = 'local';\n }\n if (result.key !== null && (typeof result.key !== 'string' || result.key === '')) {\n ge.warn('autosave.key must be a string: the page\\'s own key is used');\n result.key = null;\n }\n if (typeof result.delay !== 'number' || !Number.isInteger(result.delay) || result.delay < 0) {\n ge.warn('autosave.delay must be a whole number of milliseconds, 0 or more: ' + DEFAULT_DELAY + ' is used');\n result.delay = DEFAULT_DELAY;\n }\n if (result.maxAge !== null && !(typeof result.maxAge === 'number' && isFinite(result.maxAge) && result.maxAge > 0)) {\n ge.warn('autosave.maxAge must be a number of milliseconds over 0, or null: drafts do not expire');\n result.maxAge = null;\n }\n\n return result;\n }\n\n /** The storage, if the browser lets the page have it. */\n function storageFor(name) {\n try {\n var found = window[STORAGES[name]];\n found.getItem(key);\n return found;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * The draft saved under the key, or null. Starting, one that cannot be\n * read or has expired is taken away: nothing will ever offer it.\n */\n function readDraft(starting) {\n var raw;\n\n try {\n raw = storage.getItem(key);\n } catch (error) {\n return null;\n }\n if (raw === null) { return null; }\n\n var value = null;\n try { value = JSON.parse(raw); } catch (error) { /* not ours, or mangled */ }\n\n if (!validDraft(value)) {\n if (starting) {\n ge.warn('autosave: what is saved under \"' + key + '\" is not a draft this version can read: it is discarded');\n remove();\n }\n return null;\n }\n\n if (starting && options.maxAge !== null && Date.now() - Date.parse(value.savedAt) > options.maxAge) {\n remove();\n return null;\n }\n\n return value;\n }\n\n function remove() {\n try { storage.removeItem(key); } catch (error) { /* nothing to take away */ }\n }\n\n /** Write the canvas as it is, if it changed. True when it was written. */\n function save(source) {\n window.clearTimeout(timer);\n timer = null;\n\n if (sourceOpen || base === null) { return false; }\n\n // The read itself may change the canvas - getHtml, when a plugin\n // cannot be read on a copy - and that is not a change to save\n var watching = !!observer;\n if (watching) { observer.disconnect(); }\n var html = ge.snapshotHtml();\n if (watching) { watch(); }\n\n if (html === last) { return false; }\n\n var value = { version: VERSION, html: html, savedAt: new Date().toISOString(), base: base };\n\n try {\n storage.setItem(key, JSON.stringify(value));\n } catch (error) {\n if (!warnedWrite) {\n warnedWrite = true;\n ge.warn('autosave: the draft could not be saved (' + (error && error.message || error) + ')');\n }\n ge.emit('autosave-error', { canvas: ge.canvas, error: error });\n return false;\n }\n\n last = html;\n ge.emit('after-autosave', { canvas: ge.canvas, html: html, savedAt: value.savedAt, source: source });\n return true;\n }\n\n function schedule() {\n window.clearTimeout(timer);\n timer = window.setTimeout(function() { save('change'); }, options.delay);\n }\n\n function watch() {\n if (!observer) { observer = new MutationObserver(schedule); }\n observer.observe(ge.canvas, { subtree: true, childList: true, attributes: true, characterData: true });\n }\n\n function unwatch() {\n window.clearTimeout(timer);\n timer = null;\n if (observer) { observer.disconnect(); }\n }\n\n function onPageHide() {\n if (state === 'enabled') { save('pagehide'); }\n }\n\n /** After the first init has finished: what there is to start from, and the draft offered. */\n function start() {\n if (state === 'destroyed' || state === 'unavailable') { return; }\n\n last = ge.snapshotHtml();\n base = fingerprint(last);\n window.addEventListener('pagehide', onPageHide);\n\n // One of another document, or the same as what is there, is not offered\n if (state === 'enabled' && draft && draft.base === base && draft.html !== last) {\n ask(draft);\n return;\n }\n\n draft = null;\n if (state === 'enabled') { watch(); }\n }\n\n function dateOf(savedAt) {\n try {\n return new Date(savedAt).toLocaleString(ge.settings.locale || undefined);\n } catch (error) {\n return new Date(savedAt).toLocaleString();\n }\n }\n\n function ask(found) {\n state = 'asking';\n\n ge.confirm(ge.t('autosave.restore_message', { date: dateOf(found.savedAt) }), {\n title: ge.t('autosave.restore_title'),\n ok: ge.t('autosave.restore'),\n cancel: ge.t('autosave.discard'),\n }, function(restore) {\n if (state === 'destroyed') { return; }\n\n // Taken away unanswered - setLocale - so asked again, in the new\n // language, once the old modal is out of the way\n if (restore === null) {\n window.setTimeout(function() {\n if (state === 'asking') { ask(found); }\n }, 0);\n return;\n }\n\n draft = null;\n\n if (restore) {\n last = found.html;\n ge.setHtml(found.html);\n ge.emit('after-restore-draft', { canvas: ge.canvas, html: found.html, savedAt: found.savedAt });\n } else {\n remove();\n }\n\n state = enabledAfterAsking ? 'enabled' : 'disabled';\n if (state === 'enabled') { watch(); }\n });\n }\n\n return {\n // The first init, once it has finished: the canvas is ready to be read\n onInit: function() {\n if (started) { return; }\n started = true;\n Promise.resolve().then(start);\n },\n\n onSourceOpen: function() { sourceOpen = true; },\n onSourceClose: function() { sourceOpen = false; },\n\n onDestroy: function() {\n if (state === 'enabled' && timer) { save('destroy'); }\n\n unwatch();\n observer = null;\n window.removeEventListener('pagehide', onPageHide);\n if (state !== 'unavailable') { liveKeys.delete(key); }\n state = 'destroyed';\n },\n\n methods: {\n enableAutosave: function() {\n if (state === 'unavailable') { return false; }\n if (state === 'asking') {\n enabledAfterAsking = true;\n return true;\n }\n if (state !== 'enabled') {\n state = 'enabled';\n if (base !== null) { watch(); }\n }\n return true;\n },\n\n disableAutosave: function() {\n if (state === 'unavailable') { return false; }\n if (state === 'asking') {\n enabledAfterAsking = false;\n return true;\n }\n unwatch();\n state = 'disabled';\n return true;\n },\n\n saveDraft: function() {\n if (state === 'unavailable' || state === 'asking') { return false; }\n return save('api');\n },\n\n getDraft: function() {\n if (state === 'unavailable') { return null; }\n\n var found = readDraft(false);\n return found ? { html: found.html, savedAt: found.savedAt } : null;\n },\n\n clearDraft: function() {\n if (state === 'unavailable') { return false; }\n\n remove();\n return true;\n },\n },\n };\n};\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["/**\n * What a plugin's or a locale's classic script imports in place of the\n * editor: the GridEditor the page already loaded.\n *\n * The build points `import { GridEditor } from '../grideditor.js'` here for\n * the classic scripts, so each registers on the editor the page has rather\n * than bringing its own. Loaded before the editor there is nothing to\n * register on, and saying so is better than a TypeError three calls later.\n */\nvar GridEditor = window.GridEditor;\n\nif (!GridEditor || typeof GridEditor.get !== 'function') {\n throw new Error('grid-editor: load grideditor.js (or grideditor.bundle.min.js) before its plugins, ' +\n 'its locales and grideditor.jquery.js');\n}\n\nexport { GridEditor };\nexport default GridEditor;\n", "/**\n * Autosave for grid-editor.\n *\n * A feature plugin: load this file after the editor and what is being edited\n * is kept in the browser's storage as it changes, and offered back the next\n * time an editor starts from the same html. What it can ask the editor for is\n * the handle its factory is called with, described in docs/plugins.md.\n *\n * <script src=\"dist/grideditor.min.js\"></script>\n * <script src=\"dist/plugins/grideditor.autosave.min.js\"></script>\n *\n * It reads the canvas with ge.snapshotHtml(), which leaves the canvas\n * editing: the text being typed into stays open, with its cursor. A save\n * comes `delay` ms after the last change, and when the page is left.\n *\n * A draft remembers the html its editor started from, and is only offered\n * to an editor that starts from the same html: a page that loads one\n * document after another is not offered one document's draft over another.\n * Such a page gives each document a key of its own, and each keeps its draft.\n *\n * new GridEditor('#myGrid', { autosave: { key: 'page-42', storage: 'session' } });\n */\nimport { GridEditor } from '../grideditor.js';\n\nObject.assign(GridEditor.locales.en, {\n 'autosave.restore_title': 'Restore the draft?',\n 'autosave.restore_message': 'There is a draft of this page saved on {date}, with changes that were not published. Restore it?',\n 'autosave.restore': 'Restore',\n 'autosave.discard': 'Discard',\n});\n\nvar VERSION = 1;\nvar STORAGES = { local: 'localStorage', session: 'sessionStorage' };\nvar DEFAULT_DELAY = 1000;\n\n/** The keys the editors on this page save to: one editor to a key. */\nvar liveKeys = new Set();\n\n/** FNV-1a, 32 bits, as hex: enough to tell one document's html from another's. */\nfunction fingerprint(text) {\n var hash = 0x811c9dc5;\n\n for (var i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n\n return (hash >>> 0).toString(16).padStart(8, '0');\n}\n\n/** A stored value that is a draft this file wrote, or null. */\nfunction validDraft(value) {\n return !!value && typeof value === 'object' && value.version === VERSION &&\n typeof value.html === 'string' && typeof value.base === 'string' &&\n typeof value.savedAt === 'string' && !isNaN(Date.parse(value.savedAt));\n}\n\nGridEditor.features.autosave = function(ge) {\n\n var options = optionsFrom(ge.settings.autosave || {});\n var key = options.key || 'grideditor.autosave:' + window.location.pathname + '#' + ge.canvas.id;\n var storage = storageFor(options.storage);\n\n // unavailable | disabled | asking | enabled | destroyed\n var state = 'disabled';\n var enabledAfterAsking = true; // What asking ends in: a method may have changed it meanwhile\n var started = false; // Whether the first init has been looked at\n var draft = null; // The draft found when the editor was made, while it may be offered\n var base = null; // The fingerprint of the html the editor started from\n var last = null; // The html saved last, or the one there was to start from\n var timer = null;\n var observer = null;\n var sourceOpen = false;\n var warnedWrite = false;\n\n if (!storage) {\n ge.warn('autosave: the browser will not give this page its ' + STORAGES[options.storage] +\n ', so nothing is saved');\n state = 'unavailable';\n } else if (liveKeys.has(key)) {\n ge.warn('autosave: another editor on this page already saves to \"' + key + '\", so this one does not; ' +\n 'give each its own autosave.key');\n state = 'unavailable';\n } else {\n liveKeys.add(key);\n if (options.enabled) {\n state = 'enabled';\n draft = readDraft(true);\n }\n }\n\n function optionsFrom(given) {\n var result = {\n enabled: given.enabled === undefined ? true : !!given.enabled,\n storage: given.storage === undefined ? 'local' : given.storage,\n key: given.key === undefined ? null : given.key,\n delay: given.delay === undefined ? DEFAULT_DELAY : given.delay,\n maxAge: given.maxAge === undefined ? null : given.maxAge,\n };\n\n if (!STORAGES[result.storage]) {\n ge.warn('autosave.storage \"' + result.storage + '\" is not local or session: local is used');\n result.storage = 'local';\n }\n if (result.key !== null && (typeof result.key !== 'string' || result.key === '')) {\n ge.warn('autosave.key must be a string: the page\\'s own key is used');\n result.key = null;\n }\n if (typeof result.delay !== 'number' || !Number.isInteger(result.delay) || result.delay < 0) {\n ge.warn('autosave.delay must be a whole number of milliseconds, 0 or more: ' + DEFAULT_DELAY + ' is used');\n result.delay = DEFAULT_DELAY;\n }\n if (result.maxAge !== null && !(typeof result.maxAge === 'number' && isFinite(result.maxAge) && result.maxAge > 0)) {\n ge.warn('autosave.maxAge must be a number of milliseconds over 0, or null: drafts do not expire');\n result.maxAge = null;\n }\n\n return result;\n }\n\n /** The storage, if the browser lets the page have it. */\n function storageFor(name) {\n try {\n var found = window[STORAGES[name]];\n found.getItem(key);\n return found;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * The draft saved under the key, or null. Starting, one that cannot be\n * read or has expired is taken away: nothing will ever offer it.\n */\n function readDraft(starting) {\n var raw;\n\n try {\n raw = storage.getItem(key);\n } catch (error) {\n return null;\n }\n if (raw === null) { return null; }\n\n var value = null;\n try { value = JSON.parse(raw); } catch (error) { /* not ours, or mangled */ }\n\n if (!validDraft(value)) {\n if (starting) {\n ge.warn('autosave: what is saved under \"' + key + '\" is not a draft this version can read: it is discarded');\n remove();\n }\n return null;\n }\n\n if (starting && options.maxAge !== null && Date.now() - Date.parse(value.savedAt) > options.maxAge) {\n remove();\n return null;\n }\n\n return value;\n }\n\n function remove() {\n try { storage.removeItem(key); } catch (error) { /* nothing to take away */ }\n }\n\n /** Write the canvas as it is, if it changed. True when it was written. */\n function save(source) {\n window.clearTimeout(timer);\n timer = null;\n\n if (sourceOpen || base === null) { return false; }\n\n // The read itself may change the canvas - getHtml, when a plugin\n // cannot be read on a copy - and that is not a change to save\n var watching = !!observer;\n if (watching) { observer.disconnect(); }\n var html = ge.snapshotHtml();\n if (watching) { watch(); }\n\n if (html === last) { return false; }\n\n var value = { version: VERSION, html: html, savedAt: new Date().toISOString(), base: base };\n\n try {\n storage.setItem(key, JSON.stringify(value));\n } catch (error) {\n if (!warnedWrite) {\n warnedWrite = true;\n ge.warn('autosave: the draft could not be saved (' + (error && error.message || error) + ')');\n }\n ge.emit('autosave-error', { canvas: ge.canvas, error: error });\n return false;\n }\n\n last = html;\n ge.emit('after-autosave', { canvas: ge.canvas, html: html, savedAt: value.savedAt, source: source });\n return true;\n }\n\n function schedule() {\n window.clearTimeout(timer);\n timer = window.setTimeout(function() { save('change'); }, options.delay);\n }\n\n function watch() {\n if (!observer) { observer = new MutationObserver(schedule); }\n observer.observe(ge.canvas, { subtree: true, childList: true, attributes: true, characterData: true });\n }\n\n function unwatch() {\n window.clearTimeout(timer);\n timer = null;\n if (observer) { observer.disconnect(); }\n }\n\n function onPageHide() {\n if (state === 'enabled') { save('pagehide'); }\n }\n\n /** After the first init has finished: what there is to start from, and the draft offered. */\n function start() {\n if (state === 'destroyed' || state === 'unavailable') { return; }\n\n last = ge.snapshotHtml();\n base = fingerprint(last);\n window.addEventListener('pagehide', onPageHide);\n\n // One of another document, or the same as what is there, is not offered\n if (state === 'enabled' && draft && draft.base === base && draft.html !== last) {\n ask(draft);\n return;\n }\n\n draft = null;\n if (state === 'enabled') { watch(); }\n }\n\n function dateOf(savedAt) {\n try {\n return new Date(savedAt).toLocaleString(ge.settings.locale || undefined);\n } catch (error) {\n return new Date(savedAt).toLocaleString();\n }\n }\n\n function ask(found) {\n state = 'asking';\n\n ge.confirm(ge.t('autosave.restore_message', { date: dateOf(found.savedAt) }), {\n title: ge.t('autosave.restore_title'),\n ok: ge.t('autosave.restore'),\n cancel: ge.t('autosave.discard'),\n }, function(restore) {\n if (state === 'destroyed') { return; }\n\n // Taken away unanswered - setLocale - so asked again, in the new\n // language, once the old modal is out of the way\n if (restore === null) {\n window.setTimeout(function() {\n if (state === 'asking') { ask(found); }\n }, 0);\n return;\n }\n\n draft = null;\n\n if (restore) {\n last = found.html;\n ge.setHtml(found.html);\n ge.emit('after-restore-draft', { canvas: ge.canvas, html: found.html, savedAt: found.savedAt });\n } else {\n remove();\n }\n\n state = enabledAfterAsking ? 'enabled' : 'disabled';\n if (state === 'enabled') { watch(); }\n });\n }\n\n return {\n // The first init, once it has finished: the canvas is ready to be read\n onInit: function() {\n if (started) { return; }\n started = true;\n Promise.resolve().then(start);\n },\n\n onSourceOpen: function() { sourceOpen = true; },\n onSourceClose: function() { sourceOpen = false; },\n\n onDestroy: function() {\n if (state === 'enabled' && timer) { save('destroy'); }\n\n unwatch();\n observer = null;\n window.removeEventListener('pagehide', onPageHide);\n if (state !== 'unavailable') { liveKeys.delete(key); }\n state = 'destroyed';\n },\n\n methods: {\n enableAutosave: function() {\n if (state === 'unavailable') { return false; }\n if (state === 'asking') {\n enabledAfterAsking = true;\n return true;\n }\n if (state !== 'enabled') {\n state = 'enabled';\n if (base !== null) { watch(); }\n }\n return true;\n },\n\n disableAutosave: function() {\n if (state === 'unavailable') { return false; }\n if (state === 'asking') {\n enabledAfterAsking = false;\n return true;\n }\n unwatch();\n state = 'disabled';\n return true;\n },\n\n saveDraft: function() {\n if (state === 'unavailable' || state === 'asking') { return false; }\n return save('api');\n },\n\n getDraft: function() {\n if (state === 'unavailable') { return null; }\n\n var found = readDraft(false);\n return found ? { html: found.html, savedAt: found.savedAt } : null;\n },\n\n // What there is now is not a draft any more - a page calls this\n // once it has saved to its server - so the save waiting does not\n // write it back, and only a change from here makes a new draft\n clearDraft: function() {\n if (state === 'unavailable') { return false; }\n\n window.clearTimeout(timer);\n timer = null;\n remove();\n\n // Not while it asks: the canvas is not what was offered yet\n if (base !== null && state !== 'asking' && !sourceOpen) {\n var watching = !!observer && state === 'enabled';\n if (watching) { observer.disconnect(); }\n last = ge.snapshotHtml();\n if (watching) { watch(); }\n }\n return true;\n },\n },\n };\n};\n"],
|
|
5
|
+
"mappings": "MASA,IAAIA,EAAa,OAAO,WAExB,GAAI,CAACA,GAAc,OAAOA,EAAW,KAAQ,WACzC,MAAM,IAAI,MAAM,wHAC0B,ECW9C,OAAO,OAAOC,EAAW,QAAQ,GAAI,CACjC,yBAA0B,qBAC1B,2BAA4B,mGAC5B,mBAAoB,UACpB,mBAAoB,SACxB,CAAC,EAED,IAAIC,EAAU,EACVC,EAAW,CAAE,MAAO,eAAgB,QAAS,gBAAiB,EAC9DC,EAAgB,IAGhBC,EAAW,IAAI,IAGnB,SAASC,EAAYC,EAAM,CAGvB,QAFIC,EAAO,WAEFC,EAAI,EAAGA,EAAIF,EAAK,OAAQE,IAC7BD,GAAQD,EAAK,WAAWE,CAAC,EACzBD,EAAO,KAAK,KAAKA,EAAM,QAAU,EAGrC,OAAQA,IAAS,GAAG,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CACpD,CAGA,SAASE,EAAWC,EAAO,CACvB,MAAO,CAAC,CAACA,GAAS,OAAOA,GAAU,UAAYA,EAAM,UAAYT,GAC7D,OAAOS,EAAM,MAAS,UAAY,OAAOA,EAAM,MAAS,UACxD,OAAOA,EAAM,SAAY,UAAY,CAAC,MAAM,KAAK,MAAMA,EAAM,OAAO,CAAC,CAC7E,CAEAV,EAAW,SAAS,SAAW,SAASW,EAAI,CAExC,IAAIC,EAAUC,EAAYF,EAAG,SAAS,UAAY,CAAC,CAAC,EAChDG,EAAMF,EAAQ,KAAO,uBAAyB,OAAO,SAAS,SAAW,IAAMD,EAAG,OAAO,GACzFI,EAAUC,EAAWJ,EAAQ,OAAO,EAGpCK,EAAQ,WACRC,EAAqB,GACrBC,EAAU,GACVC,EAAQ,KACRC,EAAO,KACPC,EAAO,KACPC,EAAQ,KACRC,EAAW,KACXC,EAAa,GACbC,EAAc,GAEbX,EAIMX,EAAS,IAAIU,CAAG,GACvBH,EAAG,KAAK,2DAA6DG,EAAM,yDACvC,EACpCG,EAAQ,gBAERb,EAAS,IAAIU,CAAG,EACZF,EAAQ,UACRK,EAAQ,UACRG,EAAQO,EAAU,EAAI,KAX1BhB,EAAG,KAAK,qDAAuDT,EAASU,EAAQ,OAAO,EACnF,uBAAuB,EAC3BK,EAAQ,eAaZ,SAASJ,EAAYe,EAAO,CACxB,IAAIC,EAAS,CACT,QAASD,EAAM,UAAY,OAAY,GAAO,CAAC,CAACA,EAAM,QACtD,QAASA,EAAM,UAAY,OAAY,QAAUA,EAAM,QACvD,IAAKA,EAAM,MAAQ,OAAY,KAAOA,EAAM,IAC5C,MAAOA,EAAM,QAAU,OAAYzB,EAAgByB,EAAM,MACzD,OAAQA,EAAM,SAAW,OAAY,KAAOA,EAAM,MACtD,EAEA,OAAK1B,EAAS2B,EAAO,OAAO,IACxBlB,EAAG,KAAK,qBAAuBkB,EAAO,QAAU,0CAA0C,EAC1FA,EAAO,QAAU,SAEjBA,EAAO,MAAQ,OAAS,OAAOA,EAAO,KAAQ,UAAYA,EAAO,MAAQ,MACzElB,EAAG,KAAK,2DAA4D,EACpEkB,EAAO,IAAM,OAEb,OAAOA,EAAO,OAAU,UAAY,CAAC,OAAO,UAAUA,EAAO,KAAK,GAAKA,EAAO,MAAQ,KACtFlB,EAAG,KAAK,qEAAuER,EAAgB,UAAU,EACzG0B,EAAO,MAAQ1B,GAEf0B,EAAO,SAAW,MAAQ,EAAE,OAAOA,EAAO,QAAW,UAAY,SAASA,EAAO,MAAM,GAAKA,EAAO,OAAS,KAC5GlB,EAAG,KAAK,wFAAwF,EAChGkB,EAAO,OAAS,MAGbA,CACX,CAGA,SAASb,EAAWc,EAAM,CACtB,GAAI,CACA,IAAIC,EAAQ,OAAO7B,EAAS4B,CAAI,CAAC,EACjC,OAAAC,EAAM,QAAQjB,CAAG,EACViB,CACX,OAASC,EAAO,CACZ,OAAO,IACX,CACJ,CAMA,SAASL,EAAUM,EAAU,CACzB,IAAIC,EAEJ,GAAI,CACAA,EAAMnB,EAAQ,QAAQD,CAAG,CAC7B,OAASkB,EAAO,CACZ,OAAO,IACX,CACA,GAAIE,IAAQ,KAAQ,OAAO,KAE3B,IAAIxB,EAAQ,KACZ,GAAI,CAAEA,EAAQ,KAAK,MAAMwB,CAAG,CAAG,OAASF,EAAO,CAA6B,CAE5E,OAAKvB,EAAWC,CAAK,EAQjBuB,GAAYrB,EAAQ,SAAW,MAAQ,KAAK,IAAI,EAAI,KAAK,MAAMF,EAAM,OAAO,EAAIE,EAAQ,QACxFuB,EAAO,EACA,MAGJzB,GAZCuB,IACAtB,EAAG,KAAK,kCAAoCG,EAAM,yDAAyD,EAC3GqB,EAAO,GAEJ,KASf,CAEA,SAASA,GAAS,CACd,GAAI,CAAEpB,EAAQ,WAAWD,CAAG,CAAG,OAASkB,EAAO,CAA6B,CAChF,CAGA,SAASI,EAAKC,EAAQ,CAIlB,GAHA,OAAO,aAAad,CAAK,EACzBA,EAAQ,KAEJE,GAAcJ,IAAS,KAAQ,MAAO,GAI1C,IAAIiB,EAAW,CAAC,CAACd,EACbc,GAAYd,EAAS,WAAW,EACpC,IAAIe,EAAO5B,EAAG,aAAa,EAG3B,GAFI2B,GAAYE,EAAM,EAElBD,IAASjB,EAAQ,MAAO,GAE5B,IAAIZ,EAAQ,CAAE,QAAST,EAAS,KAAMsC,EAAM,QAAS,IAAI,KAAK,EAAE,YAAY,EAAG,KAAMlB,CAAK,EAE1F,GAAI,CACAN,EAAQ,QAAQD,EAAK,KAAK,UAAUJ,CAAK,CAAC,CAC9C,OAASsB,EAAO,CACZ,OAAKN,IACDA,EAAc,GACdf,EAAG,KAAK,4CAA8CqB,GAASA,EAAM,SAAWA,GAAS,GAAG,GAEhGrB,EAAG,KAAK,iBAAkB,CAAE,OAAQA,EAAG,OAAQ,MAAOqB,CAAM,CAAC,EACtD,EACX,CAEA,OAAAV,EAAOiB,EACP5B,EAAG,KAAK,iBAAkB,CAAE,OAAQA,EAAG,OAAQ,KAAM4B,EAAM,QAAS7B,EAAM,QAAS,OAAQ2B,CAAO,CAAC,EAC5F,EACX,CAEA,SAASI,GAAW,CAChB,OAAO,aAAalB,CAAK,EACzBA,EAAQ,OAAO,WAAW,UAAW,CAAEa,EAAK,QAAQ,CAAG,EAAGxB,EAAQ,KAAK,CAC3E,CAEA,SAAS4B,GAAQ,CACRhB,IAAYA,EAAW,IAAI,iBAAiBiB,CAAQ,GACzDjB,EAAS,QAAQb,EAAG,OAAQ,CAAE,QAAS,GAAM,UAAW,GAAM,WAAY,GAAM,cAAe,EAAK,CAAC,CACzG,CAEA,SAAS+B,GAAU,CACf,OAAO,aAAanB,CAAK,EACzBA,EAAQ,KACJC,GAAYA,EAAS,WAAW,CACxC,CAEA,SAASmB,GAAa,CACd1B,IAAU,WAAamB,EAAK,UAAU,CAC9C,CAGA,SAASQ,GAAQ,CACb,GAAI,EAAA3B,IAAU,aAAeA,IAAU,eAOvC,IALAK,EAAOX,EAAG,aAAa,EACvBU,EAAOhB,EAAYiB,CAAI,EACvB,OAAO,iBAAiB,WAAYqB,CAAU,EAG1C1B,IAAU,WAAaG,GAASA,EAAM,OAASC,GAAQD,EAAM,OAASE,EAAM,CAC5EuB,EAAIzB,CAAK,EACT,MACJ,CAEAA,EAAQ,KACJH,IAAU,WAAauB,EAAM,EACrC,CAEA,SAASM,EAAOC,EAAS,CACrB,GAAI,CACA,OAAO,IAAI,KAAKA,CAAO,EAAE,eAAepC,EAAG,SAAS,QAAU,MAAS,CAC3E,OAASqB,EAAO,CACZ,OAAO,IAAI,KAAKe,CAAO,EAAE,eAAe,CAC5C,CACJ,CAEA,SAASF,EAAId,EAAO,CAChBd,EAAQ,SAERN,EAAG,QAAQA,EAAG,EAAE,2BAA4B,CAAE,KAAMmC,EAAOf,EAAM,OAAO,CAAE,CAAC,EAAG,CAC1E,MAAOpB,EAAG,EAAE,wBAAwB,EACpC,GAAIA,EAAG,EAAE,kBAAkB,EAC3B,OAAQA,EAAG,EAAE,kBAAkB,CACnC,EAAG,SAASqC,EAAS,CACjB,GAAI/B,IAAU,YAId,IAAI+B,IAAY,KAAM,CAClB,OAAO,WAAW,UAAW,CACrB/B,IAAU,UAAY4B,EAAId,CAAK,CACvC,EAAG,CAAC,EACJ,MACJ,CAEAX,EAAQ,KAEJ4B,GACA1B,EAAOS,EAAM,KACbpB,EAAG,QAAQoB,EAAM,IAAI,EACrBpB,EAAG,KAAK,sBAAuB,CAAE,OAAQA,EAAG,OAAQ,KAAMoB,EAAM,KAAM,QAASA,EAAM,OAAQ,CAAC,GAE9FI,EAAO,EAGXlB,EAAQC,EAAqB,UAAY,WACrCD,IAAU,WAAauB,EAAM,EACrC,CAAC,CACL,CAEA,MAAO,CAEH,OAAQ,UAAW,CACXrB,IACJA,EAAU,GACV,QAAQ,QAAQ,EAAE,KAAKyB,CAAK,EAChC,EAEA,aAAc,UAAW,CAAEnB,EAAa,EAAM,EAC9C,cAAe,UAAW,CAAEA,EAAa,EAAO,EAEhD,UAAW,UAAW,CACdR,IAAU,WAAaM,GAASa,EAAK,SAAS,EAElDM,EAAQ,EACRlB,EAAW,KACX,OAAO,oBAAoB,WAAYmB,CAAU,EAC7C1B,IAAU,eAAiBb,EAAS,OAAOU,CAAG,EAClDG,EAAQ,WACZ,EAEA,QAAS,CACL,eAAgB,UAAW,CACvB,OAAIA,IAAU,cAAwB,GAClCA,IAAU,UACVC,EAAqB,GACd,KAEPD,IAAU,YACVA,EAAQ,UACJI,IAAS,MAAQmB,EAAM,GAExB,GACX,EAEA,gBAAiB,UAAW,CACxB,OAAIvB,IAAU,cAAwB,GAClCA,IAAU,UACVC,EAAqB,GACd,KAEXwB,EAAQ,EACRzB,EAAQ,WACD,GACX,EAEA,UAAW,UAAW,CAClB,OAAIA,IAAU,eAAiBA,IAAU,SAAmB,GACrDmB,EAAK,KAAK,CACrB,EAEA,SAAU,UAAW,CACjB,GAAInB,IAAU,cAAiB,OAAO,KAEtC,IAAIc,EAAQJ,EAAU,EAAK,EAC3B,OAAOI,EAAQ,CAAE,KAAMA,EAAM,KAAM,QAASA,EAAM,OAAQ,EAAI,IAClE,EAKA,WAAY,UAAW,CACnB,GAAId,IAAU,cAAiB,MAAO,GAOtC,GALA,OAAO,aAAaM,CAAK,EACzBA,EAAQ,KACRY,EAAO,EAGHd,IAAS,MAAQJ,IAAU,UAAY,CAACQ,EAAY,CACpD,IAAIa,EAAW,CAAC,CAACd,GAAYP,IAAU,UACnCqB,GAAYd,EAAS,WAAW,EACpCF,EAAOX,EAAG,aAAa,EACnB2B,GAAYE,EAAM,CAC1B,CACA,MAAO,EACX,CACJ,CACJ,CACJ",
|
|
6
6
|
"names": ["GridEditor", "GridEditor", "VERSION", "STORAGES", "DEFAULT_DELAY", "liveKeys", "fingerprint", "text", "hash", "i", "validDraft", "value", "ge", "options", "optionsFrom", "key", "storage", "storageFor", "state", "enabledAfterAsking", "started", "draft", "base", "last", "timer", "observer", "sourceOpen", "warnedWrite", "readDraft", "given", "result", "name", "found", "error", "starting", "raw", "remove", "save", "source", "watching", "html", "watch", "schedule", "unwatch", "onPageHide", "start", "ask", "dateOf", "savedAt", "restore"]
|
|
7
7
|
}
|
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.
|
|
35
|
+
"version": "8.7.1",
|
|
37
36
|
"main": "dist/grideditor.js",
|
|
38
37
|
"module": "dist/grideditor.esm.js",
|
|
39
38
|
"types": "dist/grideditor.d.ts",
|
package/src/js/grideditor.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 + '"]')
|
|
@@ -338,10 +338,23 @@ GridEditor.features.autosave = function(ge) {
|
|
|
338
338
|
return found ? { html: found.html, savedAt: found.savedAt } : null;
|
|
339
339
|
},
|
|
340
340
|
|
|
341
|
+
// What there is now is not a draft any more - a page calls this
|
|
342
|
+
// once it has saved to its server - so the save waiting does not
|
|
343
|
+
// write it back, and only a change from here makes a new draft
|
|
341
344
|
clearDraft: function() {
|
|
342
345
|
if (state === 'unavailable') { return false; }
|
|
343
346
|
|
|
347
|
+
window.clearTimeout(timer);
|
|
348
|
+
timer = null;
|
|
344
349
|
remove();
|
|
350
|
+
|
|
351
|
+
// Not while it asks: the canvas is not what was offered yet
|
|
352
|
+
if (base !== null && state !== 'asking' && !sourceOpen) {
|
|
353
|
+
var watching = !!observer && state === 'enabled';
|
|
354
|
+
if (watching) { observer.disconnect(); }
|
|
355
|
+
last = ge.snapshotHtml();
|
|
356
|
+
if (watching) { watch(); }
|
|
357
|
+
}
|
|
345
358
|
return true;
|
|
346
359
|
},
|
|
347
360
|
},
|