/ajax/libs/ngStorage/0.3.9/ngStorage.js
JavaScript | 212 lines | 137 code | 41 blank | 34 comment | 28 complexity | 9baee265643e37f301024c49df41822d MD5 | raw file
- (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';
- // RequireJS does not pass in Angular to us (will be undefined).
- // Fallback to window which should mostly be there.
- angular = (angular && angular.module ) ? angular : window.angular;
- /**
- * @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) {
- 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;
- };
- // Note: This is not very elegant at all.
- this.get = function (key) {
- return deserializer(window[storageType].getItem(storageKeyPrefix + key));
- };
- // Note: This is not very elegant at all.
- this.set = function (key, value) {
- return window[storageType].setItem(storageKeyPrefix + key, serializer(value));
- };
- this.$get = [
- '$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;
- }
- // 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
- var webStorage = isStorageSupported(storageType) || ($log.warn('This browser does not support Web Storage!'), {setItem: angular.noop, getItem: angular.noop}),
- $storage = {
- $default: function(items) {
- for (var k in items) {
- angular.isDefined($storage[k]) || ($storage[k] = 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);
- }
- },
- },
- _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 (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;
- }
- ];
- };
- }
- }));