2014-08-15 17:05:57 +00:00
|
|
|
/**
|
|
|
|
* An Angular module that gives you access to the browsers local storage
|
2014-10-30 14:16:25 +00:00
|
|
|
* @version v0.1.4 - 2014-10-30
|
2014-08-15 17:05:57 +00:00
|
|
|
* @link https://github.com/grevory/angular-local-storage
|
|
|
|
* @author grevory <greg@gregpike.ca>
|
|
|
|
* @license MIT License, http://www.opensource.org/licenses/MIT
|
|
|
|
*/
|
|
|
|
(function ( window, angular, undefined ) {
|
2014-10-06 22:15:20 +00:00
|
|
|
/*jshint globalstrict:true*/
|
2014-08-15 17:05:57 +00:00
|
|
|
'use strict';
|
2014-10-06 22:15:20 +00:00
|
|
|
|
|
|
|
var isDefined = angular.isDefined,
|
|
|
|
isUndefined = angular.isUndefined,
|
|
|
|
isNumber = angular.isNumber,
|
|
|
|
isObject = angular.isObject,
|
|
|
|
isArray = angular.isArray,
|
|
|
|
extend = angular.extend,
|
|
|
|
toJson = angular.toJson,
|
|
|
|
fromJson = angular.fromJson;
|
|
|
|
|
|
|
|
|
|
|
|
// Test if string is only contains numbers
|
|
|
|
// e.g '1' => true, "'1'" => true
|
|
|
|
function isStringNumber(num) {
|
|
|
|
return /^-?\d+\.?\d*$/.test(num.replace(/["']/g, ''));
|
|
|
|
}
|
|
|
|
|
2014-08-15 17:05:57 +00:00
|
|
|
var angularLocalStorage = angular.module('LocalStorageModule', []);
|
|
|
|
|
|
|
|
angularLocalStorage.provider('localStorageService', function() {
|
|
|
|
|
|
|
|
// You should set a prefix to avoid overwriting any local storage variables from the rest of your app
|
|
|
|
// e.g. localStorageServiceProvider.setPrefix('youAppName');
|
|
|
|
// With provider you can use config as this:
|
|
|
|
// myApp.config(function (localStorageServiceProvider) {
|
|
|
|
// localStorageServiceProvider.prefix = 'yourAppName';
|
|
|
|
// });
|
|
|
|
this.prefix = 'ls';
|
|
|
|
|
|
|
|
// You could change web storage type localstorage or sessionStorage
|
|
|
|
this.storageType = 'localStorage';
|
|
|
|
|
|
|
|
// Cookie options (usually in case of fallback)
|
|
|
|
// expiry = Number of days before cookies expire // 0 = Does not expire
|
|
|
|
// path = The web path the cookie represents
|
|
|
|
this.cookie = {
|
|
|
|
expiry: 30,
|
|
|
|
path: '/'
|
|
|
|
};
|
|
|
|
|
|
|
|
// Send signals for each of the following actions?
|
|
|
|
this.notify = {
|
|
|
|
setItem: true,
|
|
|
|
removeItem: false
|
|
|
|
};
|
|
|
|
|
|
|
|
// Setter for the prefix
|
|
|
|
this.setPrefix = function(prefix) {
|
|
|
|
this.prefix = prefix;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Setter for the storageType
|
|
|
|
this.setStorageType = function(storageType) {
|
|
|
|
this.storageType = storageType;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Setter for cookie config
|
|
|
|
this.setStorageCookie = function(exp, path) {
|
|
|
|
this.cookie = {
|
|
|
|
expiry: exp,
|
|
|
|
path: path
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
// Setter for cookie domain
|
|
|
|
this.setStorageCookieDomain = function(domain) {
|
|
|
|
this.cookie.domain = domain;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Setter for notification config
|
|
|
|
// itemSet & itemRemove should be booleans
|
|
|
|
this.setNotify = function(itemSet, itemRemove) {
|
|
|
|
this.notify = {
|
|
|
|
setItem: itemSet,
|
|
|
|
removeItem: itemRemove
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2014-10-06 22:15:20 +00:00
|
|
|
this.$get = ['$rootScope', '$window', '$document', '$parse', function($rootScope, $window, $document, $parse) {
|
2014-08-15 17:05:57 +00:00
|
|
|
var self = this;
|
|
|
|
var prefix = self.prefix;
|
|
|
|
var cookie = self.cookie;
|
|
|
|
var notify = self.notify;
|
|
|
|
var storageType = self.storageType;
|
|
|
|
var webStorage;
|
|
|
|
|
|
|
|
// When Angular's $document is not available
|
|
|
|
if (!$document) {
|
|
|
|
$document = document;
|
|
|
|
} else if ($document[0]) {
|
|
|
|
$document = $document[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there is a prefix set in the config lets use that with an appended period for readability
|
|
|
|
if (prefix.substr(-1) !== '.') {
|
|
|
|
prefix = !!prefix ? prefix + '.' : '';
|
|
|
|
}
|
|
|
|
var deriveQualifiedKey = function(key) {
|
|
|
|
return prefix + key;
|
2014-10-06 22:15:20 +00:00
|
|
|
};
|
2014-08-15 17:05:57 +00:00
|
|
|
// Checks the browser to see if local storage is supported
|
|
|
|
var browserSupportsLocalStorage = (function () {
|
|
|
|
try {
|
|
|
|
var supported = (storageType in $window && $window[storageType] !== null);
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage
|
|
|
|
// that exceeded the quota."
|
|
|
|
var key = deriveQualifiedKey('__' + Math.round(Math.random() * 1e7));
|
|
|
|
if (supported) {
|
|
|
|
webStorage = $window[storageType];
|
|
|
|
webStorage.setItem(key, '');
|
|
|
|
webStorage.removeItem(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
return supported;
|
|
|
|
} catch (e) {
|
|
|
|
storageType = 'cookie';
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Directly adds a value to local storage
|
|
|
|
// If local storage is not available in the browser use cookies
|
|
|
|
// Example use: localStorageService.add('library','angular');
|
|
|
|
var addToLocalStorage = function (key, value) {
|
2014-10-06 22:15:20 +00:00
|
|
|
// Let's convert undefined values to null to get the value consistent
|
|
|
|
if (isUndefined(value)) {
|
|
|
|
value = null;
|
|
|
|
} else if (isObject(value) || isArray(value) || isNumber(+value || value)) {
|
|
|
|
value = toJson(value);
|
|
|
|
}
|
2014-08-15 17:05:57 +00:00
|
|
|
|
|
|
|
// If this browser does not support local storage use cookies
|
|
|
|
if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
|
2014-10-06 22:15:20 +00:00
|
|
|
if (!browserSupportsLocalStorage) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
|
|
|
}
|
|
|
|
|
2014-08-15 17:05:57 +00:00
|
|
|
if (notify.setItem) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'});
|
|
|
|
}
|
|
|
|
return addToCookies(key, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2014-10-06 22:15:20 +00:00
|
|
|
if (isObject(value) || isArray(value)) {
|
|
|
|
value = toJson(value);
|
2014-08-15 17:05:57 +00:00
|
|
|
}
|
|
|
|
if (webStorage) {webStorage.setItem(deriveQualifiedKey(key), value)};
|
|
|
|
if (notify.setItem) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType});
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
|
|
|
return addToCookies(key, value);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Directly get a value from local storage
|
|
|
|
// Example use: localStorageService.get('library'); // returns 'angular'
|
|
|
|
var getFromLocalStorage = function (key) {
|
|
|
|
|
|
|
|
if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
|
2014-10-06 22:15:20 +00:00
|
|
|
if (!browserSupportsLocalStorage) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED');
|
|
|
|
}
|
|
|
|
|
2014-08-15 17:05:57 +00:00
|
|
|
return getFromCookies(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null;
|
|
|
|
// angular.toJson will convert null to 'null', so a proper conversion is needed
|
|
|
|
// FIXME not a perfect solution, since a valid 'null' string can't be stored
|
|
|
|
if (!item || item === 'null') {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2014-10-06 22:15:20 +00:00
|
|
|
if (item.charAt(0) === "{" || item.charAt(0) === "[" || isStringNumber(item)) {
|
|
|
|
return fromJson(item);
|
2014-08-15 17:05:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return item;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Remove an item from local storage
|
|
|
|
// Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular'
|
|
|
|
var removeFromLocalStorage = function (key) {
|
2014-10-06 22:15:20 +00:00
|
|
|
if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
|
|
|
|
if (!browserSupportsLocalStorage) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
|
|
|
}
|
|
|
|
|
2014-08-15 17:05:57 +00:00
|
|
|
if (notify.removeItem) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'});
|
|
|
|
}
|
|
|
|
return removeFromCookies(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
webStorage.removeItem(deriveQualifiedKey(key));
|
|
|
|
if (notify.removeItem) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: self.storageType});
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
|
|
|
return removeFromCookies(key);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Return array of keys for local storage
|
|
|
|
// Example use: var keys = localStorageService.keys()
|
|
|
|
var getKeysForLocalStorage = function () {
|
|
|
|
|
|
|
|
if (!browserSupportsLocalStorage) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var prefixLength = prefix.length;
|
|
|
|
var keys = [];
|
|
|
|
for (var key in webStorage) {
|
|
|
|
// Only return keys that are for this app
|
|
|
|
if (key.substr(0,prefixLength) === prefix) {
|
|
|
|
try {
|
|
|
|
keys.push(key.substr(prefixLength));
|
|
|
|
} catch (e) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.Description);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return keys;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Remove all data for this app from local storage
|
|
|
|
// Also optionally takes a regular expression string and removes the matching key-value pairs
|
|
|
|
// Example use: localStorageService.clearAll();
|
|
|
|
// Should be used mostly for development purposes
|
|
|
|
var clearAllFromLocalStorage = function (regularExpression) {
|
|
|
|
|
|
|
|
regularExpression = regularExpression || "";
|
|
|
|
//accounting for the '.' in the prefix when creating a regex
|
|
|
|
var tempPrefix = prefix.slice(0, -1);
|
|
|
|
var testRegex = new RegExp(tempPrefix + '.' + regularExpression);
|
|
|
|
|
2014-10-06 22:15:20 +00:00
|
|
|
if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
|
|
|
|
if (!browserSupportsLocalStorage) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
|
|
|
}
|
|
|
|
|
2014-08-15 17:05:57 +00:00
|
|
|
return clearAllFromCookies();
|
|
|
|
}
|
|
|
|
|
|
|
|
var prefixLength = prefix.length;
|
|
|
|
|
|
|
|
for (var key in webStorage) {
|
|
|
|
// Only remove items that are for this app and match the regular expression
|
|
|
|
if (testRegex.test(key)) {
|
|
|
|
try {
|
|
|
|
removeFromLocalStorage(key.substr(prefixLength));
|
|
|
|
} catch (e) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error',e.message);
|
|
|
|
return clearAllFromCookies();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Checks the browser to see if cookies are supported
|
2014-10-30 10:38:00 +00:00
|
|
|
var browserSupportsCookies = (function() {
|
2014-08-15 17:05:57 +00:00
|
|
|
try {
|
2014-10-30 10:38:00 +00:00
|
|
|
return $window.navigator.cookieEnabled ||
|
2014-08-15 17:05:57 +00:00
|
|
|
("cookie" in $document && ($document.cookie.length > 0 ||
|
|
|
|
($document.cookie = "test").indexOf.call($document.cookie, "test") > -1));
|
|
|
|
} catch (e) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
|
|
|
return false;
|
|
|
|
}
|
2014-10-30 10:38:00 +00:00
|
|
|
}());
|
2014-08-15 17:05:57 +00:00
|
|
|
|
|
|
|
// Directly adds a value to cookies
|
|
|
|
// Typically used as a fallback is local storage is not available in the browser
|
|
|
|
// Example use: localStorageService.cookie.add('library','angular');
|
|
|
|
var addToCookies = function (key, value) {
|
|
|
|
|
2014-10-06 22:15:20 +00:00
|
|
|
if (isUndefined(value)) {
|
2014-08-15 17:05:57 +00:00
|
|
|
return false;
|
2014-10-06 22:15:20 +00:00
|
|
|
} else if(isArray(value) || isObject(value)) {
|
|
|
|
value = toJson(value);
|
2014-08-15 17:05:57 +00:00
|
|
|
}
|
|
|
|
|
2014-10-30 10:38:00 +00:00
|
|
|
if (!browserSupportsCookies) {
|
2014-08-15 17:05:57 +00:00
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
var expiry = '',
|
|
|
|
expiryDate = new Date(),
|
|
|
|
cookieDomain = '';
|
|
|
|
|
|
|
|
if (value === null) {
|
|
|
|
// Mark that the cookie has expired one day ago
|
|
|
|
expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000));
|
|
|
|
expiry = "; expires=" + expiryDate.toGMTString();
|
|
|
|
value = '';
|
|
|
|
} else if (cookie.expiry !== 0) {
|
|
|
|
expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000));
|
|
|
|
expiry = "; expires=" + expiryDate.toGMTString();
|
|
|
|
}
|
|
|
|
if (!!key) {
|
|
|
|
var cookiePath = "; path=" + cookie.path;
|
|
|
|
if(cookie.domain){
|
|
|
|
cookieDomain = "; domain=" + cookie.domain;
|
|
|
|
}
|
|
|
|
$document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error',e.message);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Directly get a value from a cookie
|
|
|
|
// Example use: localStorageService.cookie.get('library'); // returns 'angular'
|
|
|
|
var getFromCookies = function (key) {
|
2014-10-30 10:38:00 +00:00
|
|
|
if (!browserSupportsCookies) {
|
2014-08-15 17:05:57 +00:00
|
|
|
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var cookies = $document.cookie && $document.cookie.split(';') || [];
|
|
|
|
for(var i=0; i < cookies.length; i++) {
|
|
|
|
var thisCookie = cookies[i];
|
|
|
|
while (thisCookie.charAt(0) === ' ') {
|
|
|
|
thisCookie = thisCookie.substring(1,thisCookie.length);
|
|
|
|
}
|
|
|
|
if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) {
|
2014-10-06 22:15:20 +00:00
|
|
|
var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length))
|
|
|
|
try{
|
|
|
|
var obj = JSON.parse(storedValues);
|
|
|
|
return fromJson(obj)
|
|
|
|
}catch(e){
|
|
|
|
return storedValues
|
|
|
|
}
|
2014-08-15 17:05:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
|
|
|
var removeFromCookies = function (key) {
|
|
|
|
addToCookies(key,null);
|
|
|
|
};
|
|
|
|
|
|
|
|
var clearAllFromCookies = function () {
|
|
|
|
var thisCookie = null, thisKey = null;
|
|
|
|
var prefixLength = prefix.length;
|
|
|
|
var cookies = $document.cookie.split(';');
|
|
|
|
for(var i = 0; i < cookies.length; i++) {
|
|
|
|
thisCookie = cookies[i];
|
|
|
|
|
|
|
|
while (thisCookie.charAt(0) === ' ') {
|
|
|
|
thisCookie = thisCookie.substring(1, thisCookie.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
var key = thisCookie.substring(prefixLength, thisCookie.indexOf('='));
|
|
|
|
removeFromCookies(key);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var getStorageType = function() {
|
|
|
|
return storageType;
|
|
|
|
};
|
|
|
|
|
2014-10-10 21:39:02 +00:00
|
|
|
// Add a listener on scope variable to save its changes to local storage
|
|
|
|
// Return a function which when called cancels binding
|
2014-10-13 22:36:11 +00:00
|
|
|
var bindToScope = function(scope, key, def, lsKey) {
|
|
|
|
lsKey = lsKey || key;
|
2014-10-06 22:15:20 +00:00
|
|
|
var value = getFromLocalStorage(lsKey);
|
2014-08-15 17:05:57 +00:00
|
|
|
|
2014-10-06 22:15:20 +00:00
|
|
|
if (value === null && isDefined(def)) {
|
2014-08-15 17:05:57 +00:00
|
|
|
value = def;
|
2014-10-06 22:15:20 +00:00
|
|
|
} else if (isObject(value) && isObject(def)) {
|
|
|
|
value = extend(def, value);
|
2014-08-15 17:05:57 +00:00
|
|
|
}
|
|
|
|
|
2014-10-13 22:36:11 +00:00
|
|
|
$parse(key).assign(scope, value);
|
2014-08-15 17:05:57 +00:00
|
|
|
|
2014-10-13 22:36:11 +00:00
|
|
|
return scope.$watch(key, function(newVal) {
|
2014-10-06 22:15:20 +00:00
|
|
|
addToLocalStorage(lsKey, newVal);
|
2014-10-13 22:36:11 +00:00
|
|
|
}, isObject(scope[key]));
|
2014-08-15 17:05:57 +00:00
|
|
|
};
|
|
|
|
|
2014-10-06 22:15:20 +00:00
|
|
|
// Return localStorageService.length
|
|
|
|
// ignore keys that not owned
|
|
|
|
var lengthOfLocalStorage = function() {
|
|
|
|
var count = 0;
|
|
|
|
var storage = $window[storageType];
|
|
|
|
for(var i = 0; i < storage.length; i++) {
|
|
|
|
if(storage.key(i).indexOf(prefix) === 0 ) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
};
|
|
|
|
|
2014-08-15 17:05:57 +00:00
|
|
|
return {
|
|
|
|
isSupported: browserSupportsLocalStorage,
|
|
|
|
getStorageType: getStorageType,
|
|
|
|
set: addToLocalStorage,
|
|
|
|
add: addToLocalStorage, //DEPRECATED
|
|
|
|
get: getFromLocalStorage,
|
|
|
|
keys: getKeysForLocalStorage,
|
|
|
|
remove: removeFromLocalStorage,
|
|
|
|
clearAll: clearAllFromLocalStorage,
|
|
|
|
bind: bindToScope,
|
|
|
|
deriveKey: deriveQualifiedKey,
|
2014-10-06 22:15:20 +00:00
|
|
|
length: lengthOfLocalStorage,
|
2014-08-15 17:05:57 +00:00
|
|
|
cookie: {
|
2014-10-30 10:38:00 +00:00
|
|
|
isSupported: browserSupportsCookies,
|
2014-08-15 17:05:57 +00:00
|
|
|
set: addToCookies,
|
|
|
|
add: addToCookies, //DEPRECATED
|
|
|
|
get: getFromCookies,
|
|
|
|
remove: removeFromCookies,
|
|
|
|
clearAll: clearAllFromCookies
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}];
|
|
|
|
});
|
|
|
|
})( window, window.angular );
|