From 0c94f04c5c2b78f8e98f708dea537bbfb9d4357c Mon Sep 17 00:00:00 2001 From: Carl Eberhard Date: Mon, 2 Mar 2015 11:20:37 -0500 Subject: [PATCH] Fix to sessionStorage Model to surpress QUOTA DOMExceptions when Safari users are in private browsing mode --- client/galaxy/scripts/mvc/base-mvc.js | 18 ++++++++++++++---- static/scripts/mvc/base-mvc.js | 18 ++++++++++++++---- static/scripts/packed/mvc/base-mvc.js | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/client/galaxy/scripts/mvc/base-mvc.js b/client/galaxy/scripts/mvc/base-mvc.js index 2a8a47c1b23..32ead34c1f5 100644 --- a/client/galaxy/scripts/mvc/base-mvc.js +++ b/client/galaxy/scripts/mvc/base-mvc.js @@ -94,7 +94,7 @@ var SessionStorageModel = Backbone.Model.extend({ if( !options.silent ){ model.trigger( 'request', model, {}, options ); } - var returned; + var returned = {}; switch( method ){ case 'create' : returned = this._create( model ); break; case 'read' : returned = this._read( model ); break; @@ -111,9 +111,19 @@ var SessionStorageModel = Backbone.Model.extend({ /** set storage to the stringified item */ _create : function( model ){ - var json = model.toJSON(), - set = sessionStorage.setItem( model.id, JSON.stringify( json ) ); - return ( set === null )?( set ):( json ); + try { + var json = model.toJSON(), + set = sessionStorage.setItem( model.id, JSON.stringify( json ) ); + return ( set === null )?( set ):( json ); + // DOMException is thrown in Safari if in private browsing mode and sessionStorage is attempted: + // http://stackoverflow.com/questions/14555347 + // TODO: this could probably use a more general soln - like detecting priv. mode + safari => non-ajaxing Model + } catch( err ){ + if( !( ( err instanceof DOMException ) && ( navigator.userAgent.indexOf("Safari") > -1 ) ) ){ + throw err; + } + } + return null; }, /** read and parse json from storage */ diff --git a/static/scripts/mvc/base-mvc.js b/static/scripts/mvc/base-mvc.js index 2a8a47c1b23..32ead34c1f5 100644 --- a/static/scripts/mvc/base-mvc.js +++ b/static/scripts/mvc/base-mvc.js @@ -94,7 +94,7 @@ var SessionStorageModel = Backbone.Model.extend({ if( !options.silent ){ model.trigger( 'request', model, {}, options ); } - var returned; + var returned = {}; switch( method ){ case 'create' : returned = this._create( model ); break; case 'read' : returned = this._read( model ); break; @@ -111,9 +111,19 @@ var SessionStorageModel = Backbone.Model.extend({ /** set storage to the stringified item */ _create : function( model ){ - var json = model.toJSON(), - set = sessionStorage.setItem( model.id, JSON.stringify( json ) ); - return ( set === null )?( set ):( json ); + try { + var json = model.toJSON(), + set = sessionStorage.setItem( model.id, JSON.stringify( json ) ); + return ( set === null )?( set ):( json ); + // DOMException is thrown in Safari if in private browsing mode and sessionStorage is attempted: + // http://stackoverflow.com/questions/14555347 + // TODO: this could probably use a more general soln - like detecting priv. mode + safari => non-ajaxing Model + } catch( err ){ + if( !( ( err instanceof DOMException ) && ( navigator.userAgent.indexOf("Safari") > -1 ) ) ){ + throw err; + } + } + return null; }, /** read and parse json from storage */ diff --git a/static/scripts/packed/mvc/base-mvc.js b/static/scripts/packed/mvc/base-mvc.js index baae0e55d97..415f13d33be 100644 --- a/static/scripts/packed/mvc/base-mvc.js +++ b/static/scripts/packed/mvc/base-mvc.js @@ -1 +1 @@ -define(["utils/add-logging","utils/localization"],function(h,b){var i={logger:null,_logNamespace:"?",log:function(){if(this.logger){var k=this.logger.log;if(typeof this.logger.log==="object"){k=Function.prototype.bind.call(this.logger.log,this.logger)}return k.apply(this.logger,arguments)}return undefined}};h(i);var a=Backbone.Model.extend({initialize:function(l){this._checkEnabledSessionStorage();if(!l.id){throw new Error("SessionStorageModel requires an id in the initial attributes")}this.id=l.id;var k=(!this.isNew())?(this._read(this)):({});this.clear({silent:true});this.save(_.extend({},this.defaults,k,l),{silent:true});this.on("change",function(){this.save()})},_checkEnabledSessionStorage:function(){try{return sessionStorage.length}catch(k){alert("Please enable cookies in your browser for this Galaxy site");return false}},sync:function(n,l,k){if(!k.silent){l.trigger("request",l,{},k)}var m;switch(n){case"create":m=this._create(l);break;case"read":m=this._read(l);break;case"update":m=this._update(l);break;case"delete":m=this._delete(l);break}if(m!==undefined||m!==null){if(k.success){k.success()}}else{if(k.error){k.error()}}return m},_create:function(k){var l=k.toJSON(),m=sessionStorage.setItem(k.id,JSON.stringify(l));return(m===null)?(m):(l)},_read:function(k){return JSON.parse(sessionStorage.getItem(k.id))},_update:function(k){return k._create(k)},_delete:function(k){return sessionStorage.removeItem(k.id)},isNew:function(){return !sessionStorage.hasOwnProperty(this.id)},_log:function(){return JSON.stringify(this.toJSON(),null," ")},toString:function(){return"SessionStorageModel("+this.id+")"}});(function(){a.prototype=_.omit(a.prototype,"url","urlRoot")}());function j(n,m){var k=Array.prototype.slice.call(arguments,0),l=k.pop();k.unshift(l);return _.defaults.apply(_,k)}var g={searchAttributes:[],searchAliases:{},searchAttribute:function(m,k){var l=this.get(m);if(!k||(l===undefined||l===null)){return false}if(_.isArray(l)){return this._searchArrayAttribute(l,k)}return(l.toString().toLowerCase().indexOf(k.toLowerCase())!==-1)},_searchArrayAttribute:function(l,k){k=k.toLowerCase();return _.any(l,function(m){return(m.toString().toLowerCase().indexOf(k.toLowerCase())!==-1)})},search:function(k){var l=this;return _.filter(this.searchAttributes,function(m){return l.searchAttribute(m,k)})},matches:function(l){var n="=",k=l.split(n);if(k.length>=2){var m=k[0];m=this.searchAliases[m]||m;return this.searchAttribute(m,k[1])}return !!this.search(l).length},matchesAll:function(l){var k=this;l=l.match(/(".*"|\w*=".*"|\S*)/g).filter(function(m){return !!m});return _.all(l,function(m){m=m.replace(/"/g,"");return k.matches(m)})}};var c={hiddenUntilActivated:function(k,m){m=m||{};this.HUAVOptions={$elementShown:this.$el,showFn:jQuery.prototype.toggle,showSpeed:"fast"};_.extend(this.HUAVOptions,m||{});this.HUAVOptions.hasBeenShown=this.HUAVOptions.$elementShown.is(":visible");this.hidden=this.isHidden();if(k){var l=this;k.on("click",function(n){l.toggle(l.HUAVOptions.showSpeed)})}},isHidden:function(){return(this.HUAVOptions.$elementShown.is(":hidden"))},toggle:function(){if(this.hidden){if(!this.HUAVOptions.hasBeenShown){if(_.isFunction(this.HUAVOptions.onshowFirstTime)){this.HUAVOptions.hasBeenShown=true;this.HUAVOptions.onshowFirstTime.call(this)}}if(_.isFunction(this.HUAVOptions.onshow)){this.HUAVOptions.onshow.call(this);this.trigger("hiddenUntilActivated:shown",this)}this.hidden=false}else{if(_.isFunction(this.HUAVOptions.onhide)){this.HUAVOptions.onhide.call(this);this.trigger("hiddenUntilActivated:hidden",this)}this.hidden=true}return this.HUAVOptions.showFn.apply(this.HUAVOptions.$elementShown,arguments)}};var f={initialize:function(k){this.draggable=k.draggable||false},$dragHandle:function(){return this.$(".title-bar")},toggleDraggable:function(){if(this.draggable){this.draggableOff()}else{this.draggableOn()}},draggableOn:function(){this.draggable=true;this.dragStartHandler=_.bind(this._dragStartHandler,this);this.dragEndHandler=_.bind(this._dragEndHandler,this);var k=this.$dragHandle().attr("draggable",true).get(0);k.addEventListener("dragstart",this.dragStartHandler,false);k.addEventListener("dragend",this.dragEndHandler,false)},draggableOff:function(){this.draggable=false;var k=this.$dragHandle().attr("draggable",false).get(0);k.removeEventListener("dragstart",this.dragStartHandler,false);k.removeEventListener("dragend",this.dragEndHandler,false)},_dragStartHandler:function(k){k.dataTransfer.effectAllowed="move";k.dataTransfer.setData("text",JSON.stringify(this.model.toJSON()));this.trigger("draggable:dragstart",k,this);return false},_dragEndHandler:function(k){this.trigger("draggable:dragend",k,this);return false}};var d={initialize:function(k){this.selectable=k.selectable||false;this.selected=k.selected||false},$selector:function(){return this.$(".selector")},_renderSelected:function(){this.$selector().find("span").toggleClass("fa-check-square-o",this.selected).toggleClass("fa-square-o",!this.selected)},toggleSelector:function(){if(!this.$selector().is(":visible")){this.showSelector()}else{this.hideSelector()}},showSelector:function(k){k=k!==undefined?k:this.fxSpeed;this.selectable=true;this.trigger("selectable",true,this);this._renderSelected();this.$selector().show(k)},hideSelector:function(k){k=k!==undefined?k:this.fxSpeed;this.selectable=false;this.trigger("selectable",false,this);this.$selector().hide(k)},toggleSelect:function(k){if(this.selected){this.deselect(k)}else{this.select(k)}},select:function(k){if(!this.selected){this.trigger("selected",this,k);this.selected=true;this._renderSelected()}return false},deselect:function(k){if(this.selected){this.trigger("de-selected",this,k);this.selected=false;this._renderSelected()}return false}};function e(l,k){k=k||"model";var m=_.template(l.join(""));return function(o,n){var p={view:n||{},_l:b};p[k]=o||{};return m(p)}}return{LoggableMixin:i,SessionStorageModel:a,mixin:j,SearchableModelMixin:g,HiddenUntilActivatedViewMixin:c,DraggableViewMixin:f,SelectableViewMixin:d,wrapTemplate:e}}); \ No newline at end of file +define(["utils/add-logging","utils/localization"],function(h,b){var i={logger:null,_logNamespace:"?",log:function(){if(this.logger){var k=this.logger.log;if(typeof this.logger.log==="object"){k=Function.prototype.bind.call(this.logger.log,this.logger)}return k.apply(this.logger,arguments)}return undefined}};h(i);var a=Backbone.Model.extend({initialize:function(l){this._checkEnabledSessionStorage();if(!l.id){throw new Error("SessionStorageModel requires an id in the initial attributes")}this.id=l.id;var k=(!this.isNew())?(this._read(this)):({});this.clear({silent:true});this.save(_.extend({},this.defaults,k,l),{silent:true});this.on("change",function(){this.save()})},_checkEnabledSessionStorage:function(){try{return sessionStorage.length}catch(k){alert("Please enable cookies in your browser for this Galaxy site");return false}},sync:function(n,l,k){if(!k.silent){l.trigger("request",l,{},k)}var m={};switch(n){case"create":m=this._create(l);break;case"read":m=this._read(l);break;case"update":m=this._update(l);break;case"delete":m=this._delete(l);break}if(m!==undefined||m!==null){if(k.success){k.success()}}else{if(k.error){k.error()}}return m},_create:function(k){try{var l=k.toJSON(),n=sessionStorage.setItem(k.id,JSON.stringify(l));return(n===null)?(n):(l)}catch(m){if(!((m instanceof DOMException)&&(navigator.userAgent.indexOf("Safari")>-1))){throw m}}return null},_read:function(k){return JSON.parse(sessionStorage.getItem(k.id))},_update:function(k){return k._create(k)},_delete:function(k){return sessionStorage.removeItem(k.id)},isNew:function(){return !sessionStorage.hasOwnProperty(this.id)},_log:function(){return JSON.stringify(this.toJSON(),null," ")},toString:function(){return"SessionStorageModel("+this.id+")"}});(function(){a.prototype=_.omit(a.prototype,"url","urlRoot")}());function j(n,m){var k=Array.prototype.slice.call(arguments,0),l=k.pop();k.unshift(l);return _.defaults.apply(_,k)}var g={searchAttributes:[],searchAliases:{},searchAttribute:function(m,k){var l=this.get(m);if(!k||(l===undefined||l===null)){return false}if(_.isArray(l)){return this._searchArrayAttribute(l,k)}return(l.toString().toLowerCase().indexOf(k.toLowerCase())!==-1)},_searchArrayAttribute:function(l,k){k=k.toLowerCase();return _.any(l,function(m){return(m.toString().toLowerCase().indexOf(k.toLowerCase())!==-1)})},search:function(k){var l=this;return _.filter(this.searchAttributes,function(m){return l.searchAttribute(m,k)})},matches:function(l){var n="=",k=l.split(n);if(k.length>=2){var m=k[0];m=this.searchAliases[m]||m;return this.searchAttribute(m,k[1])}return !!this.search(l).length},matchesAll:function(l){var k=this;l=l.match(/(".*"|\w*=".*"|\S*)/g).filter(function(m){return !!m});return _.all(l,function(m){m=m.replace(/"/g,"");return k.matches(m)})}};var c={hiddenUntilActivated:function(k,m){m=m||{};this.HUAVOptions={$elementShown:this.$el,showFn:jQuery.prototype.toggle,showSpeed:"fast"};_.extend(this.HUAVOptions,m||{});this.HUAVOptions.hasBeenShown=this.HUAVOptions.$elementShown.is(":visible");this.hidden=this.isHidden();if(k){var l=this;k.on("click",function(n){l.toggle(l.HUAVOptions.showSpeed)})}},isHidden:function(){return(this.HUAVOptions.$elementShown.is(":hidden"))},toggle:function(){if(this.hidden){if(!this.HUAVOptions.hasBeenShown){if(_.isFunction(this.HUAVOptions.onshowFirstTime)){this.HUAVOptions.hasBeenShown=true;this.HUAVOptions.onshowFirstTime.call(this)}}if(_.isFunction(this.HUAVOptions.onshow)){this.HUAVOptions.onshow.call(this);this.trigger("hiddenUntilActivated:shown",this)}this.hidden=false}else{if(_.isFunction(this.HUAVOptions.onhide)){this.HUAVOptions.onhide.call(this);this.trigger("hiddenUntilActivated:hidden",this)}this.hidden=true}return this.HUAVOptions.showFn.apply(this.HUAVOptions.$elementShown,arguments)}};var f={initialize:function(k){this.draggable=k.draggable||false},$dragHandle:function(){return this.$(".title-bar")},toggleDraggable:function(){if(this.draggable){this.draggableOff()}else{this.draggableOn()}},draggableOn:function(){this.draggable=true;this.dragStartHandler=_.bind(this._dragStartHandler,this);this.dragEndHandler=_.bind(this._dragEndHandler,this);var k=this.$dragHandle().attr("draggable",true).get(0);k.addEventListener("dragstart",this.dragStartHandler,false);k.addEventListener("dragend",this.dragEndHandler,false)},draggableOff:function(){this.draggable=false;var k=this.$dragHandle().attr("draggable",false).get(0);k.removeEventListener("dragstart",this.dragStartHandler,false);k.removeEventListener("dragend",this.dragEndHandler,false)},_dragStartHandler:function(k){k.dataTransfer.effectAllowed="move";k.dataTransfer.setData("text",JSON.stringify(this.model.toJSON()));this.trigger("draggable:dragstart",k,this);return false},_dragEndHandler:function(k){this.trigger("draggable:dragend",k,this);return false}};var d={initialize:function(k){this.selectable=k.selectable||false;this.selected=k.selected||false},$selector:function(){return this.$(".selector")},_renderSelected:function(){this.$selector().find("span").toggleClass("fa-check-square-o",this.selected).toggleClass("fa-square-o",!this.selected)},toggleSelector:function(){if(!this.$selector().is(":visible")){this.showSelector()}else{this.hideSelector()}},showSelector:function(k){k=k!==undefined?k:this.fxSpeed;this.selectable=true;this.trigger("selectable",true,this);this._renderSelected();this.$selector().show(k)},hideSelector:function(k){k=k!==undefined?k:this.fxSpeed;this.selectable=false;this.trigger("selectable",false,this);this.$selector().hide(k)},toggleSelect:function(k){if(this.selected){this.deselect(k)}else{this.select(k)}},select:function(k){if(!this.selected){this.trigger("selected",this,k);this.selected=true;this._renderSelected()}return false},deselect:function(k){if(this.selected){this.trigger("de-selected",this,k);this.selected=false;this._renderSelected()}return false}};function e(l,k){k=k||"model";var m=_.template(l.join(""));return function(o,n){var p={view:n||{},_l:b};p[k]=o||{};return m(p)}}return{LoggableMixin:i,SessionStorageModel:a,mixin:j,SearchableModelMixin:g,HiddenUntilActivatedViewMixin:c,DraggableViewMixin:f,SelectableViewMixin:d,wrapTemplate:e}}); \ No newline at end of file