Skip to content

Commit

Permalink
Merge pull request #1396 from jameschao/catch_local_storage_errors
Browse files Browse the repository at this point in the history
Fix for an uncaught error in SC.UserDefaults and adding a definition and extension of SC.UserDefaultsDelegate.
  • Loading branch information
mauritslamers committed Jan 7, 2017
2 parents fdeb391 + 5850fdb commit f37a483
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 25 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Edge
### BUG FIXES

* Removed dependency on deprecated SC.MENUPANE.VERTICAL_OFFSET property that could cause a height NaN error in SC.PickerPane
* Fix for uncaught error in SC.UserDefaults when accessing window.localStorage and adding a definition and extension of SC.UserDefaultsDelegate

1.11.1
-----------
Expand Down Expand Up @@ -2396,4 +2397,3 @@ BROWSER
* Resolve a bug where other panes would disappear if a menu pane was opened (IE7 only).
* Fix for SC.button on IE7, now it calculates the label with once is appended to the document
* SC.TextFieldView: Default hint as empty string to avoid IE displaying null in the text fields

47 changes: 47 additions & 0 deletions frameworks/foundation/delegates/user_defaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// ==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2017 Turnitin. All rights reserved.
// License: Licensed under MIT license (see license.js)
// ==========================================================================

/**
@namespace
This defines the UserDefaultsDelegate, used to be notified when a default
is required or an error occurs.
@since SproutCore 1.11.2
*/
SC.UserDefaultsDelegate = /** @scope SC.UserDefaultsDelegate */{

/**
Called when a value is needed for a user default.
@param {SC.UserDefaults} userDefaults
@param {String} keyName
@param {String} userKeyName
@returns {Object} default for then given key
*/
userDefaultsNeedsDefault: function(userDefaults, keyName, userKeyName) {},

/**
Called when a default's value is changed.
@param {SC.UserDefaults} userDefaults
@param {String} keyName
@param {Object} value
@param {String} userKeyName
@returns {void}
*/
userDefaultsDidChange: function(userDefaults, keyName, value, userKeyName) {},

/**
Called when an error occurs.
@param {SC.UserDefaults} userDefaults
@param {String} keyName
@param {Object} value
@param {String} userKeyName
@param {SC.Error} error
@returns {void}
*/
userDefaultsDidError: function(userDefaults, keyName, value, userKeyName, error) {}

};
90 changes: 66 additions & 24 deletions frameworks/foundation/system/user_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
// Note: different implementations of localStorage may return 'null' or
// may return 'undefined' for missing properties so use SC.none() to check
// for the existence of ret throughout this function.
var isIE7, ret, userKeyName, localStorage, key, del, storageSafari3;
var isIE7, ret, userKeyName, localStorage, key, storageSafari3,
errorMessage;

// namespace keyname
keyName = this._normalizeKeyName(keyName);
Expand All @@ -89,14 +90,20 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
try{
localStorage.load("SC.UserDefaults");
}catch(e){
SC.Logger.error("Couldn't load userDefaults in IE7: "+e.description);
errorMessage = "Couldn't load userDefaults in IE7: "+e.description;
this._logError(keyName, null, userKeyName, errorMessage, e);
}
}else if(this.HTML5DB_noLocalStorage){
storageSafari3 = this._safari3DB;
}else{
localStorage = window.localStorage ;
if (!localStorage && window.globalStorage) {
localStorage = window.globalStorage[window.location.hostname];
try {
localStorage = window.localStorage;
if (!localStorage && window.globalStorage) {
localStorage = window.globalStorage[window.location.hostname];
}
}catch(e){
errorMessage = "Failed accessing localStorage. "+e;
this._logError(keyName, null, userKeyName, errorMessage, e);
}
}
if (localStorage || storageSafari3) {
Expand Down Expand Up @@ -137,7 +144,8 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
@returns {SC.UserDefault} receiver
*/
writeDefault: function(keyName, value) {
var isIE7, userKeyName, written, localStorage, key, del, storageSafari3;
var isIE7, userKeyName, written, localStorage, key, del, storageSafari3,
errorMessage;

keyName = this._normalizeKeyName(keyName);
userKeyName = this._userKeyName(keyName);
Expand All @@ -156,10 +164,16 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
}else if(this.HTML5DB_noLocalStorage){
storageSafari3 = this._safari3DB;
}else{
localStorage = window.localStorage ;
if (!localStorage && window.globalStorage) {
localStorage = window.globalStorage[window.location.hostname];
}
try {
localStorage = window.localStorage;
if (!localStorage && window.globalStorage) {
localStorage = window.globalStorage[window.location.hostname];
}
}catch(e){
errorMessage = "Failed accessing localStorage. "+e;
this._logError(keyName, value, userKeyName, errorMessage, e);
}

}
key=["SC.UserDefaults",userKeyName].join('-at-');
if (localStorage || storageSafari3) {
Expand All @@ -186,7 +200,8 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
try{
localStorage[key] = encodedValue;
}catch(e){
SC.Logger.error("Failed using localStorage. "+e);
errorMessage = "Failed writing to localStorage. "+e;
this._logError(keyName, value, userKeyName, errorMessage, e);
}
}
}
Expand All @@ -207,7 +222,8 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
@returns {SC.UserDefaults} receiver
*/
resetDefault: function(keyName) {
var fullKeyName, isIE7, userKeyName, written, localStorage, key, storageSafari3;
var fullKeyName, isIE7, userKeyName, written, localStorage, key,
storageSafari3, errorMessage;
fullKeyName = this._normalizeKeyName(keyName);
userKeyName = this._userKeyName(fullKeyName);

Expand All @@ -221,14 +237,19 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
SC.browser.compare(SC.browser.version, '7') === 0;

if(isIE7){
localStorage=document.body;
localStorage=document.body;
}else if(this.HTML5DB_noLocalStorage){
storageSafari3 = this._safari3DB;
storageSafari3 = this._safari3DB;
}else{
localStorage = window.localStorage ;
if (!localStorage && window.globalStorage) {
localStorage = window.globalStorage[window.location.hostname];
}
try {
localStorage = window.localStorage;
if (!localStorage && window.globalStorage) {
localStorage = window.globalStorage[window.location.hostname];
}
}catch(e){
errorMessage = "Failed accessing localStorage. "+e;
this._logError(keyName, null, userKeyName, errorMessage, e);
}
}

key=["SC.UserDefaults",userKeyName].join('-at-');
Expand All @@ -251,7 +272,8 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
try{
delete localStorage[key];
} catch(e) {
SC.Logger.warn('Deleting local storage encountered a problem. '+e);
errorMessage = 'Deleting local storage encountered a problem. '+e;
this._logError(keyName, null, userKeyName, errorMessage, e);
}
}
}
Expand Down Expand Up @@ -315,7 +337,7 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {

init: function() {
sc_super();
var isIE7;
var isIE7, errorMessage;

// Increment the jQuery ready counter, so that SproutCore will
// defer loading the app until the user defaults are available.
Expand Down Expand Up @@ -343,9 +365,10 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
var myDB;
try {
if (!window.openDatabase) {
SC.Logger.error("Trying to load a database with safari version 3.1 "+
errorMessage = "Trying to load a database with safari version 3.1 "+
"to get SC.UserDefaults to work. You are either in a"+
" previous version or there is a problem with your browser.");
" previous version or there is a problem with your browser.";
this._logError(null, null, null, errorMessage, null);
return;
} else {
var shortName = 'scdb',
Expand All @@ -358,9 +381,10 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {

}
} catch(e) {
SC.Logger.error("Trying to load a database with safari version 3.1 "+
errorMessage = "Trying to load a database with safari version 3.1 "+
"to get SC.UserDefaults to work. You are either in a"+
" previous version or there is a problem with your browser.");
" previous version or there is a problem with your browser.";
this._logError(null, null, null, errorMessage, null);
return;
}

Expand Down Expand Up @@ -396,6 +420,24 @@ SC.UserDefaults = SC.Object.extend(/** @scope SC.UserDefaults.prototype */ {
}
},

// Private method for logging errors
_logError: function(keyName, value, userKeyName, errorMessage, errorObject) {
if (!errorMessage && errorObject) {
errorMessage = errorObject.name + ': ' + errorObject.message;
}

SC.Logger.error(errorMessage);

// also notify delegate
var del = this.delegate;
if (del && del.userDefaultsDidError) {
var e = SC.Error.create({
message: errorMessage,
errorObject: errorObject
})
del.userDefaultsDidError(this, keyName, value, userKeyName, e);
}
},

//Private methods to use if user defaults uses the database in safari 3
_killTransaction: function(transaction, error){
Expand Down

0 comments on commit f37a483

Please sign in to comment.