ext-storage - Copy.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*globals svgEditor, Editor, svgCanvas, $, widget*/
  2. /*jslint vars: true, eqeq: true, regexp: true, continue: true*/
  3. /*
  4. * ext-storage.js
  5. *
  6. * Licensed under the MIT License
  7. *
  8. * Copyright(c) 2010 Brett Zamir
  9. *
  10. */
  11. /**
  12. * This extension allows automatic saving of the SVG canvas contents upon
  13. * page unload and and automatic retrieval of the contents upon editor load.
  14. * The functionality was originally part of the SVG Editor, but moved to a
  15. * separate extension to make the behavior optional, and adapted to inform
  16. * the user of its setting of local data.
  17. */
  18. /*
  19. TODOS
  20. 1. Revisit on whether to use $.pref over directly setting curConfig in all
  21. extensions for a more public API (not only for extPath and imagePath,
  22. but other currently used config in the extensions)
  23. */
  24. svgEditor.addExtension('storage', function() { 'use strict';
  25. // We could empty any already-set data for them, but it
  26. // would be a risk for users who wanted to store but accidentally
  27. // said "no"; instead, we'll let those who already set it, delete it themselves;
  28. // to change, change the following line to true.
  29. var emptyStorageOnDecline = false;
  30. function replaceStoragePrompt (val) {
  31. val = val ? 'storagePrompt=' + val : '';
  32. if (window.location.href.indexOf('storagePrompt=') > -1) {
  33. window.location.href = window.location.href.replace(/([&?])storagePrompt=[^&]*/, (val ? '$1' : '') + val);
  34. }
  35. else {
  36. window.location.href += (window.location.href.indexOf('?') > -1 ? '&' : '?') + val;
  37. }
  38. }
  39. function setSVGContentStorage (val) {
  40. if (window.localStorage) {
  41. var name = 'svgedit-' + svgEditor.curConfig.canvasName;
  42. window.localStorage.setItem(name, val);
  43. }
  44. }
  45. function emptyLocalStorage() {
  46. document.cookie = 'store=';
  47. setSVGContentStorage('');
  48. }
  49. //emptyLocalStorage();
  50. /**
  51. * Listen for unloading: If and only if opted in by the user, set the content
  52. * document and preferences into storage:
  53. * 1. Prevent save warnings (since we're automatically saving unsaved
  54. * content into storage)
  55. * 2. Use localStorage to set SVG contents (potentially too large to allow in cookies)
  56. * 3. Use localStorage (where available) or cookies to set preferences.
  57. */
  58. function setupBeforeUnloadListener () {
  59. window.addEventListener('beforeunload', function(e) {
  60. // Don't save anything unless the user opted in to storage
  61. if (!document.cookie.match(/store=(?:prefsAndContent|prefsOnly)/)) {
  62. return;
  63. }
  64. var key;
  65. setSVGContentStorage(svgCanvas.getSvgString());
  66. svgEditor.showSaveWarning = false;
  67. var curConfig = svgEditor.curConfig;
  68. for (key in curConfig) {
  69. if (curConfig.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
  70. var d,
  71. storage = svgEditor.storage,
  72. val = curConfig[key],
  73. store = (val != undefined);
  74. key = 'svg-edit-' + key;
  75. if (!store) {
  76. continue;
  77. }
  78. if (storage) {
  79. storage.setItem(key, val);
  80. }
  81. else if (window.widget) {
  82. widget.setPreferenceForKey(val, key);
  83. }
  84. else {
  85. d = new Date();
  86. d.setTime(d.getTime() + 31536000000);
  87. val = encodeURIComponent(val);
  88. document.cookie = key + '=' + val + '; expires=' + d.toUTCString();
  89. }
  90. }
  91. }
  92. }, false);
  93. }
  94. var userStoragePref = 'noPrefsOrContent';
  95. /*
  96. // We could add locales here instead (and also thereby avoid the need
  97. // to keep our content within "langReady"), but this would be less
  98. // convenient for translators.
  99. $.extend(uiStrings, {confirmSetStorage: {
  100. message: "By default and where supported, SVG-Edit can store your editor "+
  101. "preferences and SVG content locally on your machine so you do not "+
  102. "need to add these back each time you load SVG-Edit. If, for privacy "+
  103. "reasons, you do not wish to store this information on your machine, "+
  104. "you can change away from the default option below.",
  105. storagePrefsAndContent: "Store preferences and SVG content locally",
  106. storagePrefsOnly: "Only store preferences locally",
  107. storagePrefs: "Store preferences locally",
  108. storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
  109. storageNoPrefs: "Do not store my preferences locally",
  110. rememberLabel: "Remember this choice?",
  111. rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
  112. }});
  113. */
  114. return {
  115. name: 'storage',
  116. langReady: function (lang, uiStrings) {
  117. var storagePrompt = $.deparam.querystring(true).storagePrompt;
  118. if (
  119. // If explicitly set to always prompt (e.g., so a user can alter
  120. // their settings)...
  121. storagePrompt === true ||
  122. // ...or...the user hasn't visited page preventing storage prompt (for
  123. // users who don't want to set cookies at all but don't want
  124. // continual prompts)...
  125. (storagePrompt !== false &&
  126. // ...and user hasn't already indicated a desire for storage
  127. !document.cookie.match(/store=(?:prefsAndContent|prefsOnly)/)
  128. )
  129. // ...then show the storage prompt.
  130. ) {
  131. var options = [];
  132. if (window.localStorage) {
  133. options.unshift(
  134. {value: 'prefsAndContent', text: uiStrings.confirmSetStorage.storagePrefsAndContent},
  135. {value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly},
  136. {value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent}
  137. );
  138. }
  139. else {
  140. options.unshift(
  141. {value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs},
  142. {value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs}
  143. );
  144. }
  145. // Hack to temporarily provide a wide and high enough dialog
  146. var oldContainerWidth = $('#dialog_container')[0].style.width,
  147. oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,
  148. oldContentHeight = $('#dialog_content')[0].style.height,
  149. oldContainerHeight = $('#dialog_container')[0].style.height;
  150. $('#dialog_content')[0].style.height = '120px';
  151. $('#dialog_container')[0].style.height = '170px';
  152. $('#dialog_container')[0].style.width = '800px';
  153. $('#dialog_container')[0].style.marginLeft = '-400px';
  154. // Open select-with-checkbox dialog
  155. $.select(
  156. uiStrings.confirmSetStorage.message,
  157. options,
  158. function (pref, checked) {
  159. // If the URL was configured to always insist on a prompt, if
  160. // the user does indicate a wish to store their info, we
  161. // don't want ask them again upon page refresh so move
  162. // them instead to a URL which does not always prompt
  163. if (storagePrompt === true && pref && pref !== 'noPrefsOrContent') {
  164. replaceStoragePrompt();
  165. return;
  166. }
  167. if (pref && pref !== 'noPrefsOrContent') {
  168. // Regardless of whether the user opted
  169. // to remember the choice (and move to a URL which won't
  170. // ask them again), we have to assume the user
  171. // doesn't even want to remember their not wanting
  172. // storage, so we don't set the cookie or continue on with
  173. // setting storage on beforeunload
  174. document.cookie = 'store=' + pref; // 'prefsAndContent' | 'prefsOnly'
  175. }
  176. else {
  177. if (emptyStorageOnDecline) {
  178. emptyLocalStorage();
  179. }
  180. if (checked) {
  181. // Open a URL which won't set storage and won't prompt user about storage
  182. replaceStoragePrompt('false');
  183. }
  184. }
  185. // Store the preference in memory (not currently in use)
  186. userStoragePref = pref;
  187. // Reset width/height of dialog (e.g., for use by Export)
  188. $('#dialog_container')[0].style.width = oldContainerWidth;
  189. $('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;
  190. $('#dialog_content')[0].style.height = oldContentHeight;
  191. $('#dialog_container')[0].style.height = oldContainerHeight;
  192. // It should be enough to (conditionally) add to storage on
  193. // beforeunload, but if we wished to update immediately,
  194. // we might wish to try setting:
  195. // Editor.preventStorageAccessOnLoad = true;
  196. // and then call:
  197. // Editor.loadContentAndPrefs();
  198. setupBeforeUnloadListener();
  199. Editor.storagePromptClosed = true;
  200. },
  201. null,
  202. null,
  203. {
  204. label: uiStrings.confirmSetStorage.rememberLabel,
  205. checked: false,
  206. tooltip: uiStrings.confirmSetStorage.rememberTooltip
  207. }
  208. );
  209. }
  210. else {
  211. setupBeforeUnloadListener();
  212. }
  213. }
  214. };
  215. });