Built motion from commit 1038d87.|0.0.141
[motion.git] / public / bower_components / angular-local-storage / angular-local-storage.js
1 /**
2  * An Angular module that gives you access to the browsers local storage
3  * @version v0.2.3 - 2015-10-11
4  * @link https://github.com/grevory/angular-local-storage
5  * @author grevory <greg@gregpike.ca>
6  * @license MIT License, http://www.opensource.org/licenses/MIT
7  */
8 (function ( window, angular, undefined ) {
9 /*jshint globalstrict:true*/
10 'use strict';
11
12 var isDefined = angular.isDefined,
13   isUndefined = angular.isUndefined,
14   isNumber = angular.isNumber,
15   isObject = angular.isObject,
16   isArray = angular.isArray,
17   extend = angular.extend,
18   toJson = angular.toJson;
19 var angularLocalStorage = angular.module('LocalStorageModule', []);
20
21 angularLocalStorage.provider('localStorageService', function() {
22
23   // You should set a prefix to avoid overwriting any local storage variables from the rest of your app
24   // e.g. localStorageServiceProvider.setPrefix('yourAppName');
25   // With provider you can use config as this:
26   // myApp.config(function (localStorageServiceProvider) {
27   //    localStorageServiceProvider.prefix = 'yourAppName';
28   // });
29   this.prefix = 'ls';
30
31   // You could change web storage type localstorage or sessionStorage
32   this.storageType = 'localStorage';
33
34   // Cookie options (usually in case of fallback)
35   // expiry = Number of days before cookies expire // 0 = Does not expire
36   // path = The web path the cookie represents
37   this.cookie = {
38     expiry: 30,
39     path: '/'
40   };
41
42   // Send signals for each of the following actions?
43   this.notify = {
44     setItem: true,
45     removeItem: false
46   };
47
48   // Setter for the prefix
49   this.setPrefix = function(prefix) {
50     this.prefix = prefix;
51     return this;
52   };
53
54    // Setter for the storageType
55    this.setStorageType = function(storageType) {
56      this.storageType = storageType;
57      return this;
58    };
59
60   // Setter for cookie config
61   this.setStorageCookie = function(exp, path) {
62     this.cookie.expiry = exp;
63     this.cookie.path = path;
64     return this;
65   };
66
67   // Setter for cookie domain
68   this.setStorageCookieDomain = function(domain) {
69     this.cookie.domain = domain;
70     return this;
71   };
72
73   // Setter for notification config
74   // itemSet & itemRemove should be booleans
75   this.setNotify = function(itemSet, itemRemove) {
76     this.notify = {
77       setItem: itemSet,
78       removeItem: itemRemove
79     };
80     return this;
81   };
82
83   this.$get = ['$rootScope', '$window', '$document', '$parse', function($rootScope, $window, $document, $parse) {
84     var self = this;
85     var prefix = self.prefix;
86     var cookie = self.cookie;
87     var notify = self.notify;
88     var storageType = self.storageType;
89     var webStorage;
90
91     // When Angular's $document is not available
92     if (!$document) {
93       $document = document;
94     } else if ($document[0]) {
95       $document = $document[0];
96     }
97
98     // If there is a prefix set in the config lets use that with an appended period for readability
99     if (prefix.substr(-1) !== '.') {
100       prefix = !!prefix ? prefix + '.' : '';
101     }
102     var deriveQualifiedKey = function(key) {
103       return prefix + key;
104     };
105     // Checks the browser to see if local storage is supported
106     var browserSupportsLocalStorage = (function () {
107       try {
108         var supported = (storageType in $window && $window[storageType] !== null);
109
110         // When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage
111         // is available, but trying to call .setItem throws an exception.
112         //
113         // "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage
114         // that exceeded the quota."
115         var key = deriveQualifiedKey('__' + Math.round(Math.random() * 1e7));
116         if (supported) {
117           webStorage = $window[storageType];
118           webStorage.setItem(key, '');
119           webStorage.removeItem(key);
120         }
121
122         return supported;
123       } catch (e) {
124         storageType = 'cookie';
125         $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
126         return false;
127       }
128     }());
129
130     // Directly adds a value to local storage
131     // If local storage is not available in the browser use cookies
132     // Example use: localStorageService.add('library','angular');
133     var addToLocalStorage = function (key, value) {
134       // Let's convert undefined values to null to get the value consistent
135       if (isUndefined(value)) {
136         value = null;
137       } else {
138         value = toJson(value);
139       }
140
141       // If this browser does not support local storage use cookies
142       if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
143         if (!browserSupportsLocalStorage) {
144             $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
145         }
146
147         if (notify.setItem) {
148           $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'});
149         }
150         return addToCookies(key, value);
151       }
152
153       try {
154         if (webStorage) {
155           webStorage.setItem(deriveQualifiedKey(key), value);
156         }
157         if (notify.setItem) {
158           $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType});
159         }
160       } catch (e) {
161         $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
162         return addToCookies(key, value);
163       }
164       return true;
165     };
166
167     // Directly get a value from local storage
168     // Example use: localStorageService.get('library'); // returns 'angular'
169     var getFromLocalStorage = function (key) {
170
171       if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
172         if (!browserSupportsLocalStorage) {
173           $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED');
174         }
175
176         return getFromCookies(key);
177       }
178
179       var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null;
180       // angular.toJson will convert null to 'null', so a proper conversion is needed
181       // FIXME not a perfect solution, since a valid 'null' string can't be stored
182       if (!item || item === 'null') {
183         return null;
184       }
185
186       try {
187         return JSON.parse(item);
188       } catch (e) {
189         return item;
190       }
191     };
192
193     // Remove an item from local storage
194     // Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular'
195     var removeFromLocalStorage = function () {
196       var i, key;
197       for (i=0; i<arguments.length; i++) {
198         key = arguments[i];
199         if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
200           if (!browserSupportsLocalStorage) {
201             $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
202           }
203
204           if (notify.removeItem) {
205             $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'});
206           }
207           removeFromCookies(key);
208         }
209         else {
210           try {
211             webStorage.removeItem(deriveQualifiedKey(key));
212             if (notify.removeItem) {
213               $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {
214                 key: key,
215                 storageType: self.storageType
216               });
217             }
218           } catch (e) {
219             $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
220             removeFromCookies(key);
221           }
222         }
223       }
224     };
225
226     // Return array of keys for local storage
227     // Example use: var keys = localStorageService.keys()
228     var getKeysForLocalStorage = function () {
229
230       if (!browserSupportsLocalStorage) {
231         $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
232         return false;
233       }
234
235       var prefixLength = prefix.length;
236       var keys = [];
237       for (var key in webStorage) {
238         // Only return keys that are for this app
239         if (key.substr(0,prefixLength) === prefix) {
240           try {
241             keys.push(key.substr(prefixLength));
242           } catch (e) {
243             $rootScope.$broadcast('LocalStorageModule.notification.error', e.Description);
244             return [];
245           }
246         }
247       }
248       return keys;
249     };
250
251     // Remove all data for this app from local storage
252     // Also optionally takes a regular expression string and removes the matching key-value pairs
253     // Example use: localStorageService.clearAll();
254     // Should be used mostly for development purposes
255     var clearAllFromLocalStorage = function (regularExpression) {
256
257       // Setting both regular expressions independently
258       // Empty strings result in catchall RegExp
259       var prefixRegex = !!prefix ? new RegExp('^' + prefix) : new RegExp();
260       var testRegex = !!regularExpression ? new RegExp(regularExpression) : new RegExp();
261
262       if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
263         if (!browserSupportsLocalStorage) {
264           $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
265         }
266         return clearAllFromCookies();
267       }
268
269       var prefixLength = prefix.length;
270
271       for (var key in webStorage) {
272         // Only remove items that are for this app and match the regular expression
273         if (prefixRegex.test(key) && testRegex.test(key.substr(prefixLength))) {
274           try {
275             removeFromLocalStorage(key.substr(prefixLength));
276           } catch (e) {
277             $rootScope.$broadcast('LocalStorageModule.notification.error',e.message);
278             return clearAllFromCookies();
279           }
280         }
281       }
282       return true;
283     };
284
285     // Checks the browser to see if cookies are supported
286     var browserSupportsCookies = (function() {
287       try {
288         return $window.navigator.cookieEnabled ||
289           ("cookie" in $document && ($document.cookie.length > 0 ||
290           ($document.cookie = "test").indexOf.call($document.cookie, "test") > -1));
291       } catch (e) {
292           $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
293           return false;
294       }
295     }());
296
297     // Directly adds a value to cookies
298     // Typically used as a fallback is local storage is not available in the browser
299     // Example use: localStorageService.cookie.add('library','angular');
300     var addToCookies = function (key, value, daysToExpiry) {
301
302       if (isUndefined(value)) {
303         return false;
304       } else if(isArray(value) || isObject(value)) {
305         value = toJson(value);
306       }
307
308       if (!browserSupportsCookies) {
309         $rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
310         return false;
311       }
312
313       try {
314         var expiry = '',
315             expiryDate = new Date(),
316             cookieDomain = '';
317
318         if (value === null) {
319           // Mark that the cookie has expired one day ago
320           expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000));
321           expiry = "; expires=" + expiryDate.toGMTString();
322           value = '';
323         } else if (isNumber(daysToExpiry) && daysToExpiry !== 0) {
324           expiryDate.setTime(expiryDate.getTime() + (daysToExpiry * 24 * 60 * 60 * 1000));
325           expiry = "; expires=" + expiryDate.toGMTString();
326         } else if (cookie.expiry !== 0) {
327           expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000));
328           expiry = "; expires=" + expiryDate.toGMTString();
329         }
330         if (!!key) {
331           var cookiePath = "; path=" + cookie.path;
332           if(cookie.domain){
333             cookieDomain = "; domain=" + cookie.domain;
334           }
335           $document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain;
336         }
337       } catch (e) {
338         $rootScope.$broadcast('LocalStorageModule.notification.error',e.message);
339         return false;
340       }
341       return true;
342     };
343
344     // Directly get a value from a cookie
345     // Example use: localStorageService.cookie.get('library'); // returns 'angular'
346     var getFromCookies = function (key) {
347       if (!browserSupportsCookies) {
348         $rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
349         return false;
350       }
351
352       var cookies = $document.cookie && $document.cookie.split(';') || [];
353       for(var i=0; i < cookies.length; i++) {
354         var thisCookie = cookies[i];
355         while (thisCookie.charAt(0) === ' ') {
356           thisCookie = thisCookie.substring(1,thisCookie.length);
357         }
358         if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) {
359           var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length));
360           try {
361             return JSON.parse(storedValues);
362           } catch(e) {
363             return storedValues;
364           }
365         }
366       }
367       return null;
368     };
369
370     var removeFromCookies = function (key) {
371       addToCookies(key,null);
372     };
373
374     var clearAllFromCookies = function () {
375       var thisCookie = null, thisKey = null;
376       var prefixLength = prefix.length;
377       var cookies = $document.cookie.split(';');
378       for(var i = 0; i < cookies.length; i++) {
379         thisCookie = cookies[i];
380
381         while (thisCookie.charAt(0) === ' ') {
382           thisCookie = thisCookie.substring(1, thisCookie.length);
383         }
384
385         var key = thisCookie.substring(prefixLength, thisCookie.indexOf('='));
386         removeFromCookies(key);
387       }
388     };
389
390     var getStorageType = function() {
391       return storageType;
392     };
393
394     // Add a listener on scope variable to save its changes to local storage
395     // Return a function which when called cancels binding
396     var bindToScope = function(scope, key, def, lsKey) {
397       lsKey = lsKey || key;
398       var value = getFromLocalStorage(lsKey);
399
400       if (value === null && isDefined(def)) {
401         value = def;
402       } else if (isObject(value) && isObject(def)) {
403         value = extend(def, value);
404       }
405
406       $parse(key).assign(scope, value);
407
408       return scope.$watch(key, function(newVal) {
409         addToLocalStorage(lsKey, newVal);
410       }, isObject(scope[key]));
411     };
412
413     // Return localStorageService.length
414     // ignore keys that not owned
415     var lengthOfLocalStorage = function() {
416       var count = 0;
417       var storage = $window[storageType];
418       for(var i = 0; i < storage.length; i++) {
419         if(storage.key(i).indexOf(prefix) === 0 ) {
420           count++;
421         }
422       }
423       return count;
424     };
425
426     return {
427       isSupported: browserSupportsLocalStorage,
428       getStorageType: getStorageType,
429       set: addToLocalStorage,
430       add: addToLocalStorage, //DEPRECATED
431       get: getFromLocalStorage,
432       keys: getKeysForLocalStorage,
433       remove: removeFromLocalStorage,
434       clearAll: clearAllFromLocalStorage,
435       bind: bindToScope,
436       deriveKey: deriveQualifiedKey,
437       length: lengthOfLocalStorage,
438       cookie: {
439         isSupported: browserSupportsCookies,
440         set: addToCookies,
441         add: addToCookies, //DEPRECATED
442         get: getFromCookies,
443         remove: removeFromCookies,
444         clearAll: clearAllFromCookies
445       }
446     };
447   }];
448 });
449 })( window, window.angular );