From ab47958c9438d74685688d7215e72a1af1adf020 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sat, 4 Apr 2020 16:25:32 +0100 Subject: [PATCH 01/35] Support localStorage for storing settings --- www/js/lib/cookies.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index 87dc4475f..af193bda8 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -21,11 +21,35 @@ define([], function() { |*| \*/ +// Test for cookie support +var storeType = 'cookie'; +document.cookie = 'kiwixCookie=working;expires=Fri, 31 Dec 9999 23:59:59 GMT'; +var kiwixCookie = /kiwixCookie=working/i.test(document.cookie); +if (kiwixCookie) { + document.cookie = 'kiwixCookie=broken;expires=Fri, 31 Dec 9999 23:59:59 GMT'; + kiwixCookie = !/kiwixCookie=working/i.test(document.cookie); +} +document.cookie = 'kiwixCookie=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; +// Test for localStorage support +var localStorageTest = false; +try { + localStorageTest = 'localStorage' in window && window['localStorage'] !== null; +} catch (e) { + console.log('LocalStorage is not supported!'); +} +if (localStorageTest) storeType = 'local_storage'; +console.log('cookiesTest: storeType: ' + storeType); + var docCookies = { getItem: function (sKey) { + if (storeType === 'cookie') { return unescape(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; + } else { + return localStorage.getItem(sKey); + } }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { + if (storeType === 'cookie') { if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } var sExpires = ""; if (vEnd) { @@ -42,11 +66,18 @@ var docCookies = { } } document.cookie = escape(sKey) + "=" + escape(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); + } else { + localStorage.setItem(sKey, sValue); + } return true; }, removeItem: function (sKey, sPath) { + if (storeType === 'cookie') { if (!sKey || !this.hasItem(sKey)) { return false; } document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sPath ? "; path=" + sPath : ""); + } else { + localStorage.removeItem(sKey); + } return true; }, hasItem: function (sKey) { From 8046503a84155dfb5ba793d0e867bdd769313594 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sat, 4 Apr 2020 19:05:08 +0100 Subject: [PATCH 02/35] Put test into a function --- www/js/lib/cookies.js | 45 ++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index af193bda8..d425fa1d6 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -21,24 +21,29 @@ define([], function() { |*| \*/ -// Test for cookie support -var storeType = 'cookie'; -document.cookie = 'kiwixCookie=working;expires=Fri, 31 Dec 9999 23:59:59 GMT'; -var kiwixCookie = /kiwixCookie=working/i.test(document.cookie); -if (kiwixCookie) { +var storeType = testStorageSupport(); + +// Tests for cookie or localStorage support +function testStorageSupport() { + var type = 'cookie'; + document.cookie = 'kiwixCookie=working;expires=Fri, 31 Dec 9999 23:59:59 GMT'; + var kiwixCookie = /kiwixCookie=working/i.test(document.cookie); + if (kiwixCookie) { document.cookie = 'kiwixCookie=broken;expires=Fri, 31 Dec 9999 23:59:59 GMT'; kiwixCookie = !/kiwixCookie=working/i.test(document.cookie); -} -document.cookie = 'kiwixCookie=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; -// Test for localStorage support -var localStorageTest = false; -try { + } + document.cookie = 'kiwixCookie=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; + // Test for localStorage support + var localStorageTest = false; + try { localStorageTest = 'localStorage' in window && window['localStorage'] !== null; -} catch (e) { + } catch (e) { console.log('LocalStorage is not supported!'); + } + if (localStorageTest) type = 'local_storage'; + console.log('Storage test: type: ' + type); + return type; } -if (localStorageTest) storeType = 'local_storage'; -console.log('cookiesTest: storeType: ' + storeType); var docCookies = { getItem: function (sKey) { @@ -90,11 +95,11 @@ var docCookies = { } }; -return { - getItem: docCookies.getItem, - setItem: docCookies.setItem, - removeItem: docCookies.removeItem, - hasItem: docCookies.hasItem, - keys: docCookies.keys - }; + return { + getItem: docCookies.getItem, + setItem: docCookies.setItem, + removeItem: docCookies.removeItem, + hasItem: docCookies.hasItem, + keys: docCookies.keys + }; }); \ No newline at end of file From 98b5a0022ff06a8f1f8b6d2deef7425fa4d973cc Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 5 Apr 2020 13:19:38 +0100 Subject: [PATCH 03/35] Fix for IE11 --- www/js/lib/cookies.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index d425fa1d6..fa369d44e 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -37,7 +37,10 @@ function testStorageSupport() { var localStorageTest = false; try { localStorageTest = 'localStorage' in window && window['localStorage'] !== null; + localStorage.setItem('kiwixStorage', ''); + localStorage.removeItem('kiwixStorage'); } catch (e) { + localStorageTest = false; console.log('LocalStorage is not supported!'); } if (localStorageTest) type = 'local_storage'; From 1b3c505f9412fd8728c66ecaf2a92c7825718b81 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 5 Apr 2020 16:33:35 +0100 Subject: [PATCH 04/35] Add clearer documentation --- www/js/lib/cookies.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index fa369d44e..be5780f29 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -25,6 +25,8 @@ var storeType = testStorageSupport(); // Tests for cookie or localStorage support function testStorageSupport() { + // Test for cookie support + // DEV: In Firefox running from the file:// protocol, this test passes, but no cookie is stored between sessions var type = 'cookie'; document.cookie = 'kiwixCookie=working;expires=Fri, 31 Dec 9999 23:59:59 GMT'; var kiwixCookie = /kiwixCookie=working/i.test(document.cookie); @@ -33,7 +35,7 @@ function testStorageSupport() { kiwixCookie = !/kiwixCookie=working/i.test(document.cookie); } document.cookie = 'kiwixCookie=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; - // Test for localStorage support + // Now test for localStorage support var localStorageTest = false; try { localStorageTest = 'localStorage' in window && window['localStorage'] !== null; @@ -43,6 +45,8 @@ function testStorageSupport() { localStorageTest = false; console.log('LocalStorage is not supported!'); } + // Prefer localStorage if supported due to some platforms blocking cookies in local contexts + // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] if (localStorageTest) type = 'local_storage'; console.log('Storage test: type: ' + type); return type; From 2dc6fac72867af3248076a8ce2f92e17e5d01eb1 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 5 Apr 2020 16:42:33 +0100 Subject: [PATCH 05/35] More documentation --- www/js/lib/cookies.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index be5780f29..6463bfcca 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -39,8 +39,12 @@ function testStorageSupport() { var localStorageTest = false; try { localStorageTest = 'localStorage' in window && window['localStorage'] !== null; - localStorage.setItem('kiwixStorage', ''); - localStorage.removeItem('kiwixStorage'); + // DEV: Above test returns true in IE11 running from file:// protocol, but attempting to write a key to + // localStorage causes an exception; so to test fully, we must now attempt to write a key + if (localStorageTest) { + localStorage.setItem('kiwixStorage', ''); + localStorage.removeItem('kiwixStorage'); + } } catch (e) { localStorageTest = false; console.log('LocalStorage is not supported!'); From a078f230c455fb8fa4d279777ac1d4226873bb38 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 5 Apr 2020 17:46:26 +0100 Subject: [PATCH 06/35] Simplify code --- www/js/lib/cookies.js | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index 6463bfcca..227940d9a 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -23,24 +23,17 @@ define([], function() { var storeType = testStorageSupport(); -// Tests for cookie or localStorage support +// Tests for localStorage support function testStorageSupport() { - // Test for cookie support - // DEV: In Firefox running from the file:// protocol, this test passes, but no cookie is stored between sessions - var type = 'cookie'; - document.cookie = 'kiwixCookie=working;expires=Fri, 31 Dec 9999 23:59:59 GMT'; - var kiwixCookie = /kiwixCookie=working/i.test(document.cookie); - if (kiwixCookie) { - document.cookie = 'kiwixCookie=broken;expires=Fri, 31 Dec 9999 23:59:59 GMT'; - kiwixCookie = !/kiwixCookie=working/i.test(document.cookie); - } - document.cookie = 'kiwixCookie=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; - // Now test for localStorage support + // Prefer localStorage if supported due to some platforms blocking cookies in local contexts + // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] + var type = 'local_storage'; + // First test for localStorage support var localStorageTest = false; try { localStorageTest = 'localStorage' in window && window['localStorage'] !== null; // DEV: Above test returns true in IE11 running from file:// protocol, but attempting to write a key to - // localStorage causes an exception; so to test fully, we must now attempt to write a key + // localStorage causes an exception; so to test fully, we must now attempt to write and remove a test key if (localStorageTest) { localStorage.setItem('kiwixStorage', ''); localStorage.removeItem('kiwixStorage'); @@ -49,9 +42,8 @@ function testStorageSupport() { localStorageTest = false; console.log('LocalStorage is not supported!'); } - // Prefer localStorage if supported due to some platforms blocking cookies in local contexts - // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] - if (localStorageTest) type = 'local_storage'; + // Fall back to cookie if localStorage fails + if (!localStorageTest) type = 'cookie'; console.log('Storage test: type: ' + type); return type; } From abf0bd4bde387cd8fff0bd6e4011f6abf05e060d Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 5 Apr 2020 18:04:08 +0100 Subject: [PATCH 07/35] Better format of console log message --- www/js/lib/cookies.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index 227940d9a..e943382a4 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -44,7 +44,7 @@ function testStorageSupport() { } // Fall back to cookie if localStorage fails if (!localStorageTest) type = 'cookie'; - console.log('Storage test: type: ' + type); + console.log('Storage test: type = ' + type); return type; } From 2c10e743e4da880459fbee33ce72146e64321fe1 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 5 Apr 2020 18:11:47 +0100 Subject: [PATCH 08/35] Fix some review requests --- www/js/lib/cookies.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index e943382a4..1adbd9f9b 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -35,12 +35,11 @@ function testStorageSupport() { // DEV: Above test returns true in IE11 running from file:// protocol, but attempting to write a key to // localStorage causes an exception; so to test fully, we must now attempt to write and remove a test key if (localStorageTest) { - localStorage.setItem('kiwixStorage', ''); - localStorage.removeItem('kiwixStorage'); + localStorage.setItem('temporaryKiwixStorageTest', ''); + localStorage.removeItem('temporaryKiwixStorageTest'); } } catch (e) { localStorageTest = false; - console.log('LocalStorage is not supported!'); } // Fall back to cookie if localStorage fails if (!localStorageTest) type = 'cookie'; From 45244e6015d6cc07e653ac2e84901c83467188b2 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Mon, 6 Apr 2020 07:41:48 +0100 Subject: [PATCH 09/35] Report API in status panel --- www/index.html | 1 + www/js/lib/cookies.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/www/index.html b/www/index.html index 35284f925..130ab4695 100644 --- a/www/index.html +++ b/www/index.html @@ -339,6 +339,7 @@

Expert settings

+
diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index 1adbd9f9b..46dac49be 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -43,7 +43,9 @@ function testStorageSupport() { } // Fall back to cookie if localStorage fails if (!localStorageTest) type = 'cookie'; - console.log('Storage test: type = ' + type); + // Update API panel with API name + var apiName = type === 'cookie' ? 'Cookie' : 'Local Storage'; + document.getElementById('settingsStoreStatus').innerHTML = 'Settings Storage API in use: ' + apiName; return type; } From 3acae3e0d0a024f50df608810f6923bf0e1fcf9a Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Mon, 6 Apr 2020 08:31:28 +0100 Subject: [PATCH 10/35] Complete API and status panel --- www/js/lib/cookies.js | 92 +++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index 46dac49be..3005cf491 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -2,9 +2,9 @@ define([], function() { /*\ |*| -|*| :: cookies.js :: +|*| :: settingsStore.js :: |*| -|*| A complete cookies reader/writer framework with full unicode support. +|*| A reader/writer framework for cookies or localStorage with full unicode support. |*| |*| https://developer.mozilla.org/en-US/docs/DOM/document.cookie |*| @@ -23,33 +23,43 @@ define([], function() { var storeType = testStorageSupport(); -// Tests for localStorage support +// Tests for localStorage or cookie support function testStorageSupport() { - // Prefer localStorage if supported due to some platforms blocking cookies in local contexts // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] - var type = 'local_storage'; - // First test for localStorage support - var localStorageTest = false; + var type = 'none'; + // First test for localStorage API support + var localStorageTest; try { localStorageTest = 'localStorage' in window && window['localStorage'] !== null; // DEV: Above test returns true in IE11 running from file:// protocol, but attempting to write a key to // localStorage causes an exception; so to test fully, we must now attempt to write and remove a test key if (localStorageTest) { - localStorage.setItem('temporaryKiwixStorageTest', ''); - localStorage.removeItem('temporaryKiwixStorageTest'); + localStorage.setItem('tempKiwixStorageTest', ''); + localStorage.removeItem('tempKiwixStorageTest'); } } catch (e) { localStorageTest = false; } - // Fall back to cookie if localStorage fails - if (!localStorageTest) type = 'cookie'; + // Now test for document.cookie API support + document.cookie = 'tempKiwixCookieTest=working;expires=Fri, 31 Dec 9999 23:59:59 GMT'; + var kiwixCookieTest = /tempKiwixCookieTest=working/.test(document.cookie); + // Remove test value by expiring the key + document.cookie = 'tempKiwixCookieTest=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; + if (kiwixCookieTest) type = 'cookie'; + // Prefer localStorage if supported due to some platforms removing cookies once the session ends in some contexts + if (localStorageTest) type = 'local_storage'; // Update API panel with API name - var apiName = type === 'cookie' ? 'Cookie' : 'Local Storage'; - document.getElementById('settingsStoreStatus').innerHTML = 'Settings Storage API in use: ' + apiName; + var settingsStoreStatusDiv = document.getElementById('settingsStoreStatus'); + var apiName = type === 'cookie' ? 'Cookie' : type === 'local_storage' ? 'Local Storage' : 'None'; + settingsStoreStatusDiv.innerHTML = 'Settings Storage API in use: ' + apiName; + settingsStoreStatusDiv.classList.remove('apiAvailable', 'apiUnavailable'); + settingsStoreStatusDiv.classList.add(type === 'none' ? 'apiUnavailable' : 'apiAvailable'); + // To simplify code below, this function returns either 'local_storage' or 'cookie', but does not return 'none' + // This is because setting a cookie key does not cause an exception even if it is not stored (e.g. in an Extension) return type; } -var docCookies = { +var settingsStore = { getItem: function (sKey) { if (storeType === 'cookie') { return unescape(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; @@ -59,22 +69,22 @@ var docCookies = { }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { if (storeType === 'cookie') { - if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } - var sExpires = ""; - if (vEnd) { - switch (vEnd.constructor) { - case Number: - sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; - break; - case String: - sExpires = "; expires=" + vEnd; - break; - case Date: - sExpires = "; expires=" + vEnd.toGMTString(); - break; + if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } + var sExpires = ""; + if (vEnd) { + switch (vEnd.constructor) { + case Number: + sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; + break; + case String: + sExpires = "; expires=" + vEnd; + break; + case Date: + sExpires = "; expires=" + vEnd.toGMTString(); + break; + } } - } - document.cookie = escape(sKey) + "=" + escape(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); + document.cookie = escape(sKey) + "=" + escape(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); } else { localStorage.setItem(sKey, sValue); } @@ -82,28 +92,26 @@ var docCookies = { }, removeItem: function (sKey, sPath) { if (storeType === 'cookie') { - if (!sKey || !this.hasItem(sKey)) { return false; } - document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sPath ? "; path=" + sPath : ""); + if (!sKey || !this.hasItem(sKey)) { return false; } + document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sPath ? "; path=" + sPath : ""); } else { localStorage.removeItem(sKey); } return true; }, hasItem: function (sKey) { - return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); - }, - keys: /* optional method: you can safely remove it! */ function () { - var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); - for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = unescape(aKeys[nIdx]); } - return aKeys; + if (storeType === 'cookie') { + return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); + } else { + return localStorage.getItem(sKey) === null ? false : true; + } } }; return { - getItem: docCookies.getItem, - setItem: docCookies.setItem, - removeItem: docCookies.removeItem, - hasItem: docCookies.hasItem, - keys: docCookies.keys + getItem: settingsStore.getItem, + setItem: settingsStore.setItem, + removeItem: settingsStore.removeItem, + hasItem: settingsStore.hasItem }; }); \ No newline at end of file From 6394eae890b001cd06aad56dd4bba52a1fb934fc Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Mon, 6 Apr 2020 08:48:56 +0100 Subject: [PATCH 11/35] Update latest Mozilla cookies framework Fixes #438 --- www/js/lib/cookies.js | 44 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js index 3005cf491..cba1b1507 100644 --- a/www/js/lib/cookies.js +++ b/www/js/lib/cookies.js @@ -4,20 +4,22 @@ define([], function() { |*| |*| :: settingsStore.js :: |*| -|*| A reader/writer framework for cookies or localStorage with full unicode support. +|*| A reader/writer framework for cookies or localStorage with full unicode support based on Mozilla cookie framework. |*| -|*| https://developer.mozilla.org/en-US/docs/DOM/document.cookie +|*| Revision #1 - September 4, 2014 +|*| +|*| https://developer.mozilla.org/en-US/docs/Web/API/document.cookie +|*| https://developer.mozilla.org/User:fusionchess |*| |*| This framework is released under the GNU Public License, version 3 or later. |*| http://www.gnu.org/licenses/gpl-3.0-standalone.html |*| |*| Syntaxes: |*| -|*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]]) -|*| * docCookies.getItem(name) -|*| * docCookies.removeItem(name[, path]) -|*| * docCookies.hasItem(name) -|*| * docCookies.keys() +|*| * settingsStore.setItem(name, value[, end[, path[, domain[, secure]]]]) +|*| * settingsStore.getItem(name) +|*| * settingsStore.removeItem(name[, path[, domain]]) +|*| * settingsStore.hasItem(name) |*| \*/ @@ -62,14 +64,19 @@ function testStorageSupport() { var settingsStore = { getItem: function (sKey) { if (storeType === 'cookie') { - return unescape(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; + if (!sKey) { + return null; + } + return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; } else { return localStorage.getItem(sKey); } }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { if (storeType === 'cookie') { - if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } + if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { + return false; + } var sExpires = ""; if (vEnd) { switch (vEnd.constructor) { @@ -80,28 +87,33 @@ var settingsStore = { sExpires = "; expires=" + vEnd; break; case Date: - sExpires = "; expires=" + vEnd.toGMTString(); + sExpires = "; expires=" + vEnd.toUTCString(); break; } } - document.cookie = escape(sKey) + "=" + escape(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); + document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); } else { localStorage.setItem(sKey, sValue); } return true; }, - removeItem: function (sKey, sPath) { + removeItem: function (sKey, sPath, sDomain) { + if (!this.hasItem(sKey)) { + return false; + } if (storeType === 'cookie') { - if (!sKey || !this.hasItem(sKey)) { return false; } - document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sPath ? "; path=" + sPath : ""); + document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); } else { localStorage.removeItem(sKey); - } + } return true; }, hasItem: function (sKey) { + if (!sKey) { + return false; + } if (storeType === 'cookie') { - return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); + return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); } else { return localStorage.getItem(sKey) === null ? false : true; } From 612d90f9de125cf29d3c59788d27eb1e144b51ff Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Mon, 6 Apr 2020 09:10:14 +0100 Subject: [PATCH 12/35] Rename cookies.js to settingsStore.js --- nbproject/project.properties | 2 +- www/js/app.js | 34 ++++----- www/js/lib/cookies.js | 129 ----------------------------------- www/js/lib/settingsStore.js | 129 +++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 147 deletions(-) delete mode 100644 www/js/lib/cookies.js create mode 100644 www/js/lib/settingsStore.js diff --git a/nbproject/project.properties b/nbproject/project.properties index cee96d90b..da5520123 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -1,5 +1,5 @@ auxiliary.org-netbeans-modules-javascript2-requirejs.enabled=true -auxiliary.org-netbeans-modules-javascript2-requirejs.mappings={zimArchiveLoader , www/js/lib/zimArchiveLoader.js}{cookies , www/js/lib/cookies.js}{jquery , www/js/lib/jquery-3.2.1.slim.js}{abstractFilesystemAccess , www/js/lib/abstractFilesystemAccess.js}{q , www/js/lib/q.js}{uiUtil , www/js/lib/uiUtil.js}{utf8 , www/js/lib/utf8.js}{util , www/js/lib/util.js}{xzdec_wrapper , www/js/lib/xzdec_wrapper.js}{zimArchive , www/js/lib/zimArchive.js}{zimDirEntry , www/js/lib/zimDirEntry.js}{zimfile , www/js/lib/zimfile.js} +auxiliary.org-netbeans-modules-javascript2-requirejs.mappings={zimArchiveLoader , www/js/lib/zimArchiveLoader.js}{settingsStore , www/js/lib/settingsStore.js}{jquery , www/js/lib/jquery-3.2.1.slim.js}{abstractFilesystemAccess , www/js/lib/abstractFilesystemAccess.js}{q , www/js/lib/q.js}{uiUtil , www/js/lib/uiUtil.js}{utf8 , www/js/lib/utf8.js}{util , www/js/lib/util.js}{xzdec_wrapper , www/js/lib/xzdec_wrapper.js}{zimArchive , www/js/lib/zimArchive.js}{zimDirEntry , www/js/lib/zimDirEntry.js}{zimfile , www/js/lib/zimfile.js} config.folder= file.reference.git-kiwix-js=. files.encoding=UTF-8 diff --git a/www/js/app.js b/www/js/app.js index 843119850..50b4fcdaa 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -26,8 +26,8 @@ // This uses require.js to structure javascript: // http://requirejs.org/docs/api.html#define -define(['jquery', 'zimArchiveLoader', 'uiUtil', 'cookies','abstractFilesystemAccess','q'], - function($, zimArchiveLoader, uiUtil, cookies, abstractFilesystemAccess, Q) { +define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesystemAccess','q'], + function($, zimArchiveLoader, uiUtil, settingsStore, abstractFilesystemAccess, Q) { /** * Maximum number of articles to display in a search @@ -67,14 +67,14 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'cookies','abstractFilesystemAcc // Set parameters and associated UI elements from cookie // DEV: The params global object is declared in init.js so that it is available to modules - params['hideActiveContentWarning'] = cookies.getItem('hideActiveContentWarning') === 'true'; - params['showUIAnimations'] = cookies.getItem('showUIAnimations') ? cookies.getItem('showUIAnimations') === 'true' : true; + params['hideActiveContentWarning'] = settingsStore.getItem('hideActiveContentWarning') === 'true'; + params['showUIAnimations'] = settingsStore.getItem('showUIAnimations') ? settingsStore.getItem('showUIAnimations') === 'true' : true; document.getElementById('hideActiveContentWarningCheck').checked = params.hideActiveContentWarning; document.getElementById('showUIAnimationsCheck').checked = params.showUIAnimations; // A global parameter that turns caching on or off and deletes the cache (it defaults to true unless explicitly turned off in UI) - params['useCache'] = cookies.getItem('useCache') !== 'false'; + params['useCache'] = settingsStore.getItem('useCache') !== 'false'; // A parameter to set the app theme and, if necessary, the CSS theme for article content (defaults to 'light') - params['appTheme'] = cookies.getItem('appTheme') || 'light'; // Currently implemented: light|dark|dark_invert|dark_mwInvert + params['appTheme'] = settingsStore.getItem('appTheme') || 'light'; // Currently implemented: light|dark|dark_invert|dark_mwInvert document.getElementById('appThemeSelect').value = params.appTheme; uiUtil.applyAppTheme(params.appTheme); @@ -322,27 +322,27 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'cookies','abstractFilesystemAcc }); $('input:checkbox[name=hideActiveContentWarning]').on('change', function (e) { params.hideActiveContentWarning = this.checked ? true : false; - cookies.setItem('hideActiveContentWarning', params.hideActiveContentWarning, Infinity); + settingsStore.setItem('hideActiveContentWarning', params.hideActiveContentWarning, Infinity); }); $('input:checkbox[name=showUIAnimations]').on('change', function (e) { params.showUIAnimations = this.checked ? true : false; - cookies.setItem('showUIAnimations', params.showUIAnimations, Infinity); + settingsStore.setItem('showUIAnimations', params.showUIAnimations, Infinity); }); document.getElementById('appThemeSelect').addEventListener('change', function (e) { params.appTheme = e.target.value; - cookies.setItem('appTheme', params.appTheme, Infinity); + settingsStore.setItem('appTheme', params.appTheme, Infinity); uiUtil.applyAppTheme(params.appTheme); }); document.getElementById('cachedAssetsModeRadioTrue').addEventListener('change', function (e) { if (e.target.checked) { - cookies.setItem('useCache', true, Infinity); + settingsStore.setItem('useCache', true, Infinity); params.useCache = true; refreshCacheStatus(); } }); document.getElementById('cachedAssetsModeRadioFalse').addEventListener('change', function (e) { if (e.target.checked) { - cookies.setItem('useCache', false, Infinity); + settingsStore.setItem('useCache', false, Infinity); params.useCache = false; // Delete all caches resetCssCache(); @@ -561,12 +561,12 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'cookies','abstractFilesystemAcc $('input:radio[name=contentInjectionMode]').filter('[value="' + value + '"]').prop('checked', true); contentInjectionMode = value; // Save the value in a cookie, so that to be able to keep it after a reload/restart - cookies.setItem('lastContentInjectionMode', value, Infinity); + settingsStore.setItem('lastContentInjectionMode', value, Infinity); refreshCacheStatus(); } // At launch, we try to set the last content injection mode (stored in a cookie) - var lastContentInjectionMode = cookies.getItem('lastContentInjectionMode'); + var lastContentInjectionMode = settingsStore.getItem('lastContentInjectionMode'); if (lastContentInjectionMode) { setContentInjectionMode(lastContentInjectionMode); } @@ -621,7 +621,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'cookies','abstractFilesystemAcc var storages = []; function searchForArchivesInPreferencesOrStorage() { // First see if the list of archives is stored in the cookie - var listOfArchivesFromCookie = cookies.getItem("listOfArchives"); + var listOfArchivesFromCookie = settingsStore.getItem("listOfArchives"); if (listOfArchivesFromCookie !== null && listOfArchivesFromCookie !== undefined && listOfArchivesFromCookie !== "") { var directories = listOfArchivesFromCookie.split('|'); populateDropDownListOfArchives(directories); @@ -707,11 +707,11 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'cookies','abstractFilesystemAcc } } // Store the list of archives in a cookie, to avoid rescanning at each start - cookies.setItem("listOfArchives", archiveDirectories.join('|'), Infinity); + settingsStore.setItem("listOfArchives", archiveDirectories.join('|'), Infinity); $('#archiveList').on('change', setLocalArchiveFromArchiveList); if (comboArchiveList.options.length > 0) { - var lastSelectedArchive = cookies.getItem("lastSelectedArchive"); + var lastSelectedArchive = settingsStore.getItem("lastSelectedArchive"); if (lastSelectedArchive !== null && lastSelectedArchive !== undefined && lastSelectedArchive !== "") { // Attempt to select the corresponding item in the list, if it exists if ($("#archiveList option[value='"+lastSelectedArchive+"']").length > 0) { @@ -770,7 +770,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'cookies','abstractFilesystemAcc } resetCssCache(); selectedArchive = zimArchiveLoader.loadArchiveFromDeviceStorage(selectedStorage, archiveDirectory, function (archive) { - cookies.setItem("lastSelectedArchive", archiveDirectory, Infinity); + settingsStore.setItem("lastSelectedArchive", archiveDirectory, Infinity); // The archive is set : go back to home page to start searching $("#btnHome").click(); }); diff --git a/www/js/lib/cookies.js b/www/js/lib/cookies.js deleted file mode 100644 index cba1b1507..000000000 --- a/www/js/lib/cookies.js +++ /dev/null @@ -1,129 +0,0 @@ -'use strict'; -define([], function() { -/*\ -|*| -|*| :: settingsStore.js :: -|*| -|*| A reader/writer framework for cookies or localStorage with full unicode support based on Mozilla cookie framework. -|*| -|*| Revision #1 - September 4, 2014 -|*| -|*| https://developer.mozilla.org/en-US/docs/Web/API/document.cookie -|*| https://developer.mozilla.org/User:fusionchess -|*| -|*| This framework is released under the GNU Public License, version 3 or later. -|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html -|*| -|*| Syntaxes: -|*| -|*| * settingsStore.setItem(name, value[, end[, path[, domain[, secure]]]]) -|*| * settingsStore.getItem(name) -|*| * settingsStore.removeItem(name[, path[, domain]]) -|*| * settingsStore.hasItem(name) -|*| -\*/ - -var storeType = testStorageSupport(); - -// Tests for localStorage or cookie support -function testStorageSupport() { - // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] - var type = 'none'; - // First test for localStorage API support - var localStorageTest; - try { - localStorageTest = 'localStorage' in window && window['localStorage'] !== null; - // DEV: Above test returns true in IE11 running from file:// protocol, but attempting to write a key to - // localStorage causes an exception; so to test fully, we must now attempt to write and remove a test key - if (localStorageTest) { - localStorage.setItem('tempKiwixStorageTest', ''); - localStorage.removeItem('tempKiwixStorageTest'); - } - } catch (e) { - localStorageTest = false; - } - // Now test for document.cookie API support - document.cookie = 'tempKiwixCookieTest=working;expires=Fri, 31 Dec 9999 23:59:59 GMT'; - var kiwixCookieTest = /tempKiwixCookieTest=working/.test(document.cookie); - // Remove test value by expiring the key - document.cookie = 'tempKiwixCookieTest=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; - if (kiwixCookieTest) type = 'cookie'; - // Prefer localStorage if supported due to some platforms removing cookies once the session ends in some contexts - if (localStorageTest) type = 'local_storage'; - // Update API panel with API name - var settingsStoreStatusDiv = document.getElementById('settingsStoreStatus'); - var apiName = type === 'cookie' ? 'Cookie' : type === 'local_storage' ? 'Local Storage' : 'None'; - settingsStoreStatusDiv.innerHTML = 'Settings Storage API in use: ' + apiName; - settingsStoreStatusDiv.classList.remove('apiAvailable', 'apiUnavailable'); - settingsStoreStatusDiv.classList.add(type === 'none' ? 'apiUnavailable' : 'apiAvailable'); - // To simplify code below, this function returns either 'local_storage' or 'cookie', but does not return 'none' - // This is because setting a cookie key does not cause an exception even if it is not stored (e.g. in an Extension) - return type; -} - -var settingsStore = { - getItem: function (sKey) { - if (storeType === 'cookie') { - if (!sKey) { - return null; - } - return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; - } else { - return localStorage.getItem(sKey); - } - }, - setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { - if (storeType === 'cookie') { - if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { - return false; - } - var sExpires = ""; - if (vEnd) { - switch (vEnd.constructor) { - case Number: - sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; - break; - case String: - sExpires = "; expires=" + vEnd; - break; - case Date: - sExpires = "; expires=" + vEnd.toUTCString(); - break; - } - } - document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); - } else { - localStorage.setItem(sKey, sValue); - } - return true; - }, - removeItem: function (sKey, sPath, sDomain) { - if (!this.hasItem(sKey)) { - return false; - } - if (storeType === 'cookie') { - document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); - } else { - localStorage.removeItem(sKey); - } - return true; - }, - hasItem: function (sKey) { - if (!sKey) { - return false; - } - if (storeType === 'cookie') { - return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); - } else { - return localStorage.getItem(sKey) === null ? false : true; - } - } -}; - - return { - getItem: settingsStore.getItem, - setItem: settingsStore.setItem, - removeItem: settingsStore.removeItem, - hasItem: settingsStore.hasItem - }; -}); \ No newline at end of file diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js new file mode 100644 index 000000000..f0ba0b568 --- /dev/null +++ b/www/js/lib/settingsStore.js @@ -0,0 +1,129 @@ +'use strict'; +define([], function () { + /*\ + |*| + |*| :: settingsStore.js :: + |*| + |*| A reader/writer framework for cookies or localStorage with full unicode support based on Mozilla cookies framework. + |*| + |*| Revision #1 - September 4, 2014 + |*| + |*| https://developer.mozilla.org/en-US/docs/Web/API/document.cookie + |*| https://developer.mozilla.org/User:fusionchess + |*| + |*| This framework is released under the GNU Public License, version 3 or later. + |*| http://www.gnu.org/licenses/gpl-3.0-standalone.html + |*| + |*| Syntaxes: + |*| + |*| * settingsStore.setItem(name, value[, end[, path[, domain[, secure]]]]) + |*| * settingsStore.getItem(name) + |*| * settingsStore.removeItem(name[, path[, domain]]) + |*| * settingsStore.hasItem(name) + |*| + \*/ + + var storeType = testStorageSupport(); + + // Tests for localStorage or cookie support + function testStorageSupport() { + // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] + var type = 'none'; + // First test for localStorage API support + var localStorageTest; + try { + localStorageTest = 'localStorage' in window && window['localStorage'] !== null; + // DEV: Above test returns true in IE11 running from file:// protocol, but attempting to write a key to + // localStorage causes an exception; so to test fully, we must now attempt to write and remove a test key + if (localStorageTest) { + localStorage.setItem('tempKiwixStorageTest', ''); + localStorage.removeItem('tempKiwixStorageTest'); + } + } catch (e) { + localStorageTest = false; + } + // Now test for document.cookie API support + document.cookie = 'tempKiwixCookieTest=working;expires=Fri, 31 Dec 9999 23:59:59 GMT'; + var kiwixCookieTest = /tempKiwixCookieTest=working/.test(document.cookie); + // Remove test value by expiring the key + document.cookie = 'tempKiwixCookieTest=;expires=Thu, 01 Jan 1970 00:00:00 GMT'; + if (kiwixCookieTest) type = 'cookie'; + // Prefer localStorage if supported due to some platforms removing cookies once the session ends in some contexts + if (localStorageTest) type = 'local_storage'; + // Update API panel with API name + var settingsStoreStatusDiv = document.getElementById('settingsStoreStatus'); + var apiName = type === 'cookie' ? 'Cookie' : type === 'local_storage' ? 'Local Storage' : 'None'; + settingsStoreStatusDiv.innerHTML = 'Settings Storage API in use: ' + apiName; + settingsStoreStatusDiv.classList.remove('apiAvailable', 'apiUnavailable'); + settingsStoreStatusDiv.classList.add(type === 'none' ? 'apiUnavailable' : 'apiAvailable'); + // To simplify code below, this function returns either 'local_storage' or 'cookie', but does not return 'none' + // This is because setting a cookie key does not cause an exception even if it is not stored (e.g. in an Extension) + return type; + } + + var settingsStore = { + getItem: function (sKey) { + if (storeType === 'cookie') { + if (!sKey) { + return null; + } + return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; + } else { + return localStorage.getItem(sKey); + } + }, + setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { + if (storeType === 'cookie') { + if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { + return false; + } + var sExpires = ""; + if (vEnd) { + switch (vEnd.constructor) { + case Number: + sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; + break; + case String: + sExpires = "; expires=" + vEnd; + break; + case Date: + sExpires = "; expires=" + vEnd.toUTCString(); + break; + } + } + document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); + } else { + localStorage.setItem(sKey, sValue); + } + return true; + }, + removeItem: function (sKey, sPath, sDomain) { + if (!this.hasItem(sKey)) { + return false; + } + if (storeType === 'cookie') { + document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); + } else { + localStorage.removeItem(sKey); + } + return true; + }, + hasItem: function (sKey) { + if (!sKey) { + return false; + } + if (storeType === 'cookie') { + return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); + } else { + return localStorage.getItem(sKey) === null ? false : true; + } + } + }; + + return { + getItem: settingsStore.getItem, + setItem: settingsStore.setItem, + removeItem: settingsStore.removeItem, + hasItem: settingsStore.hasItem + }; +}); \ No newline at end of file From 7a2e7b51e19f2f275aaee4e766931d918b2cdf1f Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Wed, 8 Apr 2020 12:27:20 +0100 Subject: [PATCH 13/35] Ensure cookies implementation runs even if storeType is 'none' --- www/js/lib/settingsStore.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index f0ba0b568..90d315637 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -56,14 +56,14 @@ define([], function () { settingsStoreStatusDiv.innerHTML = 'Settings Storage API in use: ' + apiName; settingsStoreStatusDiv.classList.remove('apiAvailable', 'apiUnavailable'); settingsStoreStatusDiv.classList.add(type === 'none' ? 'apiUnavailable' : 'apiAvailable'); - // To simplify code below, this function returns either 'local_storage' or 'cookie', but does not return 'none' - // This is because setting a cookie key does not cause an exception even if it is not stored (e.g. in an Extension) + // Note that if this function returns 'none', the cookie implementations below will run anyway. This is because storing a cookie + // does not cause an exception even if cookies are blocked in some contexts, whereas accessing localStorage may cause an exception return type; } var settingsStore = { getItem: function (sKey) { - if (storeType === 'cookie') { + if (storeType !== 'local_storage') { if (!sKey) { return null; } @@ -73,7 +73,7 @@ define([], function () { } }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { - if (storeType === 'cookie') { + if (storeType !== 'local_storage') { if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } @@ -101,7 +101,7 @@ define([], function () { if (!this.hasItem(sKey)) { return false; } - if (storeType === 'cookie') { + if (storeType !== 'local_storage') { document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); } else { localStorage.removeItem(sKey); @@ -112,7 +112,7 @@ define([], function () { if (!sKey) { return false; } - if (storeType === 'cookie') { + if (storeType !== 'local_storage') { return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); } else { return localStorage.getItem(sKey) === null ? false : true; From f683aad023700737db6e78fa7b84c01d542b992d Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Wed, 8 Apr 2020 14:09:12 +0100 Subject: [PATCH 14/35] Move API panel-setting code to app.js --- www/js/app.js | 15 ++++++++++++--- www/js/lib/settingsStore.js | 19 ++++++------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/www/js/app.js b/www/js/app.js index 50b4fcdaa..f7dd41b3a 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -65,8 +65,9 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys */ var selectedArchive = null; - // Set parameters and associated UI elements from cookie + // Set parameters and associated UI elements from the Settings Store // DEV: The params global object is declared in init.js so that it is available to modules + params['storeType'] = settingsStore.testStorageSupport(); // A parameter to determine the Settings Store API in use params['hideActiveContentWarning'] = settingsStore.getItem('hideActiveContentWarning') === 'true'; params['showUIAnimations'] = settingsStore.getItem('showUIAnimations') ? settingsStore.getItem('showUIAnimations') === 'true' : true; document.getElementById('hideActiveContentWarningCheck').checked = params.hideActiveContentWarning; @@ -77,7 +78,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys params['appTheme'] = settingsStore.getItem('appTheme') || 'light'; // Currently implemented: light|dark|dark_invert|dark_mwInvert document.getElementById('appThemeSelect').value = params.appTheme; uiUtil.applyAppTheme(params.appTheme); - + // Define globalDropZone (universal drop area) and configDropZone (highlighting area on Config page) var globalDropZone = document.getElementById('search-article'); var configDropZone = document.getElementById('configuration'); @@ -385,8 +386,16 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys $('#serviceWorkerStatus').removeClass("apiAvailable apiUnavailable") .addClass("apiUnavailable"); } - apiStatusPanel.classList.add(apiPanelClass); + // Update Settings Store section of API panel with API name + var settingsStoreStatusDiv = document.getElementById('settingsStoreStatus'); + var apiName = params.storeType === 'cookie' ? 'Cookie' : params.storeType === 'local_storage' ? 'Local Storage' : 'None'; + settingsStoreStatusDiv.innerHTML = 'Settings Storage API in use: ' + apiName; + settingsStoreStatusDiv.classList.remove('apiAvailable', 'apiUnavailable'); + settingsStoreStatusDiv.classList.add(params.storeType === 'none' ? 'apiUnavailable' : 'apiAvailable'); + apiPanelClass = params.storeType === 'none' ? 'card-warning' : apiPanelClass; + // Add a warning colour to the API Status Panel if any of the above tests failed + apiStatusPanel.classList.add(apiPanelClass); } /** diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 90d315637..d9942561f 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -23,8 +23,6 @@ define([], function () { |*| \*/ - var storeType = testStorageSupport(); - // Tests for localStorage or cookie support function testStorageSupport() { // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] @@ -50,12 +48,6 @@ define([], function () { if (kiwixCookieTest) type = 'cookie'; // Prefer localStorage if supported due to some platforms removing cookies once the session ends in some contexts if (localStorageTest) type = 'local_storage'; - // Update API panel with API name - var settingsStoreStatusDiv = document.getElementById('settingsStoreStatus'); - var apiName = type === 'cookie' ? 'Cookie' : type === 'local_storage' ? 'Local Storage' : 'None'; - settingsStoreStatusDiv.innerHTML = 'Settings Storage API in use: ' + apiName; - settingsStoreStatusDiv.classList.remove('apiAvailable', 'apiUnavailable'); - settingsStoreStatusDiv.classList.add(type === 'none' ? 'apiUnavailable' : 'apiAvailable'); // Note that if this function returns 'none', the cookie implementations below will run anyway. This is because storing a cookie // does not cause an exception even if cookies are blocked in some contexts, whereas accessing localStorage may cause an exception return type; @@ -63,7 +55,7 @@ define([], function () { var settingsStore = { getItem: function (sKey) { - if (storeType !== 'local_storage') { + if (params.storeType !== 'local_storage') { if (!sKey) { return null; } @@ -73,7 +65,7 @@ define([], function () { } }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { - if (storeType !== 'local_storage') { + if (params.storeType !== 'local_storage') { if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } @@ -101,7 +93,7 @@ define([], function () { if (!this.hasItem(sKey)) { return false; } - if (storeType !== 'local_storage') { + if (params.storeType !== 'local_storage') { document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); } else { localStorage.removeItem(sKey); @@ -112,7 +104,7 @@ define([], function () { if (!sKey) { return false; } - if (storeType !== 'local_storage') { + if (params.storeType !== 'local_storage') { return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); } else { return localStorage.getItem(sKey) === null ? false : true; @@ -124,6 +116,7 @@ define([], function () { getItem: settingsStore.getItem, setItem: settingsStore.setItem, removeItem: settingsStore.removeItem, - hasItem: settingsStore.hasItem + hasItem: settingsStore.hasItem, + testStorageSupport: testStorageSupport }; }); \ No newline at end of file From 03727d5555325a361e3b48ce4759471efdf9461d Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 07:02:23 +0100 Subject: [PATCH 15/35] Codefactor changes (unnecessary escape characters) --- www/js/lib/settingsStore.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index d9942561f..8d1cca48b 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -59,14 +59,14 @@ define([], function () { if (!sKey) { return null; } - return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; + return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; } else { return localStorage.getItem(sKey); } }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { if (params.storeType !== 'local_storage') { - if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { + if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) { return false; } var sExpires = ""; @@ -105,7 +105,7 @@ define([], function () { return false; } if (params.storeType !== 'local_storage') { - return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); + return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); } else { return localStorage.getItem(sKey) === null ? false : true; } From 86dbbb9853087a9a160011b32a7390f86ba82bb5 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 08:55:35 +0100 Subject: [PATCH 16/35] Use standard format for header --- www/js/lib/settingsStore.js | 49 ++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 8d1cca48b..47beb2ece 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -1,28 +1,31 @@ 'use strict'; define([], function () { - /*\ - |*| - |*| :: settingsStore.js :: - |*| - |*| A reader/writer framework for cookies or localStorage with full unicode support based on Mozilla cookies framework. - |*| - |*| Revision #1 - September 4, 2014 - |*| - |*| https://developer.mozilla.org/en-US/docs/Web/API/document.cookie - |*| https://developer.mozilla.org/User:fusionchess - |*| - |*| This framework is released under the GNU Public License, version 3 or later. - |*| http://www.gnu.org/licenses/gpl-3.0-standalone.html - |*| - |*| Syntaxes: - |*| - |*| * settingsStore.setItem(name, value[, end[, path[, domain[, secure]]]]) - |*| * settingsStore.getItem(name) - |*| * settingsStore.removeItem(name[, path[, domain]]) - |*| * settingsStore.hasItem(name) - |*| - \*/ - + /** + * settingsStore.js + * + * A reader/writer framework for cookies or localStorage with full unicode support based on the Mozilla cookies framework. + * The Mozilla code has been adapted to return Boolean values instead of 'true' or 'false' strings, and support for + * the localStorage API has been added. + * + * Mozilla version information: + * + * Revision #1 - September 4, 2014 + * + * https://developer.mozilla.org/en-US/docs/Web/API/document.cookie + * https://developer.mozilla.org/User:fusionchess + * + * This framework is released under the GNU Public License, version 3 or later. + * http://www.gnu.org/licenses/gpl-3.0-standalone.html + * + * Syntaxes: + * + * * settingsStore.setItem(name, value[, end[, path[, domain[, secure]]]]) + * * settingsStore.getItem(name) + * * settingsStore.removeItem(name[, path[, domain]]) + * * settingsStore.hasItem(name) + * + */ + // Tests for localStorage or cookie support function testStorageSupport() { // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] From b9f1323984669c16644b58bdaed8e783faf0f595 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 08:57:01 +0100 Subject: [PATCH 17/35] Return Boolean values from cookie --- www/js/lib/settingsStore.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 47beb2ece..9d0aba5e6 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -62,7 +62,9 @@ define([], function () { if (!sKey) { return null; } - return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; + var rtnString = decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")); + // Return Boolean values if they match, or the retrieved string, or null + return rtnString === 'true' || (rtnString === 'false' ? false : rtnString || null); } else { return localStorage.getItem(sKey); } From 459db343272a1e8671382f7b8f4cf3be8909638f Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 09:09:42 +0100 Subject: [PATCH 18/35] Accept Boolean values too --- www/js/lib/settingsStore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 9d0aba5e6..77c925b73 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -5,7 +5,7 @@ define([], function () { * * A reader/writer framework for cookies or localStorage with full unicode support based on the Mozilla cookies framework. * The Mozilla code has been adapted to return Boolean values instead of 'true' or 'false' strings, and support for - * the localStorage API has been added. + * the localStorage API has been added. The method setItem() can also accept Boolean values as well as strings. * * Mozilla version information: * @@ -71,7 +71,7 @@ define([], function () { }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { if (params.storeType !== 'local_storage') { - if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) { + if (skey !== false && (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey))) { return false; } var sExpires = ""; From 270594ca3f466a6c90ec0dda529feeb4c97dff01 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 10:37:43 +0100 Subject: [PATCH 19/35] Add migration code --- www/js/lib/settingsStore.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 77c925b73..dce34baa8 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -6,6 +6,7 @@ define([], function () { * A reader/writer framework for cookies or localStorage with full unicode support based on the Mozilla cookies framework. * The Mozilla code has been adapted to return Boolean values instead of 'true' or 'false' strings, and support for * the localStorage API has been added. The method setItem() can also accept Boolean values as well as strings. + * The keys() method has been renamed cookieKeys() because we only use it to get cookie keys, not localStorage keys. * * Mozilla version information: * @@ -23,6 +24,7 @@ define([], function () { * * settingsStore.getItem(name) * * settingsStore.removeItem(name[, path[, domain]]) * * settingsStore.hasItem(name) + * * settingsStore.cookieKeys() * */ @@ -51,6 +53,8 @@ define([], function () { if (kiwixCookieTest) type = 'cookie'; // Prefer localStorage if supported due to some platforms removing cookies once the session ends in some contexts if (localStorageTest) type = 'local_storage'; + // If both cookies and localStorage are supported, and document.cookie has not already been voided, migrate settings to use localStorage + if (kiwixCookieTest && localStorageTest && document.cookie !== '') _migrateStorageSettings(); // Note that if this function returns 'none', the cookie implementations below will run anyway. This is because storing a cookie // does not cause an exception even if cookies are blocked in some contexts, whereas accessing localStorage may cause an exception return type; @@ -71,7 +75,7 @@ define([], function () { }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { if (params.storeType !== 'local_storage') { - if (skey !== false && (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey))) { + if (sKey !== false && (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey))) { return false; } var sExpires = ""; @@ -114,14 +118,31 @@ define([], function () { } else { return localStorage.getItem(sKey) === null ? false : true; } + }, + cookieKeys: function () { + var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); + for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); } + return aKeys; } }; + // One-off migration of storage settings from cookies to localStorage + function _migrateStorageSettings() { + var cookieKeys = settingsStore.cookieKeys(); + // Note that because migration occurs before setting params.storeType, settingsStore.getItem() will get the item from + // document.cookie instead of localStorage, which is the intended behaviour + for (var i = 0; i < cookieKeys.length; i++) { + localStorage.setItem(cookieKeys[i], settingsStore.getItem(cookieKeys[i])); + settingsStore.removeItem(cookieKeys[i]); + } + } + return { getItem: settingsStore.getItem, setItem: settingsStore.setItem, removeItem: settingsStore.removeItem, hasItem: settingsStore.hasItem, + cookieKeys: settingsStore.cookieKeys, testStorageSupport: testStorageSupport }; }); \ No newline at end of file From 99dba533f369d2540321ef0335506181b86dc8bd Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 10:44:32 +0100 Subject: [PATCH 20/35] Revert accepting Boolean values --- www/js/lib/settingsStore.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index dce34baa8..e28718923 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -5,8 +5,7 @@ define([], function () { * * A reader/writer framework for cookies or localStorage with full unicode support based on the Mozilla cookies framework. * The Mozilla code has been adapted to return Boolean values instead of 'true' or 'false' strings, and support for - * the localStorage API has been added. The method setItem() can also accept Boolean values as well as strings. - * The keys() method has been renamed cookieKeys() because we only use it to get cookie keys, not localStorage keys. + * the localStorage API has been added. * * Mozilla version information: * @@ -75,7 +74,7 @@ define([], function () { }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { if (params.storeType !== 'local_storage') { - if (sKey !== false && (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey))) { + if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) { return false; } var sExpires = ""; From dc4a5bacd769731a05ecaba8eda4bea8a36630ef Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 10:45:38 +0100 Subject: [PATCH 21/35] Revert returning Boolean values --- www/js/lib/settingsStore.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index e28718923..afc0a7516 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -65,9 +65,7 @@ define([], function () { if (!sKey) { return null; } - var rtnString = decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")); - // Return Boolean values if they match, or the retrieved string, or null - return rtnString === 'true' || (rtnString === 'false' ? false : rtnString || null); + return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; } else { return localStorage.getItem(sKey); } From d4b5d879a873e49a6cc78a842fb62dc8025a04c3 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 10:57:05 +0100 Subject: [PATCH 22/35] Correct documentation --- www/js/lib/settingsStore.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index afc0a7516..2c3480ce2 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -4,8 +4,7 @@ define([], function () { * settingsStore.js * * A reader/writer framework for cookies or localStorage with full unicode support based on the Mozilla cookies framework. - * The Mozilla code has been adapted to return Boolean values instead of 'true' or 'false' strings, and support for - * the localStorage API has been added. + * The Mozilla code has been adapted to test for the availability of the localStorage API, and to use it in preference to cookies. * * Mozilla version information: * From 3e2aef3f34fdd9ee30ba67546f695ebf522fb791 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 11:07:08 +0100 Subject: [PATCH 23/35] Add console message for migration --- www/js/lib/settingsStore.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 2c3480ce2..937ff515a 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -124,6 +124,7 @@ define([], function () { // One-off migration of storage settings from cookies to localStorage function _migrateStorageSettings() { + console.log('Migrating Settings Store from cookies to localStorage'); var cookieKeys = settingsStore.cookieKeys(); // Note that because migration occurs before setting params.storeType, settingsStore.getItem() will get the item from // document.cookie instead of localStorage, which is the intended behaviour From 88641e79b208c139bab5c49cf33652c0220a0f1e Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 11:11:13 +0100 Subject: [PATCH 24/35] Fix more codeFactor issues --- www/js/lib/settingsStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 937ff515a..26751283d 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -116,7 +116,7 @@ define([], function () { } }, cookieKeys: function () { - var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); + var aKeys = document.cookie.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:=[^;]*)?;\s*/); for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); } return aKeys; } From a53f843260592e5d115885f50db623003e05af67 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 11:20:32 +0100 Subject: [PATCH 25/35] Add diagnostic messages --- www/js/lib/settingsStore.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 26751283d..0a3ee4ee3 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -124,14 +124,16 @@ define([], function () { // One-off migration of storage settings from cookies to localStorage function _migrateStorageSettings() { - console.log('Migrating Settings Store from cookies to localStorage'); + console.log('Migrating Settings Store from cookies to localStorage...'); var cookieKeys = settingsStore.cookieKeys(); // Note that because migration occurs before setting params.storeType, settingsStore.getItem() will get the item from // document.cookie instead of localStorage, which is the intended behaviour for (var i = 0; i < cookieKeys.length; i++) { localStorage.setItem(cookieKeys[i], settingsStore.getItem(cookieKeys[i])); settingsStore.removeItem(cookieKeys[i]); - } + console.log('- ' + cookieKeys[i]); + } + console.log('Migration done.'); } return { From 14e6e43b8019de13f27e7497c428b5864fafd513 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 11:44:03 +0100 Subject: [PATCH 26/35] Make cookieKeys() a private function --- www/js/app.js | 2 +- www/js/lib/settingsStore.js | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/www/js/app.js b/www/js/app.js index f7dd41b3a..00820f5b6 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -78,7 +78,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys params['appTheme'] = settingsStore.getItem('appTheme') || 'light'; // Currently implemented: light|dark|dark_invert|dark_mwInvert document.getElementById('appThemeSelect').value = params.appTheme; uiUtil.applyAppTheme(params.appTheme); - + // Define globalDropZone (universal drop area) and configDropZone (highlighting area on Config page) var globalDropZone = document.getElementById('search-article'); var configDropZone = document.getElementById('configuration'); diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 0a3ee4ee3..928643144 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -115,7 +115,7 @@ define([], function () { return localStorage.getItem(sKey) === null ? false : true; } }, - cookieKeys: function () { + _cookieKeys: function () { var aKeys = document.cookie.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:=[^;]*)?;\s*/); for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); } return aKeys; @@ -125,7 +125,7 @@ define([], function () { // One-off migration of storage settings from cookies to localStorage function _migrateStorageSettings() { console.log('Migrating Settings Store from cookies to localStorage...'); - var cookieKeys = settingsStore.cookieKeys(); + var cookieKeys = settingsStore._cookieKeys(); // Note that because migration occurs before setting params.storeType, settingsStore.getItem() will get the item from // document.cookie instead of localStorage, which is the intended behaviour for (var i = 0; i < cookieKeys.length; i++) { @@ -141,7 +141,6 @@ define([], function () { setItem: settingsStore.setItem, removeItem: settingsStore.removeItem, hasItem: settingsStore.hasItem, - cookieKeys: settingsStore.cookieKeys, testStorageSupport: testStorageSupport }; }); \ No newline at end of file From 7dee737f5e16ac997c18a6c3c35a53195cc7ae44 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 11:46:10 +0100 Subject: [PATCH 27/35] Remove cookieKeys from documentation --- www/js/lib/settingsStore.js | 1 - 1 file changed, 1 deletion(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 928643144..ed7de725d 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -22,7 +22,6 @@ define([], function () { * * settingsStore.getItem(name) * * settingsStore.removeItem(name[, path[, domain]]) * * settingsStore.hasItem(name) - * * settingsStore.cookieKeys() * */ From f2ea273f6238b12ad09051d512d7574354ed3c10 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Fri, 10 Apr 2020 12:42:20 +0100 Subject: [PATCH 28/35] Change some references to "cookie" in app.js --- www/js/app.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/www/js/app.js b/www/js/app.js index 00820f5b6..3403041da 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -569,12 +569,12 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys $('input:radio[name=contentInjectionMode]').prop('checked', false); $('input:radio[name=contentInjectionMode]').filter('[value="' + value + '"]').prop('checked', true); contentInjectionMode = value; - // Save the value in a cookie, so that to be able to keep it after a reload/restart + // Save the value in the Settings Store, so that to be able to keep it after a reload/restart settingsStore.setItem('lastContentInjectionMode', value, Infinity); refreshCacheStatus(); } - // At launch, we try to set the last content injection mode (stored in a cookie) + // At launch, we try to set the last content injection mode (stored in Settings Store) var lastContentInjectionMode = settingsStore.getItem('lastContentInjectionMode'); if (lastContentInjectionMode) { setContentInjectionMode(lastContentInjectionMode); @@ -629,10 +629,10 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys */ var storages = []; function searchForArchivesInPreferencesOrStorage() { - // First see if the list of archives is stored in the cookie - var listOfArchivesFromCookie = settingsStore.getItem("listOfArchives"); - if (listOfArchivesFromCookie !== null && listOfArchivesFromCookie !== undefined && listOfArchivesFromCookie !== "") { - var directories = listOfArchivesFromCookie.split('|'); + // First see if the list of archives is stored in the Settings Store + var listOfArchivesFromSettingsStore = settingsStore.getItem("listOfArchives"); + if (listOfArchivesFromSettingsStore !== null && listOfArchivesFromSettingsStore !== undefined && listOfArchivesFromSettingsStore !== "") { + var directories = listOfArchivesFromSettingsStore.split('|'); populateDropDownListOfArchives(directories); } else { @@ -715,7 +715,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys comboArchiveList.options[i] = new Option(archiveDirectory, archiveDirectory); } } - // Store the list of archives in a cookie, to avoid rescanning at each start + // Store the list of archives in the Settings Store, to avoid rescanning at each start settingsStore.setItem("listOfArchives", archiveDirectories.join('|'), Infinity); $('#archiveList').on('change', setLocalArchiveFromArchiveList); From 836e35dc3ff02a72bd598338a208ac23ba95e149 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 12 Apr 2020 08:36:57 +0100 Subject: [PATCH 29/35] Add list of keys to migrate --- www/js/lib/settingsStore.js | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index ed7de725d..a5a9a9412 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -24,7 +24,18 @@ define([], function () { * * settingsStore.hasItem(name) * */ - + + /** + * An array of the settings keys used in the cookie that should be migrated to localStorage if the API is available + * DEV: It should not be necessary to keep this list up-to-date because any keys added after this list was created + * (April 2020) will already be stored in localStorage if it is available to the client's browser or platform and + * will not need to be migrated + * @type Array + */ + var keysToMigrate = ['hideActiveContentWarning', 'showUIAnimations', 'appTheme', 'useCache', + 'lastContentInjectionMode', 'listOfArchives', 'lastSelectedArchive' + ]; + // Tests for localStorage or cookie support function testStorageSupport() { // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] @@ -51,7 +62,7 @@ define([], function () { // Prefer localStorage if supported due to some platforms removing cookies once the session ends in some contexts if (localStorageTest) type = 'local_storage'; // If both cookies and localStorage are supported, and document.cookie has not already been voided, migrate settings to use localStorage - if (kiwixCookieTest && localStorageTest && document.cookie !== '') _migrateStorageSettings(); + if (kiwixCookieTest && localStorageTest && document.cookie !== '') _migrateStorageSettings(); // Note that if this function returns 'none', the cookie implementations below will run anyway. This is because storing a cookie // does not cause an exception even if cookies are blocked in some contexts, whereas accessing localStorage may cause an exception return type; @@ -116,7 +127,9 @@ define([], function () { }, _cookieKeys: function () { var aKeys = document.cookie.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:=[^;]*)?;\s*/); - for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); } + for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { + aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); + } return aKeys; } }; @@ -124,13 +137,17 @@ define([], function () { // One-off migration of storage settings from cookies to localStorage function _migrateStorageSettings() { console.log('Migrating Settings Store from cookies to localStorage...'); + // Compile list of keys to migrate + var regExpCookieKeys = new RegExp(keysToMigrate.join('|')); var cookieKeys = settingsStore._cookieKeys(); // Note that because migration occurs before setting params.storeType, settingsStore.getItem() will get the item from // document.cookie instead of localStorage, which is the intended behaviour for (var i = 0; i < cookieKeys.length; i++) { - localStorage.setItem(cookieKeys[i], settingsStore.getItem(cookieKeys[i])); - settingsStore.removeItem(cookieKeys[i]); - console.log('- ' + cookieKeys[i]); + if (regExpCookieKeys.test(cookieKeys[i])) { + localStorage.setItem(cookieKeys[i], settingsStore.getItem(cookieKeys[i])); + settingsStore.removeItem(cookieKeys[i]); + console.log('- ' + cookieKeys[i]); + } } console.log('Migration done.'); } From 21a9dd5d244389ef6d376b667a6cfbc44d1aec97 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 12 Apr 2020 08:52:27 +0100 Subject: [PATCH 30/35] Correct JSDoc type statement --- www/js/lib/settingsStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index a5a9a9412..70d84e6b5 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -30,7 +30,7 @@ define([], function () { * DEV: It should not be necessary to keep this list up-to-date because any keys added after this list was created * (April 2020) will already be stored in localStorage if it is available to the client's browser or platform and * will not need to be migrated - * @type Array + * @type {Array} */ var keysToMigrate = ['hideActiveContentWarning', 'showUIAnimations', 'appTheme', 'useCache', 'lastContentInjectionMode', 'listOfArchives', 'lastSelectedArchive' From 21f0e14609c1b2fb7180e2b78d8fe4ec2413b1d7 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 12 Apr 2020 09:12:54 +0100 Subject: [PATCH 31/35] Do not initiate migration if keys to migrate are not in cookie --- www/js/lib/settingsStore.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 70d84e6b5..11fd6bd03 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -30,11 +30,13 @@ define([], function () { * DEV: It should not be necessary to keep this list up-to-date because any keys added after this list was created * (April 2020) will already be stored in localStorage if it is available to the client's browser or platform and * will not need to be migrated - * @type {Array} + * @type {RegExp} */ - var keysToMigrate = ['hideActiveContentWarning', 'showUIAnimations', 'appTheme', 'useCache', + var regexpCookieKeysToMigrate = new RegExp([ + 'hideActiveContentWarning', 'showUIAnimations', 'appTheme', 'useCache', 'lastContentInjectionMode', 'listOfArchives', 'lastSelectedArchive' - ]; + ].join('|')); + // Tests for localStorage or cookie support function testStorageSupport() { @@ -61,8 +63,9 @@ define([], function () { if (kiwixCookieTest) type = 'cookie'; // Prefer localStorage if supported due to some platforms removing cookies once the session ends in some contexts if (localStorageTest) type = 'local_storage'; - // If both cookies and localStorage are supported, and document.cookie has not already been voided, migrate settings to use localStorage - if (kiwixCookieTest && localStorageTest && document.cookie !== '') _migrateStorageSettings(); + // If both cookies and localStorage are supported, and document.cookie contains keys to migrate, + // migrate settings to use localStorage + if (kiwixCookieTest && localStorageTest && regexpCookieKeysToMigrate.test(document.cookie)) _migrateStorageSettings(); // Note that if this function returns 'none', the cookie implementations below will run anyway. This is because storing a cookie // does not cause an exception even if cookies are blocked in some contexts, whereas accessing localStorage may cause an exception return type; @@ -137,13 +140,11 @@ define([], function () { // One-off migration of storage settings from cookies to localStorage function _migrateStorageSettings() { console.log('Migrating Settings Store from cookies to localStorage...'); - // Compile list of keys to migrate - var regExpCookieKeys = new RegExp(keysToMigrate.join('|')); var cookieKeys = settingsStore._cookieKeys(); // Note that because migration occurs before setting params.storeType, settingsStore.getItem() will get the item from // document.cookie instead of localStorage, which is the intended behaviour for (var i = 0; i < cookieKeys.length; i++) { - if (regExpCookieKeys.test(cookieKeys[i])) { + if (regexpCookieKeysToMigrate.test(cookieKeys[i])) { localStorage.setItem(cookieKeys[i], settingsStore.getItem(cookieKeys[i])); settingsStore.removeItem(cookieKeys[i]); console.log('- ' + cookieKeys[i]); From f17dae17f3a4f246ab535bab7f94728771e8006e Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 12 Apr 2020 09:16:55 +0100 Subject: [PATCH 32/35] Correct documentation --- www/js/lib/settingsStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 11fd6bd03..9ce5ccead 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -26,7 +26,7 @@ define([], function () { */ /** - * An array of the settings keys used in the cookie that should be migrated to localStorage if the API is available + * An RegExp of the settings keys used in the cookie that should be migrated to localStorage if the API is available * DEV: It should not be necessary to keep this list up-to-date because any keys added after this list was created * (April 2020) will already be stored in localStorage if it is available to the client's browser or platform and * will not need to be migrated From 4e154c34ab502acbe26e286c983d51ffe0af8a71 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Mon, 13 Apr 2020 10:26:06 +0100 Subject: [PATCH 33/35] Change function names --- www/js/app.js | 2 +- www/js/lib/settingsStore.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/www/js/app.js b/www/js/app.js index 3403041da..f5836a606 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -67,7 +67,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // Set parameters and associated UI elements from the Settings Store // DEV: The params global object is declared in init.js so that it is available to modules - params['storeType'] = settingsStore.testStorageSupport(); // A parameter to determine the Settings Store API in use + params['storeType'] = settingsStore.getBestAvailableStorageAPI(); // A parameter to determine the Settings Store API in use params['hideActiveContentWarning'] = settingsStore.getItem('hideActiveContentWarning') === 'true'; params['showUIAnimations'] = settingsStore.getItem('showUIAnimations') ? settingsStore.getItem('showUIAnimations') === 'true' : true; document.getElementById('hideActiveContentWarningCheck').checked = params.hideActiveContentWarning; diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 9ce5ccead..eef9e7c74 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -26,7 +26,7 @@ define([], function () { */ /** - * An RegExp of the settings keys used in the cookie that should be migrated to localStorage if the API is available + * A RegExp of the settings keys used in the cookie that should be migrated to localStorage if the API is available * DEV: It should not be necessary to keep this list up-to-date because any keys added after this list was created * (April 2020) will already be stored in localStorage if it is available to the client's browser or platform and * will not need to be migrated @@ -38,8 +38,8 @@ define([], function () { ].join('|')); - // Tests for localStorage or cookie support - function testStorageSupport() { + // Tests for available Storage APIs (document.cookie or localStorage) and returns the best available of these + function getBestAvailableStorageAPI() { // DEV: In FF extensions, cookies are blocked since at least FF 68.6 but possibly since FF 55 [kiwix-js #612] var type = 'none'; // First test for localStorage API support @@ -158,6 +158,6 @@ define([], function () { setItem: settingsStore.setItem, removeItem: settingsStore.removeItem, hasItem: settingsStore.hasItem, - testStorageSupport: testStorageSupport + getBestAvailableStorageAPI: getBestAvailableStorageAPI }; }); \ No newline at end of file From c3e1bf19484a7a60b730bb53da7c086d0132f1e7 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Mon, 13 Apr 2020 10:54:04 +0100 Subject: [PATCH 34/35] Add 'kiwixjs-' prefix to keys in localStorage --- www/js/lib/settingsStore.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index eef9e7c74..7b6dcd2cb 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -73,13 +73,14 @@ define([], function () { var settingsStore = { getItem: function (sKey) { + if (!sKey) { + return null; + } if (params.storeType !== 'local_storage') { - if (!sKey) { - return null; - } return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; } else { - return localStorage.getItem(sKey); + // For the reason why we add the 'kiwixjs-' prefix to key, see setItem below + return localStorage.getItem('kiwixjs-' + sKey); } }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { @@ -103,7 +104,9 @@ define([], function () { } document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); } else { - localStorage.setItem(sKey, sValue); + // We add 'kiwixjs-' prefix to all keys that we store in localStorage as a measure to prevent potential collision of + // key names with localStorage keys used by code inside ZIM archives + localStorage.setItem('kiwixjs-' + sKey, sValue); } return true; }, @@ -114,7 +117,7 @@ define([], function () { if (params.storeType !== 'local_storage') { document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); } else { - localStorage.removeItem(sKey); + localStorage.removeItem('kiwixjs-' + sKey); } return true; }, @@ -125,7 +128,7 @@ define([], function () { if (params.storeType !== 'local_storage') { return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); } else { - return localStorage.getItem(sKey) === null ? false : true; + return localStorage.getItem('kiwixjs-' + sKey) === null ? false : true; } }, _cookieKeys: function () { @@ -145,9 +148,11 @@ define([], function () { // document.cookie instead of localStorage, which is the intended behaviour for (var i = 0; i < cookieKeys.length; i++) { if (regexpCookieKeysToMigrate.test(cookieKeys[i])) { - localStorage.setItem(cookieKeys[i], settingsStore.getItem(cookieKeys[i])); + // Add 'kiwixjs-' prefix (see setItem above for reason) + var migratedKey = 'kiwixjs-' + cookieKeys[i]; + localStorage.setItem(migratedKey, settingsStore.getItem(cookieKeys[i])); settingsStore.removeItem(cookieKeys[i]); - console.log('- ' + cookieKeys[i]); + console.log('- ' + migratedKey); } } console.log('Migration done.'); From 34ce7d91b0a31d280ec0de7ae05eb77d8ea30f80 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Mon, 13 Apr 2020 16:50:42 +0100 Subject: [PATCH 35/35] Add a constant for the keyPrefix --- www/js/lib/settingsStore.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/www/js/lib/settingsStore.js b/www/js/lib/settingsStore.js index 7b6dcd2cb..51cc34aae 100644 --- a/www/js/lib/settingsStore.js +++ b/www/js/lib/settingsStore.js @@ -36,7 +36,13 @@ define([], function () { 'hideActiveContentWarning', 'showUIAnimations', 'appTheme', 'useCache', 'lastContentInjectionMode', 'listOfArchives', 'lastSelectedArchive' ].join('|')); - + + /** + * A constant to set the prefix that will be added to keys when stored in localStorage: this is used to prevent + * potential collision of key names with localStorage keys used by code inside ZIM archives + * @type {String} + */ + const keyPrefix = 'kiwixjs-'; // Tests for available Storage APIs (document.cookie or localStorage) and returns the best available of these function getBestAvailableStorageAPI() { @@ -79,8 +85,7 @@ define([], function () { if (params.storeType !== 'local_storage') { return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; } else { - // For the reason why we add the 'kiwixjs-' prefix to key, see setItem below - return localStorage.getItem('kiwixjs-' + sKey); + return localStorage.getItem(keyPrefix + sKey); } }, setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { @@ -104,9 +109,7 @@ define([], function () { } document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); } else { - // We add 'kiwixjs-' prefix to all keys that we store in localStorage as a measure to prevent potential collision of - // key names with localStorage keys used by code inside ZIM archives - localStorage.setItem('kiwixjs-' + sKey, sValue); + localStorage.setItem(keyPrefix + sKey, sValue); } return true; }, @@ -117,7 +120,7 @@ define([], function () { if (params.storeType !== 'local_storage') { document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); } else { - localStorage.removeItem('kiwixjs-' + sKey); + localStorage.removeItem(keyPrefix + sKey); } return true; }, @@ -128,7 +131,7 @@ define([], function () { if (params.storeType !== 'local_storage') { return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[-.+*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); } else { - return localStorage.getItem('kiwixjs-' + sKey) === null ? false : true; + return localStorage.getItem(keyPrefix + sKey) === null ? false : true; } }, _cookieKeys: function () { @@ -148,8 +151,7 @@ define([], function () { // document.cookie instead of localStorage, which is the intended behaviour for (var i = 0; i < cookieKeys.length; i++) { if (regexpCookieKeysToMigrate.test(cookieKeys[i])) { - // Add 'kiwixjs-' prefix (see setItem above for reason) - var migratedKey = 'kiwixjs-' + cookieKeys[i]; + var migratedKey = keyPrefix + cookieKeys[i]; localStorage.setItem(migratedKey, settingsStore.getItem(cookieKeys[i])); settingsStore.removeItem(cookieKeys[i]); console.log('- ' + migratedKey);