/* globals jQuery */ 
 | 
/** 
 | 
 * ext-storage.js 
 | 
 * 
 | 
 * This extension allows automatic saving of the SVG canvas contents upon 
 | 
 *  page unload (which can later be automatically retrieved upon future 
 | 
 *  editor loads). 
 | 
 * 
 | 
 *  The functionality was originally part of the SVG Editor, but moved to a 
 | 
 *  separate extension to make the setting behavior optional, and adapted 
 | 
 *  to inform the user of its setting of local data. 
 | 
 * Dependencies: 
 | 
 * 
 | 
 * 1. jQuery BBQ (for deparam) 
 | 
 * @license MIT 
 | 
 * 
 | 
 * @copyright 2010 Brett Zamir 
 | 
 * @todo Revisit on whether to use $.pref over directly setting curConfig in all 
 | 
 *   extensions for a more public API (not only for extPath and imagePath, 
 | 
 *   but other currently used config in the extensions) 
 | 
 * @todo We might provide control of storage settings through the UI besides the 
 | 
 *   initial (or URL-forced) dialog. * 
 | 
*/ 
 | 
export default { 
 | 
  name: 'storage', 
 | 
  init () { 
 | 
    const svgEditor = this; 
 | 
    const $ = jQuery; 
 | 
    const svgCanvas = svgEditor.canvas; 
 | 
  
 | 
    // We could empty any already-set data for users when they decline storage, 
 | 
    //  but it would be a risk for users who wanted to store but accidentally 
 | 
    // said "no"; instead, we'll let those who already set it, delete it themselves; 
 | 
    // 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 
 | 
      // which would cause the user's local storage not to load and then 
 | 
      // upon page unload (such as the user closing the window), the storage 
 | 
      //  would thereby be set with an empty value, erasing any of the 
 | 
      // user's prior work. To change this behavior so that no use of storage 
 | 
      // or adding of new storage takes place regardless of settings, set 
 | 
      // the "noStorageOnLoad" config setting to true in svgedit-config-iife.js. 
 | 
      noStorageOnLoad, 
 | 
      forceStorage 
 | 
    } = svgEditor.curConfig; 
 | 
    const {storage, updateCanvas} = svgEditor; 
 | 
  
 | 
    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, n1, amp) { 
 | 
          return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || '')); 
 | 
        }); 
 | 
      } else { 
 | 
        loc.href += (loc.href.includes('?') ? '&' : '?') + val; 
 | 
      } 
 | 
    } 
 | 
    function setSVGContentStorage (val) { 
 | 
      if (storage) { 
 | 
        const name = 'svgedit-' + svgEditor.curConfig.canvasName; 
 | 
        if (!val) { 
 | 
          storage.removeItem(name); 
 | 
        } else { 
 | 
          storage.setItem(name, val); 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
  
 | 
    function expireCookie (cookie) { 
 | 
      document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; 
 | 
    } 
 | 
  
 | 
    function removeStoragePrefCookie () { 
 | 
      expireCookie('store'); 
 | 
    } 
 | 
  
 | 
    function emptyStorage () { 
 | 
      setSVGContentStorage(''); 
 | 
      for (let name in svgEditor.curPrefs) { 
 | 
        if (svgEditor.curPrefs.hasOwnProperty(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: 
 | 
    * 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 {undefined} 
 | 
    */ 
 | 
    function setupBeforeUnloadListener () { 
 | 
      window.addEventListener('beforeunload', function (e) { 
 | 
        // Don't save anything unless the user opted in to storage 
 | 
        if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) { 
 | 
          return; 
 | 
        } 
 | 
        if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) { 
 | 
          setSVGContentStorage(svgCanvas.getSvgString()); 
 | 
        } 
 | 
  
 | 
        svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on 
 | 
        // svgEditor.showSaveWarning = false; 
 | 
  
 | 
        const {curPrefs} = svgEditor; 
 | 
  
 | 
        for (let key in curPrefs) { 
 | 
          if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain 
 | 
            let val = curPrefs[key]; 
 | 
            const store = (val !== undefined); 
 | 
            key = 'svg-edit-' + key; 
 | 
            if (!store) { 
 | 
              continue; 
 | 
            } 
 | 
            if (storage) { 
 | 
              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'; 
 | 
            } 
 | 
          } 
 | 
        } 
 | 
      }); 
 | 
    } 
 | 
  
 | 
    let loaded = false; 
 | 
    return { 
 | 
      name: 'storage', 
 | 
      async langReady ({importLocale}) { 
 | 
        const {storagePrompt} = $.deparam.querystring(true); 
 | 
  
 | 
        const confirmSetStorage = await importLocale(); 
 | 
        const { 
 | 
          message, storagePrefsAndContent, storagePrefsOnly, 
 | 
          storagePrefs, storageNoPrefsOrContent, storageNoPrefs, 
 | 
          rememberLabel, rememberTooltip 
 | 
        } = confirmSetStorage; 
 | 
  
 | 
        // No need to run this one-time dialog again just because the user 
 | 
        //   changes the language 
 | 
        if (loaded) { 
 | 
          return; 
 | 
        } 
 | 
        loaded = true; 
 | 
  
 | 
        // Note that the following can load even if "noStorageOnLoad" is 
 | 
        //   set to false; to avoid any chance of storage, avoid this 
 | 
        //   extension! (and to avoid using any prior storage, set the 
 | 
        //   config option "noStorageOnLoad" to true). 
 | 
        if (!forceStorage && ( 
 | 
          // If the URL has been explicitly set to always prompt the 
 | 
          //  user (e.g., so one can be pointed to a URL where one 
 | 
          // can alter one's settings, say to prevent future storage)... 
 | 
          storagePrompt === true || 
 | 
          ( 
 | 
            // ...or...if the URL at least doesn't explicitly prevent a 
 | 
            //  storage prompt (as we use for users who 
 | 
            // don't want to set cookies at all but who don't want 
 | 
            // continual prompts about it)... 
 | 
            storagePrompt !== false && 
 | 
            // ...and this user hasn't previously indicated a desire for storage 
 | 
            !document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/) 
 | 
          ) 
 | 
          // ...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} 
 | 
            ); 
 | 
          } 
 | 
  
 | 
          // Hack to temporarily provide a wide and high enough dialog 
 | 
          const oldContainerWidth = $('#dialog_container')[0].style.width, 
 | 
            oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft, 
 | 
            oldContentHeight = $('#dialog_content')[0].style.height, 
 | 
            oldContainerHeight = $('#dialog_container')[0].style.height; 
 | 
          $('#dialog_content')[0].style.height = '120px'; 
 | 
          $('#dialog_container')[0].style.height = '170px'; 
 | 
          $('#dialog_container')[0].style.width = '800px'; 
 | 
          $('#dialog_container')[0].style.marginLeft = '-400px'; 
 | 
  
 | 
          // Open select-with-checkbox dialog 
 | 
          // From svg-editor.js 
 | 
          $.select( 
 | 
            message, 
 | 
            options, 
 | 
            function (pref, checked) { 
 | 
              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 = 'store=' + 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; 
 | 
                } 
 | 
              } 
 | 
  
 | 
              // Reset width/height of dialog (e.g., for use by Export) 
 | 
              $('#dialog_container')[0].style.width = oldContainerWidth; 
 | 
              $('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft; 
 | 
              $('#dialog_content')[0].style.height = oldContentHeight; 
 | 
              $('#dialog_container')[0].style.height = oldContainerHeight; 
 | 
  
 | 
              // 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); 
 | 
            }, 
 | 
            null, 
 | 
            null, 
 | 
            { 
 | 
              label: rememberLabel, 
 | 
              checked: true, 
 | 
              tooltip: rememberTooltip 
 | 
            } 
 | 
          ); 
 | 
          svgEditor.storagePromptState = 'waiting'; 
 | 
        } else if (!noStorageOnLoad || forceStorage) { 
 | 
          setupBeforeUnloadListener(); 
 | 
        } 
 | 
      } 
 | 
    }; 
 | 
  } 
 | 
}; 
 |