From e2cae035f28ff9ec668aa557f3f5ab34fd9c90fd Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 20 Sep 2017 22:26:47 +0100 Subject: [PATCH] Accessibility checks are now made before trying to access local storage. Fixes #174. --- src/web/App.js | 43 +++++++++++++++++++++++++++++++------ src/web/ControlsWaiter.js | 15 +++++++++++++ src/web/OperationsWaiter.js | 2 +- src/web/OptionsWaiter.js | 12 ++++++++--- src/web/html/index.html | 6 +++++- 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/src/web/App.js b/src/web/App.js index 7dade878..53c0158f 100755 --- a/src/web/App.js +++ b/src/web/App.js @@ -240,7 +240,7 @@ App.prototype.initialiseSplitter = function() { App.prototype.loadLocalStorage = function() { // Load options let lOptions; - if (localStorage.options !== undefined) { + if (this.isLocalStorageAvailable() && localStorage.options !== undefined) { lOptions = JSON.parse(localStorage.options); } this.manager.options.load(lOptions); @@ -256,13 +256,17 @@ App.prototype.loadLocalStorage = function() { * If the user currently has no saved favourites, the defaults from the view constructor are used. */ App.prototype.loadFavourites = function() { - let favourites = localStorage.favourites && - localStorage.favourites.length > 2 ? - JSON.parse(localStorage.favourites) : - this.dfavourites; + let favourites; - favourites = this.validFavourites(favourites); - this.saveFavourites(favourites); + if (this.isLocalStorageAvailable()) { + favourites = localStorage.favourites && localStorage.favourites.length > 2 ? + JSON.parse(localStorage.favourites) : + this.dfavourites; + favourites = this.validFavourites(favourites); + this.saveFavourites(favourites); + } else { + favourites = this.dfavourites; + } const favCat = this.categories.filter(function(c) { return c.name === "Favourites"; @@ -306,6 +310,15 @@ App.prototype.validFavourites = function(favourites) { * @param {string[]} favourites - A list of the user's favourite operations */ App.prototype.saveFavourites = function(favourites) { + if (!this.isLocalStorageAvailable()) { + this.alert( + "Your security settings do not allow access to local storage so your favourites cannot be saved.", + "danger", + 5000 + ); + return false; + } + localStorage.setItem("favourites", JSON.stringify(this.validFavourites(favourites))); }; @@ -503,6 +516,22 @@ App.prototype.setCompileMessage = function() { }; +/** + * Determines whether the browser supports Local Storage and if it is accessible. + * + * @returns {boolean} + */ +App.prototype.isLocalStorageAvailable = function() { + try { + if (!localStorage) return false; + return true; + } catch (err) { + // Access to LocalStorage is denied + return false; + } +}; + + /** * Pops up a message to the user and writes it to the console log. * diff --git a/src/web/ControlsWaiter.js b/src/web/ControlsWaiter.js index d7241e12..85982e46 100755 --- a/src/web/ControlsWaiter.js +++ b/src/web/ControlsWaiter.js @@ -254,6 +254,15 @@ ControlsWaiter.prototype.loadClick = function() { * Saves the recipe specified in the save textarea to local storage. */ ControlsWaiter.prototype.saveButtonClick = function() { + if (!this.app.isLocalStorageAvailable()) { + this.app.alert( + "Your security settings do not allow access to local storage so your recipe cannot be saved.", + "danger", + 5000 + ); + return false; + } + const recipeName = Utils.escapeHtml(document.getElementById("save-name").value); const recipeStr = document.querySelector("#save-texts .tab-pane.active textarea").value; @@ -283,6 +292,8 @@ ControlsWaiter.prototype.saveButtonClick = function() { * Populates the list of saved recipes in the load dialog box from local storage. */ ControlsWaiter.prototype.populateLoadRecipesList = function() { + if (!this.app.isLocalStorageAvailable()) return false; + const loadNameEl = document.getElementById("load-name"); // Remove current recipes from select @@ -313,6 +324,8 @@ ControlsWaiter.prototype.populateLoadRecipesList = function() { * Removes the currently selected recipe from local storage. */ ControlsWaiter.prototype.loadDeleteClick = function() { + if (!this.app.isLocalStorageAvailable()) return false; + const id = parseInt(document.getElementById("load-name").value, 10); const rawSavedRecipes = localStorage.savedRecipes ? JSON.parse(localStorage.savedRecipes) : []; @@ -328,6 +341,8 @@ ControlsWaiter.prototype.loadDeleteClick = function() { * Displays the selected recipe in the load text box. */ ControlsWaiter.prototype.loadNameChange = function(e) { + if (!this.app.isLocalStorageAvailable()) return false; + const el = e.target; const savedRecipes = localStorage.savedRecipes ? JSON.parse(localStorage.savedRecipes) : []; diff --git a/src/web/OperationsWaiter.js b/src/web/OperationsWaiter.js index 087eaa1c..adc2be6d 100755 --- a/src/web/OperationsWaiter.js +++ b/src/web/OperationsWaiter.js @@ -229,7 +229,7 @@ OperationsWaiter.prototype.editFavouritesClick = function(e) { filter: ".remove-icon", onFilter: function (evt) { const el = editableList.closest(evt.item); - if (el) { + if (el && el.parentNode) { $(el).popover("destroy"); el.parentNode.removeChild(el); } diff --git a/src/web/OptionsWaiter.js b/src/web/OptionsWaiter.js index 0760262b..b3eb364c 100755 --- a/src/web/OptionsWaiter.js +++ b/src/web/OptionsWaiter.js @@ -87,7 +87,9 @@ OptionsWaiter.prototype.switchChange = function(e, state) { const option = el.getAttribute("option"); this.app.options[option] = state; - localStorage.setItem("options", JSON.stringify(this.app.options)); + + if (this.app.isLocalStorageAvailable()) + localStorage.setItem("options", JSON.stringify(this.app.options)); }; @@ -102,7 +104,9 @@ OptionsWaiter.prototype.numberChange = function(e) { const option = el.getAttribute("option"); this.app.options[option] = parseInt(el.value, 10); - localStorage.setItem("options", JSON.stringify(this.app.options)); + + if (this.app.isLocalStorageAvailable()) + localStorage.setItem("options", JSON.stringify(this.app.options)); }; @@ -117,7 +121,9 @@ OptionsWaiter.prototype.selectChange = function(e) { const option = el.getAttribute("option"); this.app.options[option] = el.value; - localStorage.setItem("options", JSON.stringify(this.app.options)); + + if (this.app.isLocalStorageAvailable()) + localStorage.setItem("options", JSON.stringify(this.app.options)); }; diff --git a/src/web/html/index.html b/src/web/html/index.html index 02b8e2d1..94a0f08c 100755 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -35,7 +35,11 @@ "use strict"; // Load theme before the preloader is shown - document.querySelector(":root").className = (JSON.parse(localStorage.getItem("options")) || {}).theme; + try { + document.querySelector(":root").className = (JSON.parse(localStorage.getItem("options")) || {}).theme; + } catch (err) { + // LocalStorage access is denied by security settings + } // Define loading messages const loadingMsgs = [