1 line
15 KiB
Plaintext
1 line
15 KiB
Plaintext
{"version":3,"file":"ext-storage.js","sources":["../../../src/editor/extensions/ext-storage.js"],"sourcesContent":["/**\n * @file ext-storage.js\n *\n * This extension allows automatic saving of the SVG canvas contents upon\n * page unload (which can later be automatically retrieved upon future\n * editor loads).\n *\n * The functionality was originally part of the SVG Editor, but moved to a\n * separate extension to make the setting behavior optional, and adapted\n * to inform the user of its setting of local data.\n *\n * @license MIT\n *\n * @copyright 2010 Brett Zamir\n * @todo Revisit on whether to use `svgEditor.pref` over directly setting\n * `curConfig` in all extensions for a more public API (not only for `extPath`\n * and `imagePath`, but other currently used config in the extensions)\n * @todo We might provide control of storage settings through the UI besides the\n * initial (or URL-forced) dialog. *\n*/\n\nexport default {\n name: 'storage',\n init ({$}) {\n const svgEditor = this;\n const svgCanvas = svgEditor.canvas;\n\n // We could empty any already-set data for users when they decline storage,\n // but it would be a risk for users who wanted to store but accidentally\n // said \"no\"; instead, we'll let those who already set it, delete it themselves;\n // to change, set the \"emptyStorageOnDecline\" config setting to true\n // in svgedit-config-iife.js/svgedit-config-es.js.\n const {\n emptyStorageOnDecline,\n // When the code in svg-editor.js prevents local storage on load per\n // user request, we also prevent storing on unload here so as to\n // avoid third-party sites making XSRF requests or providing links\n // which would cause the user's local storage not to load and then\n // upon page unload (such as the user closing the window), the storage\n // would thereby be set with an empty value, erasing any of the\n // user's prior work. To change this behavior so that no use of storage\n // or adding of new storage takes place regardless of settings, set\n // the \"noStorageOnLoad\" config setting to true in svgedit-config-*.js.\n noStorageOnLoad,\n forceStorage\n } = svgEditor.curConfig;\n const {storage, updateCanvas} = svgEditor;\n\n /**\n * Replace `storagePrompt` parameter within URL.\n * @param {string} val\n * @returns {void}\n * @todo Replace the string manipulation with `searchParams.set`\n */\n function replaceStoragePrompt (val) {\n val = val ? 'storagePrompt=' + val : '';\n const loc = top.location; // Allow this to work with the embedded editor as well\n if (loc.href.includes('storagePrompt=')) {\n /*\n loc.href = loc.href.replace(/(?<sep>[&?])storagePrompt=[^&]*(?<amp>&?)/, function (n0, sep, amp) {\n return (val ? sep : '') + val + (!val && amp ? sep : (amp || ''));\n });\n */\n loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {\n return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));\n });\n } else {\n loc.href += (loc.href.includes('?') ? '&' : '?') + val;\n }\n }\n\n /**\n * Sets SVG content as a string with \"svgedit-\" and the current\n * canvas name as namespace.\n * @param {string} val\n * @returns {void}\n */\n function setSVGContentStorage (val) {\n if (storage) {\n const name = 'svgedit-' + svgEditor.curConfig.canvasName;\n if (!val) {\n storage.removeItem(name);\n } else {\n storage.setItem(name, val);\n }\n }\n }\n\n /**\n * Set the cookie to expire.\n * @param {string} cookie\n * @returns {void}\n */\n function expireCookie (cookie) {\n document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';\n }\n\n /**\n * Expire the storage cookie.\n * @returns {void}\n */\n function removeStoragePrefCookie () {\n expireCookie('svgeditstore');\n }\n\n /**\n * Empties storage for each of the current preferences.\n * @returns {void}\n */\n function emptyStorage () {\n setSVGContentStorage('');\n Object.keys(svgEditor.curPrefs).forEach((name) => {\n name = 'svg-edit-' + name;\n if (storage) {\n storage.removeItem(name);\n }\n expireCookie(name);\n });\n }\n\n // emptyStorage();\n\n /**\n * Listen for unloading: If and only if opted in by the user, set the content\n * document and preferences into storage:\n * 1. Prevent save warnings (since we're automatically saving unsaved\n * content into storage)\n * 2. Use localStorage to set SVG contents (potentially too large to allow in cookies)\n * 3. Use localStorage (where available) or cookies to set preferences.\n * @returns {void}\n */\n function setupBeforeUnloadListener () {\n window.addEventListener('beforeunload', function (e) {\n // Don't save anything unless the user opted in to storage\n if (!document.cookie.match(/(?:^|;\\s*)svgeditstore=(?:prefsAndContent|prefsOnly)/)) {\n return;\n }\n if (document.cookie.match(/(?:^|;\\s*)svgeditstore=prefsAndContent/)) {\n setSVGContentStorage(svgCanvas.getSvgString());\n }\n\n svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on\n // svgEditor.showSaveWarning = false;\n\n const {curPrefs} = svgEditor;\n\n Object.entries(curPrefs).forEach(([key, val]) => {\n const store = (val !== undefined);\n key = 'svg-edit-' + key;\n if (!store) {\n return;\n }\n if (storage) {\n storage.setItem(key, val);\n } else if (window.widget) {\n window.widget.setPreferenceForKey(val, key);\n } else {\n val = encodeURIComponent(val);\n document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';\n }\n });\n });\n }\n\n let loaded = false;\n return {\n name: 'storage',\n async langReady ({importLocale}) {\n const storagePrompt = new URL(top.location).searchParams.get('storagePrompt');\n\n const confirmSetStorage = await importLocale();\n const {\n message, storagePrefsAndContent, storagePrefsOnly,\n storagePrefs, storageNoPrefsOrContent, storageNoPrefs,\n rememberLabel, rememberTooltip\n } = confirmSetStorage;\n\n // No need to run this one-time dialog again just because the user\n // changes the language\n if (loaded) {\n return;\n }\n loaded = true;\n\n // Note that the following can load even if \"noStorageOnLoad\" is\n // set to false; to avoid any chance of storage, avoid this\n // extension! (and to avoid using any prior storage, set the\n // config option \"noStorageOnLoad\" to true).\n if (!forceStorage && (\n // If the URL has been explicitly set to always prompt the\n // user (e.g., so one can be pointed to a URL where one\n // can alter one's settings, say to prevent future storage)...\n storagePrompt === 'true' ||\n (\n // ...or...if the URL at least doesn't explicitly prevent a\n // storage prompt (as we use for users who\n // don't want to set cookies at all but who don't want\n // continual prompts about it)...\n storagePrompt !== 'false' &&\n // ...and this user hasn't previously indicated a desire for storage\n !document.cookie.match(/(?:^|;\\s*)svgeditstore=(?:prefsAndContent|prefsOnly)/)\n )\n // ...then show the storage prompt.\n )) {\n const options = [];\n if (storage) {\n options.unshift(\n {value: 'prefsAndContent', text: storagePrefsAndContent},\n {value: 'prefsOnly', text: storagePrefsOnly},\n {value: 'noPrefsOrContent', text: storageNoPrefsOrContent}\n );\n } else {\n options.unshift(\n {value: 'prefsOnly', text: storagePrefs},\n {value: 'noPrefsOrContent', text: storageNoPrefs}\n );\n }\n\n // Hack to temporarily provide a wide and high enough dialog\n const oldContainerWidth = $('#dialog_container')[0].style.width,\n oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,\n oldContentHeight = $('#dialog_content')[0].style.height,\n oldContainerHeight = $('#dialog_container')[0].style.height;\n $('#dialog_content')[0].style.height = '120px';\n $('#dialog_container')[0].style.height = '170px';\n $('#dialog_container')[0].style.width = '800px';\n $('#dialog_container')[0].style.marginLeft = '-400px';\n\n // Open select-with-checkbox dialog\n // From svg-editor.js\n svgEditor.storagePromptState = 'waiting';\n const {response: pref, checked} = await $.select(\n message,\n options,\n null,\n null,\n {\n label: rememberLabel,\n checked: true,\n tooltip: rememberTooltip\n }\n );\n if (pref && pref !== 'noPrefsOrContent') {\n // Regardless of whether the user opted\n // to remember the choice (and move to a URL which won't\n // ask them again), we have to assume the user\n // doesn't even want to remember their not wanting\n // storage, so we don't set the cookie or continue on with\n // setting storage on beforeunload\n document.cookie = 'svgeditstore=' + encodeURIComponent(pref) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; // 'prefsAndContent' | 'prefsOnly'\n // If the URL was configured to always insist on a prompt, if\n // the user does indicate a wish to store their info, we\n // don't want ask them again upon page refresh so move\n // them instead to a URL which does not always prompt\n if (storagePrompt === 'true' && checked) {\n replaceStoragePrompt();\n return;\n }\n } else { // The user does not wish storage (or cancelled, which we treat equivalently)\n removeStoragePrefCookie();\n if (pref && // If the user explicitly expresses wish for no storage\n emptyStorageOnDecline\n ) {\n emptyStorage();\n }\n if (pref && checked) {\n // Open a URL which won't set storage and won't prompt user about storage\n replaceStoragePrompt('false');\n return;\n }\n }\n\n // Reset width/height of dialog (e.g., for use by Export)\n $('#dialog_container')[0].style.width = oldContainerWidth;\n $('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;\n $('#dialog_content')[0].style.height = oldContentHeight;\n $('#dialog_container')[0].style.height = oldContainerHeight;\n\n // It should be enough to (conditionally) add to storage on\n // beforeunload, but if we wished to update immediately,\n // we might wish to try setting:\n // svgEditor.setConfig({noStorageOnLoad: true});\n // and then call:\n // svgEditor.loadContentAndPrefs();\n\n // We don't check for noStorageOnLoad here because\n // the prompt gives the user the option to store data\n setupBeforeUnloadListener();\n\n svgEditor.storagePromptState = 'closed';\n updateCanvas(true);\n } else if (!noStorageOnLoad || forceStorage) {\n setupBeforeUnloadListener();\n }\n }\n };\n }\n};\n"],"names":["name","init","$","svgEditor","this","svgCanvas","canvas","curConfig","emptyStorageOnDecline","noStorageOnLoad","forceStorage","storage","updateCanvas","replaceStoragePrompt","val","loc","top","location","href","includes","replace","n0","n1","amp","setSVGContentStorage","canvasName","setItem","removeItem","expireCookie","cookie","document","encodeURIComponent","setupBeforeUnloadListener","window","addEventListener","e","match","getSvgString","setConfig","no_save_warning","curPrefs","Object","entries","forEach","key","undefined","widget","setPreferenceForKey","loaded","langReady","importLocale","storagePrompt","URL","searchParams","get","confirmSetStorage","message","storagePrefsAndContent","storagePrefsOnly","storagePrefs","storageNoPrefsOrContent","storageNoPrefs","rememberLabel","rememberTooltip","options","unshift","value","text","oldContainerWidth","style","width","oldContainerMarginLeft","marginLeft","oldContentHeight","height","oldContainerHeight","storagePromptState","select","label","checked","tooltip","pref","response","keys"],"mappings":"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"} |