Permalink
Browse files

Some cosmetic changes and fixes for IE.

Fixes #7
  • Loading branch information...
1 parent bce8d60 commit 6ed17d7e627c70d7df639ce2e6c875c3b478eeac @d0ugal d0ugal committed Aug 19, 2012
Showing with 136 additions and 89 deletions.
  1. +136 −89 locache.js
View
225 locache.js
@@ -1,3 +1,5 @@
+/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, jquery:true, indent:4, maxerr:200 */
+
// locache VERSION-PLACEHOLDER
//
// (c) 2012 Dougal Matthews
@@ -7,7 +9,7 @@
// with DOM Storage and proves a memcache inspired API for
// setting and retrieving values.
-(function(){
+(function () {
"use strict";
@@ -17,25 +19,32 @@
// Save a reference to the global object, in most cases this is `window`.
var root = this;
+ // Object context bnding shim to support older versions of IE.
+ var bind = function (func, thisValue) {
+ return function () {
+ return func.apply(thisValue, arguments);
+ };
+ };
+
// Cache class constructor. This is the base “class” for
// locache and is used for the global instance plus any of your own
// custom caches.
// The constructor accepts a properties object, and assigns each value
// of the object to the instance. At the moment, this is only really used
// to set the 'storage' property - so you can choose a builtin or use
// your own storage mechanism.
- function LocacheCache(options){
+ function LocacheCache(options) {
- if(options && options.storage){
+ if (options && options.storage) {
this.storage = options.storage;
}
// Re-bind the context of the two async methods so `this` is equal to
// the instance of locache. This allows them to easily access the
// other methods and storage objects. This is a bit of hack, and may
// not be the best idea.
- this.async.set = this.async.set.bind(this);
- this.async.get = this.async.get.bind(this);
+ this.async.set = bind(this.async.set, this);
+ this.async.get = bind(this.async.get, this);
}
@@ -45,7 +54,7 @@
// Boolean value that determines if they browser supports localStorage or
// not. This is based on the Modernizr implementation that can be found
// in [the Modernizr GitHub repository.](https://github.com/Modernizr/Modernizr/blob/c56fb8b09515f629806ca44742932902ac145302/modernizr.js#L696-731)
- var supportsLocalStorage = LocacheCache.prototype.supportsLocalStorage = (function() {
+ var supportsLocalStorage = LocacheCache.prototype.supportsLocalStorage = (function () {
try {
// Create a test value and attempt to set, get and remove the
@@ -58,7 +67,7 @@
// that point we can flag the browser as not supporting
// localStorage.
return true;
- } catch(e) {
+ } catch (e) {
return false;
}
@@ -67,7 +76,7 @@
// Boolean value that determines if they browser supports sessionStorage or
// not. This is based on the Modernizr implementation that can be found
// in [the Modernizr GitHub repository.](https://github.com/Modernizr/Modernizr/blob/c56fb8b09515f629806ca44742932902ac145302/modernizr.js#L696-731)
- var supportsSessionStorage = LocacheCache.prototype.supportsSessionStorage = (function() {
+ var supportsSessionStorage = LocacheCache.prototype.supportsSessionStorage = (function () {
try {
// Create a test value and attempt to set, get and remove the
@@ -80,7 +89,7 @@
// that point we can flag the browser as not supporting
// sessionStorage.
return true;
- } catch(e) {
+ } catch (e) {
return false;
}
@@ -89,14 +98,17 @@
// Boolean flag to check if the browser supports native JSON.
var supportsNativeJSON = LocacheCache.prototype.supportsNativeJSON = !!root.JSON;
+ // Booleant flat to check if the browser supports HTML postMessage.
+ var supportsPostMessage = LocacheCache.prototype.supportsPostMessage = !!window.postMessage;
+
// Internal utility functions
// --------------------
// A defer implempmentation to avoid IO access blocking the current
// thread. This is exposed on the LocacheCache prototype, simply so it
// can be accessed from within the unit tests. It's not intended for
// public use.
- var defer = LocacheCache.prototype._defer = (function(){
+ var defer = LocacheCache.prototype._defer = (function () {
// Store of the pending functions
var timeouts = [];
@@ -107,13 +119,24 @@
// have the message name defined above, don't do anything and allow it
// to propogate to other handlers. Otherwise, its meant for us so stop
// the event.
- root.addEventListener("message", function (event) {
+ var addEventListener;
+ if (root.addEventListener) {
+ addEventListener = root.addEventListener;
+ } else if (root.attachEvent) {
+ addEventListener = root.attachEvent;
+ }
- if (event.source !== root || event.data !== messageName) return;
+ addEventListener("message", function (event) {
+
+ if (event.source !== root || event.data !== messageName) {
+ return;
+ }
event.stopPropagation();
// Make sure we have some pending functions, otherwise return.
- if (timeouts.length === 0) return;
+ if (timeouts.length === 0) {
+ return;
+ }
// take the oldest from the 'queue' and call that functions.
var fn = timeouts.shift();
@@ -126,34 +149,34 @@
// Constructor for the Defer, takes a function onject and stores it
// on itself.
- function Deferred(fn){
+ function Deferred(fn) {
this.fn = fn;
}
// The defer method runs the function and stores the result. Uppon
// finishing, it looks for a finishedFunction, that if exists, is
// called and passed the result.
- Deferred.prototype.defer = function(){
+ Deferred.prototype.defer = function () {
this.resultValue = this.fn();
- if (this.hasOwnProperty('finishedFunction')){
+ if (this.hasOwnProperty('finishedFunction')) {
this.finishedFunction(this.resultValue);
}
};
// Return if the defer has finished. THis is determined by the
// existance of the resultValue on the object.
- Deferred.prototype.hasFinished = function(){
+ Deferred.prototype.hasFinished = function () {
return this.hasOwnProperty('resultValue');
};
// The finished function takes another function and assigns that to
// be called when the deferred function has finished.
- Deferred.prototype.finished = function(fn){
+ Deferred.prototype.finished = function (fn) {
this.finishedFunction = fn;
// Check to see if the deferred function has finished, this can
// happen if its very quick or the finished function is assigned
// late. If it is, call it straight away.
- if (this.hasFinished()){
+ if (this.hasFinished()) {
this.finishedFunction(this.resultValue);
}
// Make this object chainable.
@@ -167,7 +190,7 @@
var d = new Deferred(fn);
// Add the defer method on the Deffered object, with the instance
// bound to the queue.
- timeouts.push(d.defer.bind(d));
+ timeouts.push(bind(d.defer, d));
// post a message to the window that can be recieved by the
// message handler.
root.postMessage(messageName, "*");
@@ -195,59 +218,59 @@
// Wrapper around localStorage - persistent local storage in the
// browser.
local: {
- set: function(key, value){
+ set: function (key, value) {
return root.localStorage.setItem(key, value);
},
- get: function(key){
+ get: function (key) {
return root.localStorage.getItem(key);
},
- remove: function(key){
+ remove: function (key) {
return root.localStorage.removeItem(key);
},
- length: function(key){
+ length: function (key) {
return root.localStorage.length;
},
- key: function(index){
- if (index < 0 || index >= this.length()){
+ key: function (index) {
+ if (index < 0 || index >= this.length()) {
return;
}
return root.localStorage.key(index);
},
- enabled: function(){
- return supportsLocalStorage;
+ enabled: function () {
+ return supportsNativeJSON && supportsLocalStorage;
}
},
// Wrapper around sessionStorage - storage in the browser that is
// cleared each time a new session is started - new browser window etc.
session: {
- set: function(key, value){
+ set: function (key, value) {
return root.sessionStorage.setItem(key, value);
},
- get: function(key){
+ get: function (key) {
return root.sessionStorage.getItem(key);
},
- remove: function(key){
+ remove: function (key) {
return root.sessionStorage.removeItem(key);
},
- length: function(key){
+ length: function (key) {
return root.sessionStorage.length;
},
- key: function(index){
- if (index < 0 || index >= this.length()){
+ key: function (index) {
+ if (index < 0 || index >= this.length()) {
return;
}
return root.sessionStorage.key(index);
},
- enabled: function(){
- return supportsSessionStorage;
+ enabled: function () {
+ return supportsNativeJSON && supportsSessionStorage;
}
}
@@ -257,30 +280,30 @@
// Utility method to get the number of milliseconds since the Epoch. This
// is used when comparing keys to see if they have expired.
- var _currentTime = function(){
+ var _currentTime = function () {
return new Date().getTime();
};
// Given a key, return the key used internally for storing values without
// the risk of collisions over usage of the storage backend.
- LocacheCache.prototype.key = function(key){
+ LocacheCache.prototype.key = function (key) {
return this.cachePrefix + key;
};
// Given a key, return the key to be used internally for expiry time.
- LocacheCache.prototype.expirekey = function(key){
+ LocacheCache.prototype.expirekey = function (key) {
return this.expirePrefix + key;
};
// Given a key, look up its expire time and determine if its in the past
// or not. Returns a Boolean.
- LocacheCache.prototype.hasExpired = function(key){
+ LocacheCache.prototype.hasExpired = function (key) {
var expireKey = this.expirekey(key);
var expireValue = parseInt(this.storage.get(expireKey), 10);
// If we have non-zero integer perform the comparison.
- if (expireValue && expireValue < _currentTime()){
+ if (expireValue && expireValue < _currentTime()) {
return true;
}
@@ -293,16 +316,18 @@
// Given a key, a value and an optional number of seconds store the value
// in the storage backend.
- LocacheCache.prototype.set = function(key, value, seconds){
+ LocacheCache.prototype.set = function (key, value, seconds) {
// If the storage backend isn't supported or the key passed in is
// falsy, perform a no-op.
- if (!this.storage.enabled() || !key) return;
+ if (!this.storage.enabled() || !key) {
+ return;
+ }
var expireKey = this.expirekey(key);
var valueKey = this.key(key);
- if(seconds){
+ if (seconds) {
// The time stored is in milliseconds, but this function expects
// seconds, so multiply by 1000.
var ms = seconds * 1000;
@@ -319,15 +344,17 @@
// Fetch a value from the cache. Either returns the value, or if it
// doesn't exist (or has expired) return null.
- LocacheCache.prototype.get = function(key){
+ LocacheCache.prototype.get = function (key) {
// If the storage backend isn't supported or the key passed in is
// falsy, perform a no-op and return null.
- if (!this.storage.enabled() || !key) return null;
+ if (!this.storage.enabled() || !key) {
+ return null;
+ }
// If the value has expired, before returning null remove the key
// from the storage backend to free up the space.
- if (this.hasExpired(key)){
+ if (this.hasExpired(key)) {
this.remove(this.key(key));
return null;
}
@@ -340,10 +367,10 @@
// be handled better but its hard to know what to do here? We only
// set JSON and thus we expect JSON but we don't want to delete
// values that must have come from another source.
- if (value){
- try{
+ if (value) {
+ try {
return JSON.parse(value);
- } catch(err){
+ } catch (err) {
return null;
}
}
@@ -358,27 +385,29 @@
// contains all of the sync calls supports within locache
LocacheCache.prototype.async = {
- set: function(key, value, seconds){
- return defer(function(){
+ set: function (key, value, seconds) {
+ return defer(bind(function () {
return this.set(key, value, seconds);
- }.bind(this));
+ }, this));
},
- get: function(key){
- return defer(function(){
+ get: function (key) {
+ return defer(bind(function () {
return this.get(key);
- }.bind(this));
+ }, this));
}
};
// When removing a key - delete from the storage both the value key/value
// pair and the expiration time key/value pair.
- LocacheCache.prototype.remove = function(key){
+ LocacheCache.prototype.remove = function (key) {
// If the storage backend isn't enabled perform a no-op.
- if (!this.storage.enabled()) return;
+ if (!this.storage.enabled()) {
+ return;
+ }
var expireKey = this.expirekey(key);
var valueKey = this.key(key);
@@ -393,13 +422,15 @@
// the increment. The fetched value is always parsed as an int to make
// sure the increment will work - this means if a non-int was stored, it
// will be converted first and thus reset the counter to zero.
- LocacheCache.prototype.incr = function(key){
+ LocacheCache.prototype.incr = function (key) {
// If the storage backend isn't enabled perform a no-op.
- if (!this.storage.enabled()) return;
+ if (!this.storage.enabled()) {
+ return;
+ }
var current = parseInt(this.get(key), 10);
- if (!current){
+ if (!current) {
current = 0;
}
current ++;
@@ -409,13 +440,15 @@
};
// Exactly the same as the incr function, but with a decrementing value.
- LocacheCache.prototype.decr = function(key){
+ LocacheCache.prototype.decr = function (key) {
// If the storage backend isn't enabled perform a no-op.
- if (!this.storage.enabled()) return;
+ if (!this.storage.enabled()) {
+ return;
+ }
var current = parseInt(this.get(key), 10);
- if (!current){
+ if (!current) {
current = 0;
}
current --;
@@ -426,10 +459,12 @@
// Given a properties object, in the form of {key: value, key:value} set
// multiple keys.
- LocacheCache.prototype.setMany = function(properties, seconds){
+ LocacheCache.prototype.setMany = function (properties, seconds) {
// If the storage backend isn't enabled perform a no-op.
- if (!this.storage.enabled()) return;
+ if (!this.storage.enabled()) {
+ return;
+ }
// Iterate through all the object properties.
for (var key in properties) {
@@ -444,15 +479,15 @@
// Given an array of keys, return an array of values. If values don't
// exist, null will be in their place.
- LocacheCache.prototype.getMany = function(keys){
+ LocacheCache.prototype.getMany = function (keys) {
var results = {};
- for (var i=0; i < keys.length; i++){
+ for (var i = 0; i < keys.length; i++) {
// To ensure that the correct structure is returned, if
// the storage backend isn't enabled return an array of null
// values with the correct length.
- if (this.storage.enabled()){
+ if (this.storage.enabled()) {
results[keys[i]] = this.get(keys[i]);
} else {
results[keys[i]] = null;
@@ -466,15 +501,15 @@
// Given an array of keys, return an array of values. If values don't
// exist, null will be in their place.
- LocacheCache.prototype.getManyValues = function(keys){
+ LocacheCache.prototype.getManyValues = function (keys) {
var results = [];
- for (var i=0; i < keys.length; i++){
+ for (var i = 0; i < keys.length; i++) {
// To ensure that the correct structure is returned, if
// the storage backend isn't enabled return an array of null
// values with the correct length.
- if (this.storage.enabled()){
+ if (this.storage.enabled()) {
results.push(this.get(keys[i]));
} else {
results.push(null);
@@ -486,51 +521,61 @@
};
// Given an array of keys, remove all of them from the cache.
- LocacheCache.prototype.removeMany = function(keys){
+ LocacheCache.prototype.removeMany = function (keys) {
// If the storage backend isn't enabled perform a no-op.
- if (!this.storage.enabled()) return;
+ if (!this.storage.enabled()) {
+ return;
+ }
- for (var i=0; i < keys.length; i++){
+ for (var i = 0; i < keys.length; i++) {
this.remove(keys[i]);
}
};
// Delete all stored values from the cache. This method will only remove
// values added to the storage backend with the locache prefix in the key.
- LocacheCache.prototype.flush = function(){
+ LocacheCache.prototype.flush = function () {
// If the storage backend isn't enabled perform a no-op.
- if (!this.storage.enabled()) return;
+ if (!this.storage.enabled()) {
+ return;
+ }
var length = this.storage.length();
var prefix = this.cachePrefix;
// Iteratate through all the keys stored in the storage backend - if
// the key tarts with the prefix cache prefix, then remove that key.
// backwards to make sure removing items does not mess up the index
- for (var i=length-1; i >= 0; i-- ) {
+ for (var i = length - 1; i >= 0; i--) {
var key = this.storage.key(i);
- if (key && key.indexOf(prefix) === 0) this.storage.remove(key);
+ if (key && key.indexOf(prefix) === 0) {
+ this.storage.remove(key);
+ }
}
};
// Return the number of cache values stored in the storage backend. This
// only calculates the values stored by locache
- LocacheCache.prototype.length = function(){
+ LocacheCache.prototype.length = function () {
// If the storage backend isn't supported perform a no-op and return
// zero.
- if (!this.storage.enabled()) return 0;
+ if (!this.storage.enabled()) {
+ return 0;
+ }
var c = 0;
var length = this.storage.length();
var prefix = this.cachePrefix;
- for (var i=0; i < length; i++) {
- if (this.storage.key(i).indexOf(prefix) === 0) c++;
+ for (var i = 0; i < length; i++) {
+ if (this.storage.key(i).indexOf(prefix) === 0) {
+ c++;
+ }
}
return c;
@@ -541,23 +586,25 @@
// the keys stored in the storage backend. If they key is a locache key
// (it has the prefix) then check to see if the key has expired. If it
// has, remove the key from the cache.
- LocacheCache.prototype.cleanup = function(){
+ LocacheCache.prototype.cleanup = function () {
// If the storage backend isn't enabled perform a no-op.
- if (!this.storage.enabled()) return;
+ if (!this.storage.enabled()) {
+ return;
+ }
var length = this.storage.length();
var prefix = this.cachePrefix;
- for (var i=0; i < length; i++) {
+ for (var i = 0; i < length; i++) {
var key = this.storage.key(i);
// If the key matches, remove the prefix to get the original key
// and then make use of the normal remove method that will clean
// up the cache value key pair and the cache epiration time key
// pair.
- if (key && key.indexOf(prefix) === 0){
+ if (key && key.indexOf(prefix) === 0) {
var actualKey = key.substring(prefix.length, key.length);
- if (this.hasExpired(actualKey)){
+ if (this.hasExpired(actualKey)) {
this.remove(actualKey);
}
}
@@ -568,7 +615,7 @@
// A factory method added to the LocacheCache constructor to create
// instances of itself. Rather than placing the class publicly, wrap
// it up in a method and keep it for internal usage.
- LocacheCache.prototype.createCache = function(options){
+ LocacheCache.prototype.createCache = function (options) {
return new LocacheCache(options);
};

0 comments on commit 6ed17d7

Please sign in to comment.