diff --git a/dist/angular-locker.js b/dist/angular-locker.js index 16908b1..4ae46b5 100644 --- a/dist/angular-locker.js +++ b/dist/angular-locker.js @@ -163,7 +163,7 @@ * @return {Boolean} */ this._checkSupport = function (driver) { - if (angular.isUndefined(this._supported)) { + if (! _defined(this._supported)) { var l = 'l'; try { this._resolveDriver(driver || 'local').setItem(l, l); @@ -423,10 +423,8 @@ var items = {}; angular.forEach(this._driver, function (value, key) { if (this._namespace) { - var prefixWithSeparator = this._namespace + this._separator; - if (key.indexOf(prefixWithSeparator) === 0) { - key = key.substring(prefixWithSeparator.length); - } + var prefix = this._namespace + this._separator; + if (key.indexOf(prefix) === 0) key = key.substring(prefix.length); } if (this.has(key)) items[key] = this.get(key); }, this); @@ -434,15 +432,22 @@ return items; }, + /** + * Get the storage keys as an array + * + * @return {Array} + */ + keys: function () { + return Object.keys(this.all()); + }, + /** * Remove all items set within the current namespace/driver * * @return {self} */ clean: function () { - this.forget(Object.keys(this.all())); - - return this; + return this.forget(this.keys()); }, /** @@ -462,7 +467,7 @@ * @return {Integer} */ count: function () { - return Object.keys(this.all()).length; + return this.keys().length; }, /** diff --git a/dist/angular-locker.min.js b/dist/angular-locker.min.js index 57d529f..56209c7 100644 --- a/dist/angular-locker.min.js +++ b/dist/angular-locker.min.js @@ -1,3 +1,3 @@ /*! angular-locker v1.2.1 | (c) 2015 @tymondesigns | https://github.com/tymondesigns/angular-locker */ -!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t.angular)}):"object"==typeof exports?module.exports=e(t.angular||window&&window.angular):e(t.angular)}(this,function(t){"use strict";t.module("angular-locker",[]).provider("locker",function(){var e=function(e,r){return t.isFunction(e)?e(r):e},r=function(e){return t.isDefined(e)&&null!==e},i=function(t){throw new Error("[angular-locker] "+t)},s={driver:"local",namespace:"locker",eventsEnabled:!0,separator:"."};return{defaults:function(e){return r(e)?void t.forEach(e,function(t,e){s.hasOwnProperty(e)&&(s[e]=t)}):s},$get:["$window","$rootScope","$parse",function(n,o,h){function a(r){this._options=r,this._registeredDrivers={local:n.localStorage,session:n.sessionStorage},this._resolveDriver=function(t){return this._registeredDrivers.hasOwnProperty(t)||i('The driver "'+t+'" was not found.'),this._registeredDrivers[t]},this._driver=this._resolveDriver(r.driver),this._namespace=r.namespace,this._separator=r.separator,this._watchers={},this._checkSupport=function(e){if(t.isUndefined(this._supported)){var r="l";try{this._resolveDriver(e||"local").setItem(r,r),this._resolveDriver(e||"local").removeItem(r),this._supported=!0}catch(i){this._supported=!1}}return this._supported},this._getPrefix=function(t){return this._namespace?this._namespace+this._separator+t:t},this._serialize=function(e){try{return t.toJson(e)}catch(r){return e}},this._unserialize=function(e){try{return t.fromJson(e)}catch(r){return e}},this._event=function(e,r){this._options.eventsEnabled&&o.$emit(e,t.extend(r,{driver:this._options.driver,namespace:this._namespace}))},this._setItem=function(e,r){this._checkSupport()||i("The browser does not support localStorage");try{var s=this._getItem(e);this._driver.setItem(this._getPrefix(e),this._serialize(r)),this._exists(e)&&!t.equals(s,r)?this._event("locker.item.updated",{key:e,oldValue:s,newValue:r}):this._event("locker.item.added",{key:e,value:r})}catch(n){i(-1!==["QUOTA_EXCEEDED_ERR","NS_ERROR_DOM_QUOTA_REACHED","QuotaExceededError"].indexOf(n.name)?"The browser storage quota has been exceeded":'Could not add item with key "'+e+'"')}},this._getItem=function(t){return this._checkSupport()||i("The browser does not support localStorage"),this._unserialize(this._driver.getItem(this._getPrefix(t)))},this._exists=function(t){return this._checkSupport()||i("The browser does not support localStorage"),this._driver.hasOwnProperty(this._getPrefix(e(t)))},this._removeItem=function(t){return this._checkSupport()||i("The browser does not support localStorage"),this._exists(t)?(this._driver.removeItem(this._getPrefix(t)),this._event("locker.item.forgotten",{key:t}),!0):!1}}return a.prototype={put:function(i,s,n){if(!r(i))return!1;if(i=e(i),t.isObject(i))t.forEach(i,function(t,e){this._setItem(e,r(t)?t:n)},this);else{if(!r(s))return!1;var o=this._getItem(i);this._setItem(i,e(s,r(o)?o:n))}return this},add:function(t,e,r){return this.has(t)?!1:(this.put(t,e,r),!0)},get:function(e,r){if(t.isArray(e)){var i={};return t.forEach(e,function(t){this.has(t)&&(i[t]=this._getItem(t))},this),i}return this.has(e)?this._getItem(e):2===arguments.length?r:void 0},has:function(t){return this._exists(t)},forget:function(r){return r=e(r),t.isArray(r)?r.map(this._removeItem,this):this._removeItem(r),this},pull:function(t,e){var r=this.get(t,e);return this.forget(t),r},all:function(){var e={};return t.forEach(this._driver,function(t,r){if(this._namespace){var i=this._namespace+this._separator;0===r.indexOf(i)&&(r=r.substring(i.length))}this.has(r)&&(e[r]=this.get(r))},this),e},clean:function(){return this.forget(Object.keys(this.all())),this},empty:function(){return this._driver.clear(),this},count:function(){return Object.keys(this.all()).length},bind:function(e,i,s){r(e.$eval(i))||(h(i).assign(e,this.get(i,s)),this.has(i)||this.put(i,s));var n=this;return this._watchers[i+e.$id]=e.$watch(i,function(t){r(t)&&n.put(i,t)},t.isObject(e[i])),this},unbind:function(t,e){h(e).assign(t,void 0),this.forget(e);var r=e+t.$id;return this._watchers[r]&&(this._watchers[r](),delete this._watchers[r]),this},driver:function(e){return e===this._options.driver?this:this.instance(t.extend(this._options,{driver:e}))},getDriver:function(){return this._driver},namespace:function(e){return e===this._namespace?this:this.instance(t.extend(this._options,{namespace:e}))},getNamespace:function(){return this._namespace},supported:function(t){return this._checkSupport(t)},instance:function(t){return new a(t)}},new a(s)}]}})}); +!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t.angular)}):"object"==typeof exports?module.exports=e(t.angular||window&&window.angular):e(t.angular)}(this,function(t){"use strict";t.module("angular-locker",[]).provider("locker",function(){var e=function(e,r){return t.isFunction(e)?e(r):e},r=function(e){return t.isDefined(e)&&null!==e},i=function(t){throw new Error("[angular-locker] "+t)},s={driver:"local",namespace:"locker",eventsEnabled:!0,separator:"."};return{defaults:function(e){return r(e)?void t.forEach(e,function(t,e){s.hasOwnProperty(e)&&(s[e]=t)}):s},$get:["$window","$rootScope","$parse",function(n,o,h){function a(s){this._options=s,this._registeredDrivers={local:n.localStorage,session:n.sessionStorage},this._resolveDriver=function(t){return this._registeredDrivers.hasOwnProperty(t)||i('The driver "'+t+'" was not found.'),this._registeredDrivers[t]},this._driver=this._resolveDriver(s.driver),this._namespace=s.namespace,this._separator=s.separator,this._watchers={},this._checkSupport=function(t){if(!r(this._supported)){var e="l";try{this._resolveDriver(t||"local").setItem(e,e),this._resolveDriver(t||"local").removeItem(e),this._supported=!0}catch(i){this._supported=!1}}return this._supported},this._getPrefix=function(t){return this._namespace?this._namespace+this._separator+t:t},this._serialize=function(e){try{return t.toJson(e)}catch(r){return e}},this._unserialize=function(e){try{return t.fromJson(e)}catch(r){return e}},this._event=function(e,r){this._options.eventsEnabled&&o.$emit(e,t.extend(r,{driver:this._options.driver,namespace:this._namespace}))},this._setItem=function(e,r){this._checkSupport()||i("The browser does not support localStorage");try{var s=this._getItem(e);this._driver.setItem(this._getPrefix(e),this._serialize(r)),this._exists(e)&&!t.equals(s,r)?this._event("locker.item.updated",{key:e,oldValue:s,newValue:r}):this._event("locker.item.added",{key:e,value:r})}catch(n){i(-1!==["QUOTA_EXCEEDED_ERR","NS_ERROR_DOM_QUOTA_REACHED","QuotaExceededError"].indexOf(n.name)?"The browser storage quota has been exceeded":'Could not add item with key "'+e+'"')}},this._getItem=function(t){return this._checkSupport()||i("The browser does not support localStorage"),this._unserialize(this._driver.getItem(this._getPrefix(t)))},this._exists=function(t){return this._checkSupport()||i("The browser does not support localStorage"),this._driver.hasOwnProperty(this._getPrefix(e(t)))},this._removeItem=function(t){return this._checkSupport()||i("The browser does not support localStorage"),this._exists(t)?(this._driver.removeItem(this._getPrefix(t)),this._event("locker.item.forgotten",{key:t}),!0):!1}}return a.prototype={put:function(i,s,n){if(!r(i))return!1;if(i=e(i),t.isObject(i))t.forEach(i,function(t,e){this._setItem(e,r(t)?t:n)},this);else{if(!r(s))return!1;var o=this._getItem(i);this._setItem(i,e(s,r(o)?o:n))}return this},add:function(t,e,r){return this.has(t)?!1:(this.put(t,e,r),!0)},get:function(e,r){if(t.isArray(e)){var i={};return t.forEach(e,function(t){this.has(t)&&(i[t]=this._getItem(t))},this),i}return this.has(e)?this._getItem(e):2===arguments.length?r:void 0},has:function(t){return this._exists(t)},forget:function(r){return r=e(r),t.isArray(r)?r.map(this._removeItem,this):this._removeItem(r),this},pull:function(t,e){var r=this.get(t,e);return this.forget(t),r},all:function(){var e={};return t.forEach(this._driver,function(t,r){if(this._namespace){var i=this._namespace+this._separator;0===r.indexOf(i)&&(r=r.substring(i.length))}this.has(r)&&(e[r]=this.get(r))},this),e},keys:function(){return Object.keys(this.all())},clean:function(){return this.forget(this.keys())},empty:function(){return this._driver.clear(),this},count:function(){return this.keys().length},bind:function(e,i,s){r(e.$eval(i))||(h(i).assign(e,this.get(i,s)),this.has(i)||this.put(i,s));var n=this;return this._watchers[i+e.$id]=e.$watch(i,function(t){r(t)&&n.put(i,t)},t.isObject(e[i])),this},unbind:function(t,e){h(e).assign(t,void 0),this.forget(e);var r=e+t.$id;return this._watchers[r]&&(this._watchers[r](),delete this._watchers[r]),this},driver:function(e){return e===this._options.driver?this:this.instance(t.extend(this._options,{driver:e}))},getDriver:function(){return this._driver},namespace:function(e){return e===this._namespace?this:this.instance(t.extend(this._options,{namespace:e}))},getNamespace:function(){return this._namespace},supported:function(t){return this._checkSupport(t)},instance:function(t){return new a(t)}},new a(s)}]}})}); //# sourceMappingURL=angular-locker.min.js.map \ No newline at end of file diff --git a/dist/angular-locker.min.js.map b/dist/angular-locker.min.js.map index 6646e79..a9d2597 100644 --- a/dist/angular-locker.min.js.map +++ b/dist/angular-locker.min.js.map @@ -1,2 +1,2 @@ /*! angular-locker v1.2.1 | (c) 2015 @tymondesigns | https://github.com/tymondesigns/angular-locker */ -{"version":3,"sources":["angular-locker.min.js"],"names":["root","factory","define","amd","angular","exports","module","window","this","provider","_value","value","param","isFunction","_defined","isDefined","_error","msg","Error","defaults","driver","namespace","eventsEnabled","separator","forEach","val","key","hasOwnProperty","$get","$window","$rootScope","$parse","Locker","options","_options","_registeredDrivers","local","localStorage","session","sessionStorage","_resolveDriver","_driver","_namespace","_separator","_watchers","_checkSupport","isUndefined","_supported","l","setItem","removeItem","e","_getPrefix","_serialize","toJson","_unserialize","fromJson","_event","name","payload","$emit","extend","_setItem","oldVal","_getItem","_exists","equals","oldValue","newValue","indexOf","getItem","_removeItem","prototype","put","def","isObject","add","has","get","isArray","items","k","arguments","length","forget","map","pull","all","prefixWithSeparator","substring","clean","Object","keys","empty","clear","count","bind","$scope","$eval","assign","self","$id","$watch","newVal","unbind","watchId","instance","getDriver","getNamespace","supported"],"mappings":"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","file":"angular-locker.min.js","sourcesContent":["/**\n * angular-locker\n *\n * A simple & configurable abstraction for local/session storage in angular projects.\n *\n * @link https://github.com/tymondesigns/angular-locker\n * @author Sean Tymon @tymondesigns\n * @license MIT License, http://www.opensource.org/licenses/MIT\n */\n\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n define(function () {\n return factory(root.angular);\n });\n } else if (typeof exports === 'object') {\n module.exports = factory(root.angular || (window && window.angular));\n } else {\n factory(root.angular);\n }\n})(this, function (angular) {\n\n 'use strict';\n\n angular.module('angular-locker', [])\n\n .provider('locker', function () {\n\n /**\n * If value is a function then execute, otherwise return\n *\n * @param {Mixed} value\n * @param {Mixed} param\n * @return {Mixed}\n */\n var _value = function (value, param) {\n return angular.isFunction(value) ? value(param) : value;\n };\n\n /**\n * Determine whether a value is defined and not null\n *\n * @param {Mixed} value\n * @return {Boolean}\n */\n var _defined = function (value) {\n return angular.isDefined(value) && value !== null;\n };\n\n /**\n * Trigger an error\n *\n * @param {String} msg\n * @return {void}\n */\n var _error = function (msg) {\n throw new Error('[angular-locker] ' + msg);\n };\n\n /**\n * Set the defaults\n *\n * @type {Object}\n */\n var defaults = {\n driver: 'local',\n namespace: 'locker',\n eventsEnabled: true,\n separator: '.'\n };\n\n return {\n\n /**\n * Allow the defaults to be specified via the `lockerProvider`\n *\n * @param {Object} value\n */\n defaults: function (value) {\n if (! _defined(value)) return defaults;\n\n angular.forEach(value, function (val, key) {\n if (defaults.hasOwnProperty(key)) defaults[key] = val;\n });\n },\n\n /**\n * The locker service\n */\n $get: ['$window', '$rootScope', '$parse', function ($window, $rootScope, $parse) {\n\n /**\n * Define the Locker class\n *\n * @param {Object} options\n */\n function Locker (options) {\n\n /**\n * The config options\n *\n * @type {Object}\n */\n this._options = options;\n\n /**\n * Out of the box drivers\n *\n * @type {Object}\n */\n this._registeredDrivers = {\n local: $window.localStorage,\n session: $window.sessionStorage\n };\n\n /**\n * Get the Storage instance from the key\n *\n * @param {String} driver\n * @return {Storage}\n */\n this._resolveDriver = function (driver) {\n if (! this._registeredDrivers.hasOwnProperty(driver)) {\n _error('The driver \"' + driver + '\" was not found.');\n }\n\n return this._registeredDrivers[driver];\n };\n\n /**\n * The driver instance\n *\n * @type {Storage}\n */\n this._driver = this._resolveDriver(options.driver);\n\n /**\n * The namespace value\n *\n * @type {String}\n */\n this._namespace = options.namespace;\n\n /**\n * Separates the namespace from the keys\n *\n * @type {String}\n */\n this._separator = options.separator;\n\n /**\n * Store the watchers here so we can un-register them later\n *\n * @type {Object}\n */\n this._watchers = {};\n\n /**\n * Check browser support\n *\n * @see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js#L38-L47\n * @param {String} driver\n * @return {Boolean}\n */\n this._checkSupport = function (driver) {\n if (angular.isUndefined(this._supported)) {\n var l = 'l';\n try {\n this._resolveDriver(driver || 'local').setItem(l, l);\n this._resolveDriver(driver || 'local').removeItem(l);\n this._supported = true;\n } catch (e) {\n this._supported = false;\n }\n }\n\n return this._supported;\n };\n\n /**\n * Build the storage key from the namspace\n *\n * @param {String} key\n * @return {String}\n */\n this._getPrefix = function (key) {\n if (! this._namespace) return key;\n\n return this._namespace + this._separator + key;\n };\n\n /**\n * Try to encode value as json, or just return the value upon failure\n *\n * @param {Mixed} value\n * @return {Mixed}\n */\n this._serialize = function (value) {\n try {\n return angular.toJson(value);\n } catch (e) {\n return value;\n }\n };\n\n /**\n * Try to parse value as json, if it fails then it probably isn't json so just return it\n *\n * @param {String} value\n * @return {Object|String}\n */\n this._unserialize = function (value) {\n try {\n return angular.fromJson(value);\n } catch (e) {\n return value;\n }\n };\n\n /**\n * Trigger an event\n *\n * @param {String} name\n * @param {Object} payload\n * @return {void}\n */\n this._event = function (name, payload) {\n if (! this._options.eventsEnabled) return;\n\n $rootScope.$emit(name, angular.extend(payload, {\n driver: this._options.driver,\n namespace: this._namespace,\n }));\n };\n\n /**\n * Add to storage\n *\n * @param {String} key\n * @param {Mixed} value\n */\n this._setItem = function (key, value) {\n if (! this._checkSupport()) _error('The browser does not support localStorage');\n\n try {\n var oldVal = this._getItem(key);\n this._driver.setItem(this._getPrefix(key), this._serialize(value));\n if (this._exists(key) && ! angular.equals(oldVal, value)) {\n this._event('locker.item.updated', { key: key, oldValue: oldVal, newValue: value });\n } else {\n this._event('locker.item.added', { key: key, value: value });\n }\n } catch (e) {\n if (['QUOTA_EXCEEDED_ERR', 'NS_ERROR_DOM_QUOTA_REACHED', 'QuotaExceededError'].indexOf(e.name) !== -1) {\n _error('The browser storage quota has been exceeded');\n } else {\n _error('Could not add item with key \"' + key + '\"');\n }\n }\n };\n\n /**\n * Get from storage\n *\n * @param {String} key\n * @return {Mixed}\n */\n this._getItem = function (key) {\n if (! this._checkSupport()) _error('The browser does not support localStorage');\n\n return this._unserialize(this._driver.getItem(this._getPrefix(key)));\n };\n\n /**\n * Exists in storage\n *\n * @param {String} key\n * @return {Boolean}\n */\n this._exists = function (key) {\n if (! this._checkSupport()) _error('The browser does not support localStorage');\n\n return this._driver.hasOwnProperty(this._getPrefix(_value(key)));\n };\n\n /**\n * Remove from storage\n *\n * @param {String} key\n * @return {Boolean}\n */\n this._removeItem = function (key) {\n if (! this._checkSupport()) _error('The browser does not support localStorage');\n\n if (! this._exists(key)) return false;\n\n this._driver.removeItem(this._getPrefix(key));\n this._event('locker.item.forgotten', { key: key });\n\n return true;\n };\n }\n\n /**\n * Define the public api\n *\n * @type {Object}\n */\n Locker.prototype = {\n\n /**\n * Add a new item to storage (even if it already exists)\n *\n * @param {Mixed} key\n * @param {Mixed} value\n * @param {Mixed} def\n * @return {self}\n */\n put: function (key, value, def) {\n if (! _defined(key)) return false;\n key = _value(key);\n\n if (angular.isObject(key)) {\n angular.forEach(key, function (value, key) {\n this._setItem(key, _defined(value) ? value : def);\n }, this);\n } else {\n if (! _defined(value)) return false;\n var val = this._getItem(key);\n this._setItem(key, _value(value, _defined(val) ? val : def));\n }\n\n return this;\n },\n\n /**\n * Add an item to storage if it doesn't already exist\n *\n * @param {Mixed} key\n * @param {Mixed} value\n * @param {Mixed} def\n * @return {Boolean}\n */\n add: function (key, value, def) {\n if (! this.has(key)) {\n this.put(key, value, def);\n return true;\n }\n\n return false;\n },\n\n /**\n * Retrieve the specified item from storage\n *\n * @param {String|Array} key\n * @param {Mixed} def\n * @return {Mixed}\n */\n get: function (key, def) {\n if (angular.isArray(key)) {\n var items = {};\n angular.forEach(key, function (k) {\n if (this.has(k)) items[k] = this._getItem(k);\n }, this);\n\n return items;\n }\n\n if (! this.has(key)) return arguments.length === 2 ? def : void 0;\n\n return this._getItem(key);\n },\n\n /**\n * Determine whether the item exists in storage\n *\n * @param {String|Function} key\n * @return {Boolean}\n */\n has: function (key) {\n return this._exists(key);\n },\n\n /**\n * Remove specified item(s) from storage\n *\n * @param {Mixed} key\n * @return {Object}\n */\n forget: function (key) {\n key = _value(key);\n\n if (angular.isArray(key)) {\n key.map(this._removeItem, this);\n } else {\n this._removeItem(key);\n }\n\n return this;\n },\n\n /**\n * Retrieve the specified item from storage and then remove it\n *\n * @param {String|Array} key\n * @param {Mixed} def\n * @return {Mixed}\n */\n pull: function (key, def) {\n var value = this.get(key, def);\n this.forget(key);\n\n return value;\n },\n\n /**\n * Return all items in storage within the current namespace/driver\n *\n * @return {Object}\n */\n all: function () {\n var items = {};\n angular.forEach(this._driver, function (value, key) {\n if (this._namespace) {\n var prefixWithSeparator = this._namespace + this._separator;\n if (key.indexOf(prefixWithSeparator) === 0) {\n key = key.substring(prefixWithSeparator.length);\n }\n }\n if (this.has(key)) items[key] = this.get(key);\n }, this);\n\n return items;\n },\n\n /**\n * Remove all items set within the current namespace/driver\n *\n * @return {self}\n */\n clean: function () {\n this.forget(Object.keys(this.all()));\n\n return this;\n },\n\n /**\n * Empty the current storage driver completely. careful now.\n *\n * @return {self}\n */\n empty: function () {\n this._driver.clear();\n\n return this;\n },\n\n /**\n * Get the total number of items within the current namespace\n *\n * @return {Integer}\n */\n count: function () {\n return Object.keys(this.all()).length;\n },\n\n /**\n * Bind a storage key to a $scope property\n *\n * @param {Object} $scope\n * @param {String} key\n * @param {Mixed} def\n * @return {self}\n */\n bind: function ($scope, key, def) {\n if (! _defined( $scope.$eval(key) )) {\n $parse(key).assign($scope, this.get(key, def));\n if (! this.has(key)) this.put(key, def);\n }\n\n var self = this;\n this._watchers[key + $scope.$id] = $scope.$watch(key, function (newVal) {\n if (_defined(newVal)) self.put(key, newVal);\n }, angular.isObject($scope[key]));\n\n return this;\n },\n\n /**\n * Unbind a storage key from a $scope property\n *\n * @param {Object} $scope\n * @param {String} key\n * @return {self}\n */\n unbind: function ($scope, key) {\n $parse(key).assign($scope, void 0);\n this.forget(key);\n\n var watchId = key + $scope.$id;\n\n if (this._watchers[watchId]) {\n // execute the de-registration function\n this._watchers[watchId]();\n delete this._watchers[watchId];\n }\n\n return this;\n },\n\n /**\n * Set the storage driver on a new instance to enable overriding defaults\n *\n * @param {String} driver\n * @return {self}\n */\n driver: function (driver) {\n // no need to create a new instance if the driver is the same\n if (driver === this._options.driver) return this;\n\n return this.instance(angular.extend(this._options, { driver: driver }));\n },\n\n /**\n * Get the currently set driver\n *\n * @return {Storage}\n */\n getDriver: function () {\n return this._driver;\n },\n\n /**\n * Set the namespace on a new instance to enable overriding defaults\n *\n * @param {String} namespace\n * @return {self}\n */\n namespace: function (namespace) {\n // no need to create a new instance if the namespace is the same\n if (namespace === this._namespace) return this;\n\n return this.instance(angular.extend(this._options, { namespace: namespace }));\n },\n\n /**\n * Get the currently set namespace\n *\n * @return {String}\n */\n getNamespace: function () {\n return this._namespace;\n },\n\n /**\n * Check browser support\n *\n * @see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js#L38-L47\n * @param {String} driver\n * @return {Boolean}\n */\n supported: function (driver) {\n return this._checkSupport(driver);\n },\n\n /**\n * Get a new instance of Locker\n *\n * @param {Object} options\n * @return {Locker}\n */\n instance: function (options) {\n return new Locker(options);\n }\n };\n\n // return the default instance\n return new Locker(defaults);\n }]\n };\n\n });\n\n});\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["angular-locker.min.js"],"names":["root","factory","define","amd","angular","exports","module","window","this","provider","_value","value","param","isFunction","_defined","isDefined","_error","msg","Error","defaults","driver","namespace","eventsEnabled","separator","forEach","val","key","hasOwnProperty","$get","$window","$rootScope","$parse","Locker","options","_options","_registeredDrivers","local","localStorage","session","sessionStorage","_resolveDriver","_driver","_namespace","_separator","_watchers","_checkSupport","_supported","l","setItem","removeItem","e","_getPrefix","_serialize","toJson","_unserialize","fromJson","_event","name","payload","$emit","extend","_setItem","oldVal","_getItem","_exists","equals","oldValue","newValue","indexOf","getItem","_removeItem","prototype","put","def","isObject","add","has","get","isArray","items","k","arguments","length","forget","map","pull","all","prefix","substring","keys","Object","clean","empty","clear","count","bind","$scope","$eval","assign","self","$id","$watch","newVal","unbind","watchId","instance","getDriver","getNamespace","supported"],"mappings":"CAUA,SAAWA,EAAMC,GACS,kBAAXC,SAAyBA,OAAOC,IACvCD,OAAO,WACH,MAAOD,GAAQD,EAAKI,WAEE,gBAAZC,SACdC,OAAOD,QAAUJ,EAAQD,EAAKI,SAAYG,QAAUA,OAAOH,SAE3DH,EAAQD,EAAKI,UAElBI,KAAM,SAAUJ,GAEf,YAEAA,GAAQE,OAAO,qBAEdG,SAAS,SAAU,WAShB,GAAIC,GAAS,SAAUC,EAAOC,GAC1B,MAAOR,GAAQS,WAAWF,GAASA,EAAMC,GAASD,GASlDG,EAAW,SAAUH,GACrB,MAAOP,GAAQW,UAAUJ,IAAoB,OAAVA,GASnCK,EAAS,SAAUC,GACnB,KAAM,IAAIC,OAAM,oBAAsBD,IAQtCE,GACAC,OAAQ,QACRC,UAAW,SACXC,eAAe,EACfC,UAAW,IAGf,QAOIJ,SAAU,SAAUR,GAChB,MAAMG,GAASH,OAEfP,GAAQoB,QAAQb,EAAO,SAAUc,EAAKC,GAC9BP,EAASQ,eAAeD,KAAMP,EAASO,GAAOD,KAHxBN,GAUlCS,MAAO,UAAW,aAAc,SAAU,SAAUC,EAASC,EAAYC,GAOrE,QAASC,GAAQC,GAObzB,KAAK0B,SAAWD,EAOhBzB,KAAK2B,oBACDC,MAAOP,EAAQQ,aACfC,QAAST,EAAQU,gBASrB/B,KAAKgC,eAAiB,SAAUpB,GAK5B,MAJMZ,MAAK2B,mBAAmBR,eAAeP,IACzCJ,EAAO,eAAiBI,EAAS,oBAG9BZ,KAAK2B,mBAAmBf,IAQnCZ,KAAKiC,QAAUjC,KAAKgC,eAAeP,EAAQb,QAO3CZ,KAAKkC,WAAaT,EAAQZ,UAO1Bb,KAAKmC,WAAaV,EAAQV,UAO1Bf,KAAKoC,aASLpC,KAAKqC,cAAgB,SAAUzB,GAC3B,IAAMN,EAASN,KAAKsC,YAAa,CAC7B,GAAIC,GAAI,GACR,KACIvC,KAAKgC,eAAepB,GAAU,SAAS4B,QAAQD,EAAGA,GAClDvC,KAAKgC,eAAepB,GAAU,SAAS6B,WAAWF,GAClDvC,KAAKsC,YAAa,EACpB,MAAOI,GACL1C,KAAKsC,YAAa,GAI1B,MAAOtC,MAAKsC,YAShBtC,KAAK2C,WAAa,SAAUzB,GACxB,MAAMlB,MAAKkC,WAEJlC,KAAKkC,WAAalC,KAAKmC,WAAajB,EAFbA,GAWlClB,KAAK4C,WAAa,SAAUzC,GACxB,IACI,MAAOP,GAAQiD,OAAO1C,GACxB,MAAOuC,GACL,MAAOvC,KAUfH,KAAK8C,aAAe,SAAU3C,GAC1B,IACI,MAAOP,GAAQmD,SAAS5C,GAC1B,MAAOuC,GACL,MAAOvC,KAWfH,KAAKgD,OAAS,SAAUC,EAAMC,GACpBlD,KAAK0B,SAASZ,eAEpBQ,EAAW6B,MAAMF,EAAMrD,EAAQwD,OAAOF,GAClCtC,OAAQZ,KAAK0B,SAASd,OACtBC,UAAWb,KAAKkC,eAUxBlC,KAAKqD,SAAW,SAAUnC,EAAKf,GACrBH,KAAKqC,iBAAiB7B,EAAO,4CAEnC,KACI,GAAI8C,GAAStD,KAAKuD,SAASrC,EAC3BlB,MAAKiC,QAAQO,QAAQxC,KAAK2C,WAAWzB,GAAMlB,KAAK4C,WAAWzC,IACvDH,KAAKwD,QAAQtC,KAAUtB,EAAQ6D,OAAOH,EAAQnD,GAC9CH,KAAKgD,OAAO,uBAAyB9B,IAAKA,EAAKwC,SAAUJ,EAAQK,SAAUxD,IAE3EH,KAAKgD,OAAO,qBAAuB9B,IAAKA,EAAKf,MAAOA,IAE1D,MAAOuC,GAEDlC,EAD+F,MAA9F,qBAAsB,6BAA8B,sBAAsBoD,QAAQlB,EAAEO,MAC9E,8CAEA,gCAAkC/B,EAAM,OAW3DlB,KAAKuD,SAAW,SAAUrC,GAGtB,MAFMlB,MAAKqC,iBAAiB7B,EAAO,6CAE5BR,KAAK8C,aAAa9C,KAAKiC,QAAQ4B,QAAQ7D,KAAK2C,WAAWzB,MASlElB,KAAKwD,QAAU,SAAUtC,GAGrB,MAFMlB,MAAKqC,iBAAiB7B,EAAO,6CAE5BR,KAAKiC,QAAQd,eAAenB,KAAK2C,WAAWzC,EAAOgB,MAS9DlB,KAAK8D,YAAc,SAAU5C,GAGzB,MAFMlB,MAAKqC,iBAAiB7B,EAAO,6CAE7BR,KAAKwD,QAAQtC,IAEnBlB,KAAKiC,QAAQQ,WAAWzC,KAAK2C,WAAWzB,IACxClB,KAAKgD,OAAO,yBAA2B9B,IAAKA,KAErC,IALyB,GAiSxC,MAnRAM,GAAOuC,WAUHC,IAAK,SAAU9C,EAAKf,EAAO8D,GACvB,IAAM3D,EAASY,GAAM,OAAO,CAG5B,IAFAA,EAAMhB,EAAOgB,GAETtB,EAAQsE,SAAShD,GACjBtB,EAAQoB,QAAQE,EAAK,SAAUf,EAAOe,GAClClB,KAAKqD,SAASnC,EAAKZ,EAASH,GAASA,EAAQ8D,IAC9CjE,UACA,CACH,IAAMM,EAASH,GAAQ,OAAO,CAC9B,IAAIc,GAAMjB,KAAKuD,SAASrC,EACxBlB,MAAKqD,SAASnC,EAAKhB,EAAOC,EAAOG,EAASW,GAAOA,EAAMgD,IAG3D,MAAOjE,OAWXmE,IAAK,SAAUjD,EAAKf,EAAO8D,GACvB,MAAMjE,MAAKoE,IAAIlD,IAKR,GAJHlB,KAAKgE,IAAI9C,EAAKf,EAAO8D,IACd,IAafI,IAAK,SAAUnD,EAAK+C,GAChB,GAAIrE,EAAQ0E,QAAQpD,GAAM,CACtB,GAAIqD,KAKJ,OAJA3E,GAAQoB,QAAQE,EAAK,SAAUsD,GACvBxE,KAAKoE,IAAII,KAAID,EAAMC,GAAKxE,KAAKuD,SAASiB,KAC3CxE,MAEIuE,EAGX,MAAMvE,MAAKoE,IAAIlD,GAERlB,KAAKuD,SAASrC,GAF4B,IAArBuD,UAAUC,OAAeT,EAAM,QAW/DG,IAAK,SAAUlD,GACX,MAAOlB,MAAKwD,QAAQtC,IASxByD,OAAQ,SAAUzD,GASd,MARAA,GAAMhB,EAAOgB,GAETtB,EAAQ0E,QAAQpD,GAChBA,EAAI0D,IAAI5E,KAAK8D,YAAa9D,MAE1BA,KAAK8D,YAAY5C,GAGdlB,MAUX6E,KAAM,SAAU3D,EAAK+C,GACjB,GAAI9D,GAAQH,KAAKqE,IAAInD,EAAK+C,EAG1B,OAFAjE,MAAK2E,OAAOzD,GAELf,GAQX2E,IAAK,WACD,GAAIP,KASJ,OARA3E,GAAQoB,QAAQhB,KAAKiC,QAAS,SAAU9B,EAAOe,GAC3C,GAAIlB,KAAKkC,WAAY,CACjB,GAAI6C,GAAS/E,KAAKkC,WAAalC,KAAKmC,UACR,KAAxBjB,EAAI0C,QAAQmB,KAAe7D,EAAMA,EAAI8D,UAAUD,EAAOL,SAE1D1E,KAAKoE,IAAIlD,KAAMqD,EAAMrD,GAAOlB,KAAKqE,IAAInD,KAC1ClB,MAEIuE,GAQXU,KAAM,WACF,MAAOC,QAAOD,KAAKjF,KAAK8E,QAQ5BK,MAAO,WACH,MAAOnF,MAAK2E,OAAO3E,KAAKiF,SAQ5BG,MAAO,WAGH,MAFApF,MAAKiC,QAAQoD,QAENrF,MAQXsF,MAAO,WACH,MAAOtF,MAAKiF,OAAOP,QAWvBa,KAAM,SAAUC,EAAQtE,EAAK+C,GACnB3D,EAAUkF,EAAOC,MAAMvE,MACzBK,EAAOL,GAAKwE,OAAOF,EAAQxF,KAAKqE,IAAInD,EAAK+C,IACnCjE,KAAKoE,IAAIlD,IAAMlB,KAAKgE,IAAI9C,EAAK+C,GAGvC,IAAI0B,GAAO3F,IAKX,OAJAA,MAAKoC,UAAUlB,EAAMsE,EAAOI,KAAOJ,EAAOK,OAAO3E,EAAK,SAAU4E,GACxDxF,EAASwF,IAASH,EAAK3B,IAAI9C,EAAK4E,IACrClG,EAAQsE,SAASsB,EAAOtE,KAEpBlB,MAUX+F,OAAQ,SAAUP,EAAQtE,GACtBK,EAAOL,GAAKwE,OAAOF,EAAQ,QAC3BxF,KAAK2E,OAAOzD,EAEZ,IAAI8E,GAAU9E,EAAMsE,EAAOI,GAQ3B,OANI5F,MAAKoC,UAAU4D,KAEfhG,KAAKoC,UAAU4D,WACRhG,MAAKoC,UAAU4D,IAGnBhG,MASXY,OAAQ,SAAUA,GAEd,MAAIA,KAAWZ,KAAK0B,SAASd,OAAeZ,KAErCA,KAAKiG,SAASrG,EAAQwD,OAAOpD,KAAK0B,UAAYd,OAAQA,MAQjEsF,UAAW,WACP,MAAOlG,MAAKiC,SAShBpB,UAAW,SAAUA,GAEjB,MAAIA,KAAcb,KAAKkC,WAAmBlC,KAEnCA,KAAKiG,SAASrG,EAAQwD,OAAOpD,KAAK0B,UAAYb,UAAWA,MAQpEsF,aAAc,WACV,MAAOnG,MAAKkC,YAUhBkE,UAAW,SAAUxF,GACjB,MAAOZ,MAAKqC,cAAczB,IAS9BqF,SAAU,SAAUxE,GAChB,MAAO,IAAID,GAAOC,KAKnB,GAAID,GAAOb","file":"angular-locker.min.js","sourcesContent":["/**\n * angular-locker\n *\n * A simple & configurable abstraction for local/session storage in angular projects.\n *\n * @link https://github.com/tymondesigns/angular-locker\n * @author Sean Tymon @tymondesigns\n * @license MIT License, http://www.opensource.org/licenses/MIT\n */\n\n(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n define(function () {\n return factory(root.angular);\n });\n } else if (typeof exports === 'object') {\n module.exports = factory(root.angular || (window && window.angular));\n } else {\n factory(root.angular);\n }\n})(this, function (angular) {\n\n 'use strict';\n\n angular.module('angular-locker', [])\n\n .provider('locker', function () {\n\n /**\n * If value is a function then execute, otherwise return\n *\n * @param {Mixed} value\n * @param {Mixed} param\n * @return {Mixed}\n */\n var _value = function (value, param) {\n return angular.isFunction(value) ? value(param) : value;\n };\n\n /**\n * Determine whether a value is defined and not null\n *\n * @param {Mixed} value\n * @return {Boolean}\n */\n var _defined = function (value) {\n return angular.isDefined(value) && value !== null;\n };\n\n /**\n * Trigger an error\n *\n * @param {String} msg\n * @return {void}\n */\n var _error = function (msg) {\n throw new Error('[angular-locker] ' + msg);\n };\n\n /**\n * Set the defaults\n *\n * @type {Object}\n */\n var defaults = {\n driver: 'local',\n namespace: 'locker',\n eventsEnabled: true,\n separator: '.'\n };\n\n return {\n\n /**\n * Allow the defaults to be specified via the `lockerProvider`\n *\n * @param {Object} value\n */\n defaults: function (value) {\n if (! _defined(value)) return defaults;\n\n angular.forEach(value, function (val, key) {\n if (defaults.hasOwnProperty(key)) defaults[key] = val;\n });\n },\n\n /**\n * The locker service\n */\n $get: ['$window', '$rootScope', '$parse', function ($window, $rootScope, $parse) {\n\n /**\n * Define the Locker class\n *\n * @param {Object} options\n */\n function Locker (options) {\n\n /**\n * The config options\n *\n * @type {Object}\n */\n this._options = options;\n\n /**\n * Out of the box drivers\n *\n * @type {Object}\n */\n this._registeredDrivers = {\n local: $window.localStorage,\n session: $window.sessionStorage\n };\n\n /**\n * Get the Storage instance from the key\n *\n * @param {String} driver\n * @return {Storage}\n */\n this._resolveDriver = function (driver) {\n if (! this._registeredDrivers.hasOwnProperty(driver)) {\n _error('The driver \"' + driver + '\" was not found.');\n }\n\n return this._registeredDrivers[driver];\n };\n\n /**\n * The driver instance\n *\n * @type {Storage}\n */\n this._driver = this._resolveDriver(options.driver);\n\n /**\n * The namespace value\n *\n * @type {String}\n */\n this._namespace = options.namespace;\n\n /**\n * Separates the namespace from the keys\n *\n * @type {String}\n */\n this._separator = options.separator;\n\n /**\n * Store the watchers here so we can un-register them later\n *\n * @type {Object}\n */\n this._watchers = {};\n\n /**\n * Check browser support\n *\n * @see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js#L38-L47\n * @param {String} driver\n * @return {Boolean}\n */\n this._checkSupport = function (driver) {\n if (! _defined(this._supported)) {\n var l = 'l';\n try {\n this._resolveDriver(driver || 'local').setItem(l, l);\n this._resolveDriver(driver || 'local').removeItem(l);\n this._supported = true;\n } catch (e) {\n this._supported = false;\n }\n }\n\n return this._supported;\n };\n\n /**\n * Build the storage key from the namspace\n *\n * @param {String} key\n * @return {String}\n */\n this._getPrefix = function (key) {\n if (! this._namespace) return key;\n\n return this._namespace + this._separator + key;\n };\n\n /**\n * Try to encode value as json, or just return the value upon failure\n *\n * @param {Mixed} value\n * @return {Mixed}\n */\n this._serialize = function (value) {\n try {\n return angular.toJson(value);\n } catch (e) {\n return value;\n }\n };\n\n /**\n * Try to parse value as json, if it fails then it probably isn't json so just return it\n *\n * @param {String} value\n * @return {Object|String}\n */\n this._unserialize = function (value) {\n try {\n return angular.fromJson(value);\n } catch (e) {\n return value;\n }\n };\n\n /**\n * Trigger an event\n *\n * @param {String} name\n * @param {Object} payload\n * @return {void}\n */\n this._event = function (name, payload) {\n if (! this._options.eventsEnabled) return;\n\n $rootScope.$emit(name, angular.extend(payload, {\n driver: this._options.driver,\n namespace: this._namespace,\n }));\n };\n\n /**\n * Add to storage\n *\n * @param {String} key\n * @param {Mixed} value\n */\n this._setItem = function (key, value) {\n if (! this._checkSupport()) _error('The browser does not support localStorage');\n\n try {\n var oldVal = this._getItem(key);\n this._driver.setItem(this._getPrefix(key), this._serialize(value));\n if (this._exists(key) && ! angular.equals(oldVal, value)) {\n this._event('locker.item.updated', { key: key, oldValue: oldVal, newValue: value });\n } else {\n this._event('locker.item.added', { key: key, value: value });\n }\n } catch (e) {\n if (['QUOTA_EXCEEDED_ERR', 'NS_ERROR_DOM_QUOTA_REACHED', 'QuotaExceededError'].indexOf(e.name) !== -1) {\n _error('The browser storage quota has been exceeded');\n } else {\n _error('Could not add item with key \"' + key + '\"');\n }\n }\n };\n\n /**\n * Get from storage\n *\n * @param {String} key\n * @return {Mixed}\n */\n this._getItem = function (key) {\n if (! this._checkSupport()) _error('The browser does not support localStorage');\n\n return this._unserialize(this._driver.getItem(this._getPrefix(key)));\n };\n\n /**\n * Exists in storage\n *\n * @param {String} key\n * @return {Boolean}\n */\n this._exists = function (key) {\n if (! this._checkSupport()) _error('The browser does not support localStorage');\n\n return this._driver.hasOwnProperty(this._getPrefix(_value(key)));\n };\n\n /**\n * Remove from storage\n *\n * @param {String} key\n * @return {Boolean}\n */\n this._removeItem = function (key) {\n if (! this._checkSupport()) _error('The browser does not support localStorage');\n\n if (! this._exists(key)) return false;\n\n this._driver.removeItem(this._getPrefix(key));\n this._event('locker.item.forgotten', { key: key });\n\n return true;\n };\n }\n\n /**\n * Define the public api\n *\n * @type {Object}\n */\n Locker.prototype = {\n\n /**\n * Add a new item to storage (even if it already exists)\n *\n * @param {Mixed} key\n * @param {Mixed} value\n * @param {Mixed} def\n * @return {self}\n */\n put: function (key, value, def) {\n if (! _defined(key)) return false;\n key = _value(key);\n\n if (angular.isObject(key)) {\n angular.forEach(key, function (value, key) {\n this._setItem(key, _defined(value) ? value : def);\n }, this);\n } else {\n if (! _defined(value)) return false;\n var val = this._getItem(key);\n this._setItem(key, _value(value, _defined(val) ? val : def));\n }\n\n return this;\n },\n\n /**\n * Add an item to storage if it doesn't already exist\n *\n * @param {Mixed} key\n * @param {Mixed} value\n * @param {Mixed} def\n * @return {Boolean}\n */\n add: function (key, value, def) {\n if (! this.has(key)) {\n this.put(key, value, def);\n return true;\n }\n\n return false;\n },\n\n /**\n * Retrieve the specified item from storage\n *\n * @param {String|Array} key\n * @param {Mixed} def\n * @return {Mixed}\n */\n get: function (key, def) {\n if (angular.isArray(key)) {\n var items = {};\n angular.forEach(key, function (k) {\n if (this.has(k)) items[k] = this._getItem(k);\n }, this);\n\n return items;\n }\n\n if (! this.has(key)) return arguments.length === 2 ? def : void 0;\n\n return this._getItem(key);\n },\n\n /**\n * Determine whether the item exists in storage\n *\n * @param {String|Function} key\n * @return {Boolean}\n */\n has: function (key) {\n return this._exists(key);\n },\n\n /**\n * Remove specified item(s) from storage\n *\n * @param {Mixed} key\n * @return {Object}\n */\n forget: function (key) {\n key = _value(key);\n\n if (angular.isArray(key)) {\n key.map(this._removeItem, this);\n } else {\n this._removeItem(key);\n }\n\n return this;\n },\n\n /**\n * Retrieve the specified item from storage and then remove it\n *\n * @param {String|Array} key\n * @param {Mixed} def\n * @return {Mixed}\n */\n pull: function (key, def) {\n var value = this.get(key, def);\n this.forget(key);\n\n return value;\n },\n\n /**\n * Return all items in storage within the current namespace/driver\n *\n * @return {Object}\n */\n all: function () {\n var items = {};\n angular.forEach(this._driver, function (value, key) {\n if (this._namespace) {\n var prefix = this._namespace + this._separator;\n if (key.indexOf(prefix) === 0) key = key.substring(prefix.length);\n }\n if (this.has(key)) items[key] = this.get(key);\n }, this);\n\n return items;\n },\n\n /**\n * Get the storage keys as an array\n *\n * @return {Array}\n */\n keys: function () {\n return Object.keys(this.all());\n },\n\n /**\n * Remove all items set within the current namespace/driver\n *\n * @return {self}\n */\n clean: function () {\n return this.forget(this.keys());\n },\n\n /**\n * Empty the current storage driver completely. careful now.\n *\n * @return {self}\n */\n empty: function () {\n this._driver.clear();\n\n return this;\n },\n\n /**\n * Get the total number of items within the current namespace\n *\n * @return {Integer}\n */\n count: function () {\n return this.keys().length;\n },\n\n /**\n * Bind a storage key to a $scope property\n *\n * @param {Object} $scope\n * @param {String} key\n * @param {Mixed} def\n * @return {self}\n */\n bind: function ($scope, key, def) {\n if (! _defined( $scope.$eval(key) )) {\n $parse(key).assign($scope, this.get(key, def));\n if (! this.has(key)) this.put(key, def);\n }\n\n var self = this;\n this._watchers[key + $scope.$id] = $scope.$watch(key, function (newVal) {\n if (_defined(newVal)) self.put(key, newVal);\n }, angular.isObject($scope[key]));\n\n return this;\n },\n\n /**\n * Unbind a storage key from a $scope property\n *\n * @param {Object} $scope\n * @param {String} key\n * @return {self}\n */\n unbind: function ($scope, key) {\n $parse(key).assign($scope, void 0);\n this.forget(key);\n\n var watchId = key + $scope.$id;\n\n if (this._watchers[watchId]) {\n // execute the de-registration function\n this._watchers[watchId]();\n delete this._watchers[watchId];\n }\n\n return this;\n },\n\n /**\n * Set the storage driver on a new instance to enable overriding defaults\n *\n * @param {String} driver\n * @return {self}\n */\n driver: function (driver) {\n // no need to create a new instance if the driver is the same\n if (driver === this._options.driver) return this;\n\n return this.instance(angular.extend(this._options, { driver: driver }));\n },\n\n /**\n * Get the currently set driver\n *\n * @return {Storage}\n */\n getDriver: function () {\n return this._driver;\n },\n\n /**\n * Set the namespace on a new instance to enable overriding defaults\n *\n * @param {String} namespace\n * @return {self}\n */\n namespace: function (namespace) {\n // no need to create a new instance if the namespace is the same\n if (namespace === this._namespace) return this;\n\n return this.instance(angular.extend(this._options, { namespace: namespace }));\n },\n\n /**\n * Get the currently set namespace\n *\n * @return {String}\n */\n getNamespace: function () {\n return this._namespace;\n },\n\n /**\n * Check browser support\n *\n * @see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/storage/localstorage.js#L38-L47\n * @param {String} driver\n * @return {Boolean}\n */\n supported: function (driver) {\n return this._checkSupport(driver);\n },\n\n /**\n * Get a new instance of Locker\n *\n * @param {Object} options\n * @return {Locker}\n */\n instance: function (options) {\n return new Locker(options);\n }\n };\n\n // return the default instance\n return new Locker(defaults);\n }]\n };\n\n });\n\n});\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 6076748..226e0c3 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,8 +1,8 @@ var gulp = require('gulp'), -fizzy = require('fizzy'), -pkg = require('./package.json'), -config = require('./config'), -paths = config.paths; + fizzy = require('fizzy'), + pkg = require('./package.json'), + config = require('./config'), + paths = config.paths; // Lint the JS gulp.task('lint', fizzy.task('lint', { src: paths.scripts })); diff --git a/src/angular-locker.js b/src/angular-locker.js index 16908b1..4ae46b5 100644 --- a/src/angular-locker.js +++ b/src/angular-locker.js @@ -163,7 +163,7 @@ * @return {Boolean} */ this._checkSupport = function (driver) { - if (angular.isUndefined(this._supported)) { + if (! _defined(this._supported)) { var l = 'l'; try { this._resolveDriver(driver || 'local').setItem(l, l); @@ -423,10 +423,8 @@ var items = {}; angular.forEach(this._driver, function (value, key) { if (this._namespace) { - var prefixWithSeparator = this._namespace + this._separator; - if (key.indexOf(prefixWithSeparator) === 0) { - key = key.substring(prefixWithSeparator.length); - } + var prefix = this._namespace + this._separator; + if (key.indexOf(prefix) === 0) key = key.substring(prefix.length); } if (this.has(key)) items[key] = this.get(key); }, this); @@ -434,15 +432,22 @@ return items; }, + /** + * Get the storage keys as an array + * + * @return {Array} + */ + keys: function () { + return Object.keys(this.all()); + }, + /** * Remove all items set within the current namespace/driver * * @return {self} */ clean: function () { - this.forget(Object.keys(this.all())); - - return this; + return this.forget(this.keys()); }, /** @@ -462,7 +467,7 @@ * @return {Integer} */ count: function () { - return Object.keys(this.all()).length; + return this.keys().length; }, /**