From f71a3fb6d9dca3524b4d23b8e8bab6e8f0f06248 Mon Sep 17 00:00:00 2001 From: Agriya Dev5 Date: Tue, 29 Dec 2020 22:16:29 +0530 Subject: [PATCH] #storageDialog dialog separate moved dialog --- src/editor/dialogs/index.js | 1 + src/editor/dialogs/storageDialog.js | 166 ++++++++++++++++++ .../extensions/ext-storage/ext-storage.js | 138 +-------------- src/editor/svgedit.js | 137 +++++++++++++++ 4 files changed, 309 insertions(+), 133 deletions(-) create mode 100644 src/editor/dialogs/storageDialog.js diff --git a/src/editor/dialogs/index.js b/src/editor/dialogs/index.js index e45048fd..821f09ca 100644 --- a/src/editor/dialogs/index.js +++ b/src/editor/dialogs/index.js @@ -6,3 +6,4 @@ import './cmenuLayersDialog.js'; import './seSelectDialog.js'; import './seConfirmDialog.js'; import './seAlertDialog.js'; +import './storageDialog.js'; diff --git a/src/editor/dialogs/storageDialog.js b/src/editor/dialogs/storageDialog.js new file mode 100644 index 00000000..32ee919e --- /dev/null +++ b/src/editor/dialogs/storageDialog.js @@ -0,0 +1,166 @@ +/* eslint-disable node/no-unpublished-import */ +import 'elix/define/Dialog.js'; + +const template = document.createElement('template'); +template.innerHTML = ` + + +
+
+
+

+ By default and where supported, SVG-Edit can store your editor preferences and SVG content locally on your machine so you do not need to add these back each time you load SVG-Edit. If, for privacy reasons, you do not wish to store this information on your machine, you can change away from the default option below. +

+ + +
+
+ + +
+
+
+`; +/** + * @class SeStorageDialog + */ +export class SeStorageDialog extends HTMLElement { + /** + * @function constructor + */ + constructor () { + super(); + // create the shadowDom and insert the template + this._shadowRoot = this.attachShadow({mode: 'open'}); + this._shadowRoot.appendChild(template.content.cloneNode(true)); + this.$dialog = this._shadowRoot.querySelector('#dialog_box'); + this.$storage = this._shadowRoot.querySelector('#js-storage'); + this.$okBtn = this._shadowRoot.querySelector('#storage_ok'); + this.$cancelBtn = this._shadowRoot.querySelector('#storage_cancel'); + this.$storageInput = this._shadowRoot.querySelector('#se-storage-pref'); + this.$rememberInput = this._shadowRoot.querySelector('#se-remember'); + } + /** + * @function observedAttributes + * @returns {any} observed + */ + static get observedAttributes () { + return ['dialog', 'storage']; + } + /** + * @function attributeChangedCallback + * @param {string} name + * @param {string} oldValue + * @param {string} newValue + * @returns {void} + */ + attributeChangedCallback (name, oldValue, newValue) { + switch (name) { + case 'dialog': + if (newValue === 'open') { + this.$dialog.open(); + } else { + this.$dialog.close(); + } + break; + case 'storage': + if (newValue === 'true') { + this.$storageInput.options[0].disabled = false; + } else { + this.$storageInput.options[0].disabled = true; + } + break; + default: + // super.attributeChangedCallback(name, oldValue, newValue); + break; + } + } + /** + * @function get + * @returns {any} + */ + get dialog () { + return this.getAttribute('dialog'); + } + /** + * @function set + * @returns {void} + */ + set dialog (value) { + this.setAttribute('dialog', value); + } + /** + * @function connectedCallback + * @returns {void} + */ + connectedCallback () { + const onSubmitHandler = (e, action) => { + const triggerEvent = new CustomEvent('change', {detail: { + trigger: action, + select: this.$storageInput.value, + checkbox: this.$rememberInput.checked + }}); + this.dispatchEvent(triggerEvent); + }; + this.$okBtn.addEventListener('click', (evt) => onSubmitHandler(evt, 'ok')); + this.$cancelBtn.addEventListener('click', (evt) => onSubmitHandler(evt, 'cancel')); + } +} + +// Register +customElements.define('se-storage-dialog', SeStorageDialog); diff --git a/src/editor/extensions/ext-storage/ext-storage.js b/src/editor/extensions/ext-storage/ext-storage.js index dddadd53..ba52e0b4 100644 --- a/src/editor/extensions/ext-storage/ext-storage.js +++ b/src/editor/extensions/ext-storage/ext-storage.js @@ -44,7 +44,6 @@ export default { // to change, set the "emptyStorageOnDecline" config setting to true // in svgedit-config-iife.js/svgedit-config-es.js. const { - emptyStorageOnDecline, // When the code in svg-editor.js prevents local storage on load per // user request, we also prevent storing on unload here so as to // avoid third-party sites making XSRF requests or providing links @@ -57,30 +56,7 @@ export default { noStorageOnLoad, forceStorage } = svgEditor.curConfig; - const {storage, updateCanvas} = svgEditor; - - /** - * Replace `storagePrompt` parameter within URL. - * @param {string} val - * @returns {void} - * @todo Replace the string manipulation with `searchParams.set` - */ - function replaceStoragePrompt (val) { - val = val ? 'storagePrompt=' + val : ''; - const loc = top.location; // Allow this to work with the embedded editor as well - if (loc.href.includes('storagePrompt=')) { - /* - loc.href = loc.href.replace(/(?[&?])storagePrompt=[^&]*(?&?)/, function (n0, sep, amp) { - return (val ? sep : '') + val + (!val && amp ? sep : (amp || '')); - }); - */ - loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) { - return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || '')); - }); - } else { - loc.href += (loc.href.includes('?') ? '&' : '?') + val; - } - } + const {storage} = svgEditor; /** * Sets SVG content as a string with "svgedit-" and the current @@ -99,40 +75,6 @@ export default { } } - /** - * Set the cookie to expire. - * @param {string} cookie - * @returns {void} - */ - function expireCookie (cookie) { - document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; - } - - /** - * Expire the storage cookie. - * @returns {void} - */ - function removeStoragePrefCookie () { - expireCookie('svgeditstore'); - } - - /** - * Empties storage for each of the current preferences. - * @returns {void} - */ - function emptyStorage () { - setSVGContentStorage(''); - Object.keys(svgEditor.curPrefs).forEach((name) => { - name = 'svg-edit-' + name; - if (storage) { - storage.removeItem(name); - } - expireCookie(name); - }); - } - - // emptyStorage(); - /** * Listen for unloading: If and only if opted in by the user, set the content * document and preferences into storage: @@ -214,83 +156,13 @@ export default { ) // ...then show the storage prompt. )) { - /* - const options = []; - if (storage) { - options.unshift( - {value: 'prefsAndContent', text: storagePrefsAndContent}, - {value: 'prefsOnly', text: storagePrefsOnly}, - {value: 'noPrefsOrContent', text: storageNoPrefsOrContent} - ); - } else { - options.unshift( - {value: 'prefsOnly', text: storagePrefs}, - {value: 'noPrefsOrContent', text: storageNoPrefs} - ); - } - */ - const options = storage ? ['prefsAndContent', 'prefsOnly', 'noPrefsOrContent'] : ['prefsOnly', 'noPrefsOrContent']; - + const options = storage ? true : false; // Open select-with-checkbox dialog // From svg-editor.js svgEditor.storagePromptState = 'waiting'; - /* JFH !!!!! - const {response: pref, checked} = await $.select( - message, - options, - null, - null, - { - label: rememberLabel, - checked: true, - tooltip: rememberTooltip - } - ); - */ - const pref = await seSelect(message, options); - if (pref && pref !== 'noPrefsOrContent') { - // Regardless of whether the user opted - // to remember the choice (and move to a URL which won't - // ask them again), we have to assume the user - // doesn't even want to remember their not wanting - // storage, so we don't set the cookie or continue on with - // setting storage on beforeunload - document.cookie = 'svgeditstore=' + encodeURIComponent(pref) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; // 'prefsAndContent' | 'prefsOnly' - // If the URL was configured to always insist on a prompt, if - // the user does indicate a wish to store their info, we - // don't want ask them again upon page refresh so move - // them instead to a URL which does not always prompt - if (storagePrompt === 'true' /* && checked */) { - replaceStoragePrompt(); - return; - } - } else { // The user does not wish storage (or cancelled, which we treat equivalently) - removeStoragePrefCookie(); - if (pref && // If the user explicitly expresses wish for no storage - emptyStorageOnDecline - ) { - emptyStorage(); - } - if (pref /* && checked */) { - // Open a URL which won't set storage and won't prompt user about storage - replaceStoragePrompt('false'); - return; - } - } - - // It should be enough to (conditionally) add to storage on - // beforeunload, but if we wished to update immediately, - // we might wish to try setting: - // svgEditor.setConfig({noStorageOnLoad: true}); - // and then call: - // svgEditor.loadContentAndPrefs(); - - // We don't check for noStorageOnLoad here because - // the prompt gives the user the option to store data - setupBeforeUnloadListener(); - - svgEditor.storagePromptState = 'closed'; - updateCanvas(true); + const $storageDialog = document.getElementById('se-storage-dialog'); + $storageDialog.setAttribute('dialog', 'open'); + $storageDialog.setAttribute('storage', options); } else if (!noStorageOnLoad || forceStorage) { setupBeforeUnloadListener(); } diff --git a/src/editor/svgedit.js b/src/editor/svgedit.js index ce81af8f..167e12ee 100644 --- a/src/editor/svgedit.js +++ b/src/editor/svgedit.js @@ -226,6 +226,10 @@ editor.init = () => { const alertBox = document.createElement('se-alert-dialog'); alertBox.setAttribute('id', 'se-alert-dialog'); document.body.append(alertBox); + // storageDialog added to DOM + const storageBox = document.createElement('se-storage-dialog'); + storageBox.setAttribute('id', 'se-storage-dialog'); + document.body.append(storageBox); } catch (err) {} editor.configObj.load(); @@ -1982,6 +1986,105 @@ editor.init = () => { } }; + /** + * Replace `storagePrompt` parameter within URL. + * @param {string} val + * @returns {void} + * @todo Replace the string manipulation with `searchParams.set` + */ + function replaceStoragePrompt (val) { + val = val ? 'storagePrompt=' + val : ''; + const loc = top.location; // Allow this to work with the embedded editor as well + if (loc.href.includes('storagePrompt=')) { + /* + loc.href = loc.href.replace(/(?[&?])storagePrompt=[^&]*(?&?)/, function (n0, sep, amp) { + return (val ? sep : '') + val + (!val && amp ? sep : (amp || '')); + }); + */ + loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) { + return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || '')); + }); + } else { + loc.href += (loc.href.includes('?') ? '&' : '?') + val; + } + } + + /** + * Sets SVG content as a string with "svgedit-" and the current + * canvas name as namespace. + * @param {string} val + * @returns {void} + */ + function setSVGContentStorage (val) { + if (editor.storage) { + const name = 'svgedit-' + editor.curConfig.canvasName; + if (!val) { + editor.storage.removeItem(name); + } else { + editor.storage.setItem(name, val); + } + } + } + + /** + * Listen for unloading: If and only if opted in by the user, set the content + * document and preferences into storage: + * 1. Prevent save warnings (since we're automatically saving unsaved + * content into storage) + * 2. Use localStorage to set SVG contents (potentially too large to allow in cookies) + * 3. Use localStorage (where available) or cookies to set preferences. + * @returns {void} + */ + function setupBeforeUnloadListener () { + window.addEventListener('beforeunload', function (e) { + // Don't save anything unless the user opted in to storage + if (!document.cookie.match(/(?:^|;\s*)svgeditstore=(?:prefsAndContent|prefsOnly)/)) { + return; + } + if (document.cookie.match(/(?:^|;\s*)svgeditstore=prefsAndContent/)) { + setSVGContentStorage(svgCanvas.getSvgString()); + } + + editor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on + // svgEditor.showSaveWarning = false; + + const {curPrefs} = editor; + + Object.entries(curPrefs).forEach(([key, val]) => { + const store = (val !== undefined); + key = 'svg-edit-' + key; + if (!store) { + return; + } + if (editor.storage) { + editor.storage.setItem(key, val); + } else if (window.widget) { + window.widget.setPreferenceForKey(val, key); + } else { + val = encodeURIComponent(val); + document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; + } + }); + }); + } + + /** + * Set the cookie to expire. + * @param {string} cookie + * @returns {void} + */ + function expireCookie (cookie) { + document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; + } + + /** + * Expire the storage cookie. + * @returns {void} + */ + function removeStoragePrefCookie () { + expireCookie('svgeditstore'); + } + const winWh = {width: $(window).width(), height: $(window).height()}; $(window).resize(function (evt) { @@ -2153,6 +2256,40 @@ editor.init = () => { break; } }); + $id('se-storage-dialog').addEventListener('change', function (e) { + document.getElementById('se-storage-dialog').setAttribute('dialog', 'close'); + if (e?.detail?.trigger === 'ok') { + if (e?.detail?.select !== 'noPrefsOrContent') { + const storagePrompt = new URL(top.location).searchParams.get('storagePrompt'); + document.cookie = 'svgeditstore=' + encodeURIComponent(e.detail.select) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; + if (storagePrompt === 'true' && e?.detail?.checkbox ) { + replaceStoragePrompt(); + return; + } + } else { + removeStoragePrefCookie(); + if (editor.curConfig.emptyStorageOnDecline && e?.detail?.checkbox) { + setSVGContentStorage(''); + Object.keys(editor.curPrefs).forEach((name) => { + name = 'svg-edit-' + name; + if (editor.storage) { + editor.storage.removeItem(name); + } + expireCookie(name); + }); + } + if (e?.detail?.select && e?.detail?.checkbox) { + replaceStoragePrompt('false'); + return; + } + } + } else if (e?.detail?.trigger === 'cancel') { + removeStoragePrefCookie(); + } + setupBeforeUnloadListener(); + editor.storagePromptState = 'closed'; + updateCanvas(true); + }); const toolButtons = [ // Shortcuts not associated with buttons