|
|
(function (root, factory) { 'use strict';
if (typeof define === 'function' && define.amd) { define(['angular'], factory); } else if (root.hasOwnProperty('angular')) { // Browser globals (root is window), we don't register it.
factory(root.angular); } else if (typeof exports === 'object') { module.exports = factory(require('angular')); } }(this , function (angular) { 'use strict';
// In cases where Angular does not get passed or angular is a truthy value
// but misses .module we can fall back to using window.
angular = (angular && angular.module ) ? angular : window.angular;
function isStorageSupported($window, 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 and sessionStorage
// 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) { var key = '__' + Math.round(Math.random() * 1e7); try { $window[storageType].setItem(key, key); $window[storageType].removeItem(key, key); } catch(err) { supported = false; } }
return supported; }
/** * @ngdoc overview * @name ngStorage */
return angular.module('ngStorage', [])
/** * @ngdoc object * @name ngStorage.$localStorage * @requires $rootScope * @requires $window */
.provider('$localStorage', _storageProvider('localStorage'))
/** * @ngdoc object * @name ngStorage.$sessionStorage * @requires $rootScope * @requires $window */
.provider('$sessionStorage', _storageProvider('sessionStorage'));
function _storageProvider(storageType) { var providerWebStorage = isStorageSupported(window, storageType);
return function () { var storageKeyPrefix = 'ngStorage-';
this.setKeyPrefix = function (prefix) { if (typeof prefix !== 'string') { throw new TypeError('[ngStorage] - ' + storageType + 'Provider.setKeyPrefix() expects a String.'); } storageKeyPrefix = prefix; };
var serializer = angular.toJson; var deserializer = angular.fromJson;
this.setSerializer = function (s) { if (typeof s !== 'function') { throw new TypeError('[ngStorage] - ' + storageType + 'Provider.setSerializer expects a function.'); }
serializer = s; };
this.setDeserializer = function (d) { if (typeof d !== 'function') { throw new TypeError('[ngStorage] - ' + storageType + 'Provider.setDeserializer expects a function.'); }
deserializer = d; };
this.supported = function() { return !!providerWebStorage; };
// Note: This is not very elegant at all.
this.get = function (key) { return providerWebStorage && deserializer(providerWebStorage.getItem(storageKeyPrefix + key)); };
// Note: This is not very elegant at all.
this.set = function (key, value) { return providerWebStorage && providerWebStorage.setItem(storageKeyPrefix + key, serializer(value)); };
this.remove = function (key) { providerWebStorage && providerWebStorage.removeItem(storageKeyPrefix + key); }
this.$get = [ '$rootScope', '$window', '$log', '$timeout', '$document',
function( $rootScope, $window, $log, $timeout, $document ){
// The magic number 10 is used which only works for some keyPrefixes...
// See https://github.com/gsklee/ngStorage/issues/137
var prefixLength = storageKeyPrefix.length;
// #9: Assign a placeholder object if Web Storage is unavailable to prevent breaking the entire AngularJS app
// Note: recheck mainly for testing (so we can use $window[storageType] rather than window[storageType])
var isSupported = isStorageSupported($window, storageType), webStorage = isSupported || ($log.warn('This browser does not support Web Storage!'), {setItem: angular.noop, getItem: angular.noop, removeItem: angular.noop}), $storage = { $default: function(items) { for (var k in items) { angular.isDefined($storage[k]) || ($storage[k] = angular.copy(items[k]) ); }
$storage.$sync(); return $storage; }, $reset: function(items) { for (var k in $storage) { '$' === k[0] || (delete $storage[k] && webStorage.removeItem(storageKeyPrefix + k)); }
return $storage.$default(items); }, $sync: function () { 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)) && storageKeyPrefix === k.slice(0, prefixLength) && ($storage[k.slice(prefixLength)] = deserializer(webStorage.getItem(k))); } }, $apply: function() { var temp$storage;
_debounce = null;
if (!angular.equals($storage, _last$storage)) { temp$storage = angular.copy(_last$storage); angular.forEach($storage, function(v, k) { if (angular.isDefined(v) && '$' !== k[0]) { webStorage.setItem(storageKeyPrefix + k, serializer(v)); delete temp$storage[k]; } });
for (var k in temp$storage) { webStorage.removeItem(storageKeyPrefix + k); }
_last$storage = angular.copy($storage); } }, $supported: function() { return !!isSupported; } }, _last$storage, _debounce;
$storage.$sync();
_last$storage = angular.copy($storage);
$rootScope.$watch(function() { _debounce || (_debounce = $timeout($storage.$apply, 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 (!event.key) { return; }
// Reference doc.
var doc = $document[0];
if ( (!doc.hasFocus || !doc.hasFocus()) && storageKeyPrefix === event.key.slice(0, prefixLength) ) { event.newValue ? $storage[event.key.slice(prefixLength)] = deserializer(event.newValue) : delete $storage[event.key.slice(prefixLength)];
_last$storage = angular.copy($storage);
$rootScope.$apply(); } });
$window.addEventListener && $window.addEventListener('beforeunload', function() { $storage.$apply(); });
return $storage; } ]; }; }
}));
|