1/** 2 * An Angular module that gives you access to the browsers local storage 3 * @version v0.2.1 - 2015-05-18 4 * @link https://github.com/grevory/angular-local-storage 5 * @author grevory <[email protected]> 6 * @license MIT License, http://www.opensource.org/licenses/MIT 7 */ 8(function ( window, angular, undefined ) { 9/*jshint globalstrict:true*/ 10'use strict'; 11 12var 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; 19var angularLocalStorage = angular.module('LocalStorageModule', []); 20 21angularLocalStorage.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) {webStorage.setItem(deriveQualifiedKey(key), value)}; 155 if (notify.setItem) { 156 $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType}); 157 } 158 } catch (e) { 159 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message); 160 return addToCookies(key, value); 161 } 162 return true; 163 }; 164 165 // Directly get a value from local storage 166 // Example use: localStorageService.get('library'); // returns 'angular' 167 var getFromLocalStorage = function (key) { 168 169 if (!browserSupportsLocalStorage || self.storageType === 'cookie') { 170 if (!browserSupportsLocalStorage) { 171 $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); 172 } 173 174 return getFromCookies(key); 175 } 176 177 var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null; 178 // angular.toJson will convert null to 'null', so a proper conversion is needed 179 // FIXME not a perfect solution, since a valid 'null' string can't be stored 180 if (!item || item === 'null') { 181 return null; 182 } 183 184 return JSON.parse(item); 185 }; 186 187 // Remove an item from local storage 188 // Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular' 189 var removeFromLocalStorage = function () { 190 var i, key; 191 for (i=0; i<arguments.length; i++) { 192 key = arguments[i]; 193 if (!browserSupportsLocalStorage || self.storageType === 'cookie') { 194 if (!browserSupportsLocalStorage) { 195 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED'); 196 } 197 198 if (notify.removeItem) { 199 $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'}); 200 } 201 removeFromCookies(key); 202 } 203 else { 204 try { 205 webStorage.removeItem(deriveQualifiedKey(key)); 206 if (notify.removeItem) { 207 $rootScope.$broadcast('LocalStorageModule.notification.removeitem', { 208 key: key, 209 storageType: self.storageType 210 }); 211 } 212 } catch (e) { 213 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message); 214 removeFromCookies(key); 215 } 216 } 217 } 218 }; 219 220 // Return array of keys for local storage 221 // Example use: var keys = localStorageService.keys() 222 var getKeysForLocalStorage = function () { 223 224 if (!browserSupportsLocalStorage) { 225 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED'); 226 return false; 227 } 228 229 var prefixLength = prefix.length; 230 var keys = []; 231 for (var key in webStorage) { 232 // Only return keys that are for this app 233 if (key.substr(0,prefixLength) === prefix) { 234 try { 235 keys.push(key.substr(prefixLength)); 236 } catch (e) { 237 $rootScope.$broadcast('LocalStorageModule.notification.error', e.Description); 238 return []; 239 } 240 } 241 } 242 return keys; 243 }; 244 245 // Remove all data for this app from local storage 246 // Also optionally takes a regular expression string and removes the matching key-value pairs 247 // Example use: localStorageService.clearAll(); 248 // Should be used mostly for development purposes 249 var clearAllFromLocalStorage = function (regularExpression) { 250 251 // Setting both regular expressions independently 252 // Empty strings result in catchall RegExp 253 var prefixRegex = !!prefix ? new RegExp('^' + prefix) : new RegExp(); 254 var testRegex = !!regularExpression ? new RegExp(regularExpression) : new RegExp(); 255 256 if (!browserSupportsLocalStorage || self.storageType === 'cookie') { 257 if (!browserSupportsLocalStorage) { 258 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED'); 259 } 260 return clearAllFromCookies(); 261 } 262 263 var prefixLength = prefix.length; 264 265 for (var key in webStorage) { 266 // Only remove items that are for this app and match the regular expression 267 if (prefixRegex.test(key) && testRegex.test(key.substr(prefixLength))) { 268 try { 269 removeFromLocalStorage(key.substr(prefixLength)); 270 } catch (e) { 271 $rootScope.$broadcast('LocalStorageModule.notification.error',e.message); 272 return clearAllFromCookies(); 273 } 274 } 275 } 276 return true; 277 }; 278 279 // Checks the browser to see if cookies are supported 280 var browserSupportsCookies = (function() {
281 try { 282 return $window.navigator.cookieEnabled || 283 ("cookie" in $document && ($document.cookie.length > 0 || 284 ($document.cookie = "test").indexOf.call($document.cookie, "test") > -1)); 285 } catch (e) { 286 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message); 287 return false; 288 } 289 }()); 290 291 // Directly adds a value to cookies 292 // Typically used as a fallback is local storage is not available in the browser 293 // Example use: localStorageService.cookie.add('library','angular'); 294 var addToCookies = function (key, value, daysToExpiry) { 295 296 if (isUndefined(value)) { 297 return false; 298 } else if(isArray(value) || isObject(value)) { 299 value = toJson(value); 300 } 301 302 if (!browserSupportsCookies) { 303 $rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED'); 304 return false; 305 } 306 307 try { 308 var expiry = '', 309 expiryDate = new Date(), 310 cookieDomain = ''; 311 312 if (value === null) { 313 // Mark that the cookie has expired one day ago 314 expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000)); 315 expiry = "; expires=" + expiryDate.toGMTString(); 316 value = ''; 317 } else if (isNumber(daysToExpiry) && daysToExpiry !== 0) { 318 expiryDate.setTime(expiryDate.getTime() + (daysToExpiry * 24 * 60 * 60 * 1000)); 319 expiry = "; expires=" + expiryDate.toGMTString(); 320 } else if (cookie.expiry !== 0) { 321 expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000)); 322 expiry = "; expires=" + expiryDate.toGMTString(); 323 } 324 if (!!key) { 325 var cookiePath = "; path=" + cookie.path; 326 if(cookie.domain){ 327 cookieDomain = "; domain=" + cookie.domain; 328 } 329 $document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain; 330 } 331 } catch (e) { 332 $rootScope.$broadcast('LocalStorageModule.notification.error',e.message); 333 return false; 334 } 335 return true; 336 }; 337 338 // Directly get a value from a cookie 339 // Example use: localStorageService.cookie.get('library'); // returns 'angular' 340 var getFromCookies = function (key) { 341 if (!browserSupportsCookies) { 342 $rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED'); 343 return false; 344 } 345 346 var cookies = $document.cookie && $document.cookie.split(';') || []; 347 for(var i=0; i < cookies.length; i++) { 348 var thisCookie = cookies[i]; 349 while (thisCookie.charAt(0) === ' ') { 350 thisCookie = thisCookie.substring(1,thisCookie.length); 351 } 352 if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) { 353 var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length)) 354 try { 355 return JSON.parse(storedValues); 356 } catch(e) { 357 return storedValues 358 } 359 } 360 } 361 return null; 362 }; 363 364 var removeFromCookies = function (key) { 365 addToCookies(key,null); 366 }; 367 368 var clearAllFromCookies = function () { 369 var thisCookie = null, thisKey = null; 370 var prefixLength = prefix.length; 371 var cookies = $document.cookie.split(';'); 372 for(var i = 0; i < cookies.length; i++) { 373 thisCookie = cookies[i]; 374 375 while (thisCookie.charAt(0) === ' ') { 376 thisCookie = thisCookie.substring(1, thisCookie.length); 377 } 378 379 var key = thisCookie.substring(prefixLength, thisCookie.indexOf('=')); 380 removeFromCookies(key); 381 } 382 }; 383 384 var getStorageType = function() { 385 return storageType; 386 }; 387 388 // Add a listener on scope variable to save its changes to local storage 389 // Return a function which when called cancels binding 390 var bindToScope = function(scope, key, def, lsKey) { 391 lsKey = lsKey || key; 392 var value = getFromLocalStorage(lsKey); 393 394 if (value === null && isDefined(def)) { 395 value = def; 396 } else if (isObject(value) && isObject(def)) { 397 value = extend(def, value); 398 } 399 400 $parse(key).assign(scope, value); 401 402 return scope.$watch(key, function(newVal) { 403 addToLocalStorage(lsKey, newVal); 404 }, isObject(scope[key])); 405 }; 406 407 // Return localStorageService.length 408 // ignore keys that not owned 409 var lengthOfLocalStorage = function() { 410 var count = 0; 411 var storage = $window[storageType]; 412 for(var i = 0; i < storage.length; i++) { 413 if(storage.key(i).indexOf(prefix) === 0 ) { 414 count++; 415 } 416 } 417 return count; 418 }; 419 420 return { 421 isSupported: browserSupportsLocalStorage, 422 getStorageType: getStorageType, 423 set: addToLocalStorage, 424 add: addToLocalStorage, //DEPRECATED 425 get: getFromLocalStorage, 426 keys: getKeysForLocalStorage, 427 remove: removeFromLocalStorage, 428 clearAll: clearAllFromLocalStorage, 429 bind: bindToScope, 430 deriveKey: deriveQualifiedKey, 431 length: lengthOfLocalStorage, 432 cookie: { 433 isSupported: browserSupportsCookies, 434 set: addToCookies, 435 add: addToCookies, //DEPRECATED 436 get: getFromCookies,
437 remove: removeFromCookies, 438 clearAll: clearAllFromCookies 439 } 440 }; 441 }]; 442}); 443})( window, window.angular );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.