arnaucube
arnaucube/thoughtsPublic Self-hosted repository
thoughts/node_modules/ngstorage/ngStorage.js
node_modules/ngstorage/ngStorage.jsRaw
  1(function (root, factory) {
  2  'use strict';
  3
  4  if (typeof define === 'function' && define.amd) {
  5    define(['angular'], factory);
  6  } else if (root.hasOwnProperty('angular')) {
  7    // Browser globals (root is window), we don't register it.
  8    factory(root.angular);
  9  } else if (typeof exports === 'object') {
 10    module.exports = factory(require('angular'));
 11  }
 12}(this , function (angular) {
 13    'use strict';
 14
 15    // In cases where Angular does not get passed or angular is a truthy value
 16    // but misses .module we can fall back to using window.
 17    angular = (angular && angular.module ) ? angular : window.angular;
 18
 19
 20    function isStorageSupported($window, storageType) {
 21
 22      // Some installations of IE, for an unknown reason, throw "SCRIPT5: Error: Access is denied"
 23      // when accessing window.localStorage. This happens before you try to do anything with it. Catch
 24      // that error and allow execution to continue.
 25
 26      // fix 'SecurityError: DOM Exception 18' exception in Desktop Safari, Mobile Safari
 27      // when "Block cookies": "Always block" is turned on
 28      var supported;
 29      try {
 30        supported = $window[storageType];
 31      }
 32      catch(err) {
 33        supported = false;
 34      }
 35
 36      // When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage and sessionStorage
 37      // is available, but trying to call .setItem throws an exception below:
 38      // "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota."
 39      if(supported) {
 40        var key = '__' + Math.round(Math.random() * 1e7);
 41        try {
 42          $window[storageType].setItem(key, key);
 43          $window[storageType].removeItem(key, key);
 44        }
 45        catch(err) {
 46          supported = false;
 47        }
 48      }
 49
 50      return supported;
 51    }
 52
 53    /**
 54     * @ngdoc overview
 55     * @name ngStorage
 56     */
 57
 58    return angular.module('ngStorage', [])
 59
 60    /**
 61     * @ngdoc object
 62     * @name ngStorage.$localStorage
 63     * @requires $rootScope
 64     * @requires $window
 65     */
 66
 67    .provider('$localStorage', _storageProvider('localStorage'))
 68
 69    /**
 70     * @ngdoc object
 71     * @name ngStorage.$sessionStorage
 72     * @requires $rootScope
 73     * @requires $window
 74     */
 75
 76    .provider('$sessionStorage', _storageProvider('sessionStorage'));
 77
 78    function _storageProvider(storageType) {
 79        var providerWebStorage = isStorageSupported(window, storageType);
 80
 81        return function () {
 82          var storageKeyPrefix = 'ngStorage-';
 83
 84          this.setKeyPrefix = function (prefix) {
 85            if (typeof prefix !== 'string') {
 86              throw new TypeError('[ngStorage] - ' + storageType + 'Provider.setKeyPrefix() expects a String.');
 87            }
 88            storageKeyPrefix = prefix;
 89          };
 90
 91          var serializer = angular.toJson;
 92          var deserializer = angular.fromJson;
 93
 94          this.setSerializer = function (s) {
 95            if (typeof s !== 'function') {
 96              throw new TypeError('[ngStorage] - ' + storageType + 'Provider.setSerializer expects a function.');
 97            }
 98
 99            serializer = s;
100          };
101
102          this.setDeserializer = function (d) {
103            if (typeof d !== 'function') {
104              throw new TypeError('[ngStorage] - ' + storageType + 'Provider.setDeserializer expects a function.');
105            }
106
107            deserializer = d;
108          };
109
110          this.supported = function() {
111            return !!providerWebStorage;
112          };
113
114          // Note: This is not very elegant at all.
115          this.get = function (key) {
116            return providerWebStorage && deserializer(providerWebStorage.getItem(storageKeyPrefix + key));
117          };
118
119          // Note: This is not very elegant at all.
120          this.set = function (key, value) {
121            return providerWebStorage && providerWebStorage.setItem(storageKeyPrefix + key, serializer(value));
122          };
123
124          this.remove = function (key) {
125            providerWebStorage && providerWebStorage.removeItem(storageKeyPrefix + key);
126          }
127
128          this.$get = [
129              '$rootScope',
130              '$window',
131              '$log',
132              '$timeout',
133              '$document',
134
135              function(
136                  $rootScope,
137                  $window,
138                  $log,
139                  $timeout,
140                  $document
141              ){
142
143                // The magic number 10 is used which only works for some keyPrefixes...
144                // See https://github.com/gsklee/ngStorage/issues/137
145                var prefixLength = storageKeyPrefix.length;
146
147                // #9: Assign a placeholder object if Web Storage is unavailable to prevent breaking the entire AngularJS app
148                // Note: recheck mainly for testing (so we can use $window[storageType] rather than window[storageType])
149                var isSupported = isStorageSupported($window, storageType),
150                    webStorage = isSupported || ($log.warn('This browser does not support Web Storage!'), {setItem: angular.noop, getItem: angular.noop, removeItem: angular.noop}),
151                    $storage = {
152                        $default: function(items) {
153                            for (var k in items) {
154                                angular.isDefined($storage[k]) || ($storage[k] = angular.copy(items[k]) );
155                            }
156
157                            $storage.$sync();
158                            return $storage;
159                        },
160                        $reset: function(items) {
161                            for (var k in $storage) {
162                                '$' === k[0] || (delete $storage[k] && webStorage.removeItem(storageKeyPrefix + k));
163                            }
164
165                            return $storage.$default(items);
166                        },
167                        $sync: function () {
168                            for (var i = 0, l = webStorage.length, k; i < l; i++) {
169                                // #8, #10: `webStorage.key(i)` may be an empty string (or throw an exception in IE9 if `webStorage` is empty)
170                                (k = webStorage.key(i)) && storageKeyPrefix === k.slice(0, prefixLength) && ($storage[k.slice(prefixLength)] = deserializer(webStorage.getItem(k)));
171                            }
172                        },
173                        $apply: function() {
174                            var temp$storage;
175
176                            _debounce = null;
177
178                            if (!angular.equals($storage, _last$storage)) {
179                                temp$storage = angular.copy(_last$storage);
180                                angular.forEach($storage, function(v, k) {
181                                    if (angular.isDefined(v) && '$' !== k[0]) {
182                                        webStorage.setItem(storageKeyPrefix + k, serializer(v));
183                                        delete temp$storage[k];
184                                    }
185                                });
186
187                                for (var k in temp$storage) {
188                                    webStorage.removeItem(storageKeyPrefix + k);
189                                }
190
191                                _last$storage = angular.copy($storage);
192                            }
193                        },
194                        $supported: function() {
195                            return !!isSupported;
196                        }
197                    },
198                    _last$storage,
199                    _debounce;
200
201                $storage.$sync();
202
203                _last$storage = angular.copy($storage);
204
205                $rootScope.$watch(function() {
206                    _debounce || (_debounce = $timeout($storage.$apply, 100, false));
207                });
208
209                // #6: Use `$window.addEventListener` instead of `angular.element` to avoid the jQuery-specific `event.originalEvent`
210                $window.addEventListener && $window.addEventListener('storage', function(event) {
211                    if (!event.key) {
212                      return;
213                    }
214
215                    // Reference doc.
216                    var doc = $document[0];
217
218                    if ( (!doc.hasFocus || !doc.hasFocus()) && storageKeyPrefix === event.key.slice(0, prefixLength) ) {
219                        event.newValue ? $storage[event.key.slice(prefixLength)] = deserializer(event.newValue) : delete $storage[event.key.slice(prefixLength)];
220
221                        _last$storage = angular.copy($storage);
222
223                        $rootScope.$apply();
224                    }
225                });
226
227                $window.addEventListener && $window.addEventListener('beforeunload', function() {
228                    $storage.$apply();
229                });
230
231                return $storage;
232              }
233          ];
234      };
235    }
236
237}));