diff --git a/Gruntfile.js b/Gruntfile.js index b821fdd..28e43fc 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -10,13 +10,13 @@ module.exports = function(grunt) { grunt.initConfig({ karma: { options: { - autowatch: false, + autowatch: true, browsers: [ 'PhantomJS' ], configFile: 'test/karma.conf.js', reporters: [ 'dots' ], - singleRun: true + singleRun: false }, unit: {} }, diff --git a/angular-local-storage.js b/angular-local-storage.js index 6f23c6a..cb7c126 100644 --- a/angular-local-storage.js +++ b/angular-local-storage.js @@ -1,270 +1,287 @@ (function() { -/* Start angularLocalStorage */ - -var angularLocalStorage = angular.module('LocalStorageModule', []); + /* Start angularLocalStorage */ + 'use strict'; + 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. angularLocalStorage.constant('prefix', 'youAppName'); -angularLocalStorage.value('prefix', 'ls'); + this.prefix = 'ls'; // 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 -angularLocalStorage.constant('cookie', { expiry:30, path: '/'}); -angularLocalStorage.constant('notify', { setItem: true, removeItem: false} ); - -angularLocalStorage.service('localStorageService', [ - '$rootScope', - 'prefix', - 'cookie', - 'notify', - function($rootScope, prefix, cookie, notify) { - - // If there is a prefix set in the config lets use that with an appended period for readability - //var prefix = angularLocalStorage.constant; - if (prefix.substr(-1)!=='.') { - prefix = !!prefix ? prefix + '.' : ''; - } - - // Checks the browser to see if local storage is supported - var browserSupportsLocalStorage = function () { - try { - return ('localStorage' in window && window['localStorage'] !== null); - } catch (e) { - $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) { - - // If this browser does not support local storage use cookies - if (!browserSupportsLocalStorage()) { - $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); - if (notify.setItem) { - $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'}); - } - return addToCookies(key, value); - } - - // Let's convert undefined values to null to get the value consistent - if (typeof value == "undefined") { - value = null; - } - - try { - if (angular.isObject(value) || angular.isArray(value)) { - value = angular.toJson(value); - } - localStorage.setItem(prefix+key, value); - if (notify.setItem) { - $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'localStorage'}); - } - } 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()) { - $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); - return getFromCookies(key); - } - - var item = localStorage.getItem(prefix+key); - // 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; - - if (item.charAt(0) === "{" || item.charAt(0) === "[") { - return angular.fromJson(item); - } - 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) { - if (!browserSupportsLocalStorage()) { - $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); - if (notify.removeItem) { - $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'}); - } - return removeFromCookies(key); - } - - try { - localStorage.removeItem(prefix+key); - if (notify.removeItem) { - $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'localStorage'}); - } - } 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 localStorage) { - // 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 - // Example use: localStorageService.clearAll(); - // Should be used mostly for development purposes - var clearAllFromLocalStorage = function () { - - if (!browserSupportsLocalStorage()) { - $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); - return clearAllFromCookies(); - } - - var prefixLength = prefix.length; - - for (var key in localStorage) { - // Only remove items that are for this app - if (key.substr(0,prefixLength) === prefix) { - 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 - var browserSupportsCookies = function() { - try { - return navigator.cookieEnabled || - ("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; - } - }; - - // 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) { - - if (typeof value == "undefined") { - return false; - } - - if (!browserSupportsCookies()) { - $rootScope.$broadcast('LocalStorageModule.notification.error','COOKIES_NOT_SUPPORTED'); - return false; - } - - try { - var expiry = '', expiryDate = new Date(); - 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) { - document.cookie = prefix + key + "=" + encodeURIComponent(value) + expiry + "; path="+cookie.path; - } - } 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) { - if (!browserSupportsCookies()) { - $rootScope.$broadcast('LocalStorageModule.notification.error','COOKIES_NOT_SUPPORTED'); - return false; - } - - var cookies = 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(prefix+key+'=') === 0) { - return decodeURIComponent(thisCookie.substring(prefix.length+key.length+1,thisCookie.length)); - } - } - 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); - } - key = thisCookie.substring(prefixLength,thisCookie.indexOf('=')); - removeFromCookies(key); - } - }; - - return { - isSupported: browserSupportsLocalStorage, - set: addToLocalStorage, - add: addToLocalStorage, //DEPRECATED - get: getFromLocalStorage, - keys: getKeysForLocalStorage, - remove: removeFromLocalStorage, - clearAll: clearAllFromLocalStorage, - cookie: { - set: addToCookies, - add: addToCookies, //DEPRECATED - get: getFromCookies, - remove: removeFromCookies, - clearAll: clearAllFromCookies - } - }; - -}]); -}).call(this); + this.cookie = { + expiry: 30, + path: '/' + }; + this.notify = { + setItem: true, + removeItem: false + }; + this.setPrefix = function(prefix){ + this.prefix = prefix; + }; + this.setStorageCookie = function(exp, path){ + this.cookie = { + expiry: exp, + path: path + }; + }; + this.setNotify = function(itemSet, itemRemove){ + this.notify = { + setItem: itemSet, + removeItem: itemRemove + }; + }; + + this.$get = ['$rootScope',function($rootScope){ + var prefix = this.prefix; + // If there is a prefix set in the config lets use that with an appended period for readability + //var prefix = angularLocalStorage.constant; + if (prefix.substr(-1)!=='.') { + prefix = !!prefix ? prefix + '.' : ''; + } + + // Checks the browser to see if local storage is supported + var browserSupportsLocalStorage = function () { + try { + return ('localStorage' in window && window.localStorage !== null); + } catch (e) { + $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) { + + // If this browser does not support local storage use cookies + if (!browserSupportsLocalStorage()) { + $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); + if (notify.setItem) { + $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'}); + } + return addToCookies(key, value); + } + + // Let's convert undefined values to null to get the value consistent + if (typeof value === "undefined") { + value = null; + } + + try { + if (angular.isObject(value) || angular.isArray(value)) { + value = angular.toJson(value); + } + localStorage.setItem(prefix+key, value); + if (notify.setItem) { + $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'localStorage'}); + } + } 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()) { + $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); + return getFromCookies(key); + } + + var item = localStorage.getItem(prefix+key); + // 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;} + + if (item.charAt(0) === "{" || item.charAt(0) === "[") { + return angular.fromJson(item); + } + 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) { + if (!browserSupportsLocalStorage()) { + $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); + if (notify.removeItem) { + $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'}); + } + return removeFromCookies(key); + } + + try { + localStorage.removeItem(prefix+key); + if (notify.removeItem) { + $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'localStorage'}); + } + } 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 localStorage) { + // 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 + // Example use: localStorageService.clearAll(); + // Should be used mostly for development purposes + var clearAllFromLocalStorage = function () { + + if (!browserSupportsLocalStorage()) { + $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED'); + return clearAllFromCookies(); + } + + var prefixLength = prefix.length; + + for (var key in localStorage) { + // Only remove items that are for this app + if (key.substr(0,prefixLength) === prefix) { + 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 + var browserSupportsCookies = function() { + try { + return navigator.cookieEnabled || + ("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; + } + }; + + // 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) { + + if (typeof value === "undefined") { + return false; + } + + if (!browserSupportsCookies()) { + $rootScope.$broadcast('LocalStorageModule.notification.error','COOKIES_NOT_SUPPORTED'); + return false; + } + + try { + var expiry = '', expiryDate = new Date(); + 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) { + document.cookie = prefix + key + "=" + encodeURIComponent(value) + expiry + "; path="+cookie.path; + } + } 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) { + if (!browserSupportsCookies()) { + $rootScope.$broadcast('LocalStorageModule.notification.error','COOKIES_NOT_SUPPORTED'); + return false; + } + + var cookies = 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(prefix+key+'=') === 0) { + return decodeURIComponent(thisCookie.substring(prefix.length+key.length+1,thisCookie.length)); + } + } + 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); + } + key = thisCookie.substring(prefixLength,thisCookie.indexOf('=')); + removeFromCookies(key); + } + }; + + return { + isSupported: browserSupportsLocalStorage, + set: addToLocalStorage, + add: addToLocalStorage, //DEPRECATED + get: getFromLocalStorage, + keys: getKeysForLocalStorage, + remove: removeFromLocalStorage, + clearAll: clearAllFromLocalStorage, + cookie: { + set: addToCookies, + add: addToCookies, //DEPRECATED + get: getFromCookies, + remove: removeFromCookies, + clearAll: clearAllFromCookies + } + }; + }] + }); +}).call(this); \ No newline at end of file diff --git a/test/spec/test.js b/test/spec/test.js index 1a520de..2a3af0a 100644 --- a/test/spec/test.js +++ b/test/spec/test.js @@ -1,16 +1,16 @@ describe('Tests functionality of the localStorage module', function(){ - beforeEach(module('LocalStorageModule')); + beforeEach(module('LocalStorageModule', function(localStorageServiceProvider){ + p = localStorageServiceProvider; + })); var ls, store = []; beforeEach(inject(function(_localStorageService_){ ls = _localStorageService_; - spyOn(ls, 'get').andCallFake(function(key){ if(store[key].charAt(0) === "{" || store[key].charAt(0) === "["){ return angular.fromJson(store[key]); }else{ return store[key]; } - }); spyOn(ls, 'set').andCallFake(function(key, val){ @@ -32,6 +32,7 @@ describe('Tests functionality of the localStorage module', function(){ it("Should add a value to my local storage", function(){ var n = 234; ls.set('test', n); + //Since localStorage makes the value a string, we look for the '234' and not 234 expect(ls.get('test')).toBe('234'); var obj = { key: 'val' }; @@ -40,4 +41,15 @@ describe('Tests functionality of the localStorage module', function(){ expect(res.key).toBe('val'); }); -}); + + it('Should allow me to set a prefix', function(){ + p.setPrefix("myPref"); + expect(p.prefix).toBe("myPref"); + }); + + it('Should allow me to set the cookie values', function(){ + p.setStorageCookie(60, '/path'); + expect(p.cookie.expiry).toBe(60); + expect(p.cookie.path).toBe('/path'); + }); +}); \ No newline at end of file