blob: ee45bb224598eee774451cc02bc1e1e73944f7dc [file] [log] [blame]
(function (root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(['angular'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('angular'));
} else {
// Browser globals (root is window), we don't register it.
factory(root.angular);
}
}(this , function (angular) {
'use strict';
/**
* @ngdoc overview
* @name ngStorage
*/
return angular.module('ngStorage', [])
/**
* @ngdoc object
* @name ngStorage.$localStorage
* @requires $rootScope
* @requires $window
*/
.factory('$localStorage', _storageFactory('localStorage'))
/**
* @ngdoc object
* @name ngStorage.$sessionStorage
* @requires $rootScope
* @requires $window
*/
.factory('$sessionStorage', _storageFactory('sessionStorage'));
function _storageFactory(storageType) {
return [
'$rootScope',
'$window',
'$log',
'$timeout',
function(
$rootScope,
$window,
$log,
$timeout
){
function isStorageSupported(storageType) {
// Some installations of IE, for an unknown reason, throw "SCRIPT5: Error: Access is denied"
// when accessing window.localStorage. This happens before you try to do anything with it. Catch
// that error and allow execution to continue.
// fix 'SecurityError: DOM Exception 18' exception in Desktop Safari, Mobile Safari
// when "Block cookies": "Always block" is turned on
var supported;
try {
supported = $window[storageType];
}
catch (err) {
supported = false;
}
// When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage
// is available, but trying to call .setItem throws an exception below:
// "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota."
if (supported && storageType === 'localStorage') {
var key = '__' + Math.round(Math.random() * 1e7);
try {
localStorage.setItem(key, key);
localStorage.removeItem(key);
}
catch (err) {
supported = false;
}
}
return supported;
}
// #9: Assign a placeholder object if Web Storage is unavailable to prevent breaking the entire AngularJS app
var webStorage = isStorageSupported(storageType) || ($log.warn('This browser does not support Web Storage!'), {setItem: function() {}, getItem: function() {}}),
$storage = {
$default: function(items) {
for (var k in items) {
angular.isDefined($storage[k]) || ($storage[k] = items[k]);
}
return $storage;
},
$reset: function(items) {
for (var k in $storage) {
'$' === k[0] || (delete $storage[k] && webStorage.removeItem('ngStorage-' + k));
}
return $storage.$default(items);
}
},
_last$storage,
_debounce;
try {
webStorage = $window[storageType];
webStorage.length;
} catch(e) {
$log.warn('This browser does not support Web Storage!');
webStorage = {};
}
for (var i = 0, l = webStorage.length, k; i < l; i++) {
// #8, #10: `webStorage.key(i)` may be an empty string (or throw an exception in IE9 if `webStorage` is empty)
(k = webStorage.key(i)) && 'ngStorage-' === k.slice(0, 10) && ($storage[k.slice(10)] = angular.fromJson(webStorage.getItem(k)));
}
_last$storage = angular.copy($storage);
$rootScope.$watch(function() {
var temp$storage;
_debounce || (_debounce = $timeout(function() {
_debounce = null;
if (!angular.equals($storage, _last$storage)) {
temp$storage = angular.copy(_last$storage);
angular.forEach($storage, function(v, k) {
angular.isDefined(v) && '$' !== k[0] && webStorage.setItem('ngStorage-' + k, angular.toJson(v));
delete temp$storage[k];
});
for (var k in temp$storage) {
webStorage.removeItem('ngStorage-' + k);
}
_last$storage = angular.copy($storage);
}
}, 100, false));
});
// #6: Use `$window.addEventListener` instead of `angular.element` to avoid the jQuery-specific `event.originalEvent`
$window.addEventListener && $window.addEventListener('storage', function(event) {
if ('ngStorage-' === event.key.slice(0, 10)) {
event.newValue ? $storage[event.key.slice(10)] = angular.fromJson(event.newValue) : delete $storage[event.key.slice(10)];
_last$storage = angular.copy($storage);
$rootScope.$apply();
}
});
return $storage;
}
];
}
}));