Skip to content

Instantly share code, notes, and snippets.

@benekastah
Created September 2, 2011 22:39
Show Gist options
  • Save benekastah/1190123 to your computer and use it in GitHub Desktop.
Save benekastah/1190123 to your computer and use it in GitHub Desktop.
This is the basis for my DomStore repo (https://github.com/benekastah/DomStore)
(function ()
{
var hasProperty = Object.hasOwnProperty,
// make sure we have a trim function available
trim = String.prototype.trim || function () { return this.replace(/^\s*/, '').replace(/\s*$/, ''); },
// This function divides a string into multiple strings of a certain length.
// Some browsers limit an individual cookie to about 4000 bytes of data
// This allows us to store all the info we want by splitting an item into multiple cookies
divide = function (len)
{
var thisLen = this.length;
if (thisLen < len)
return [this];
var indx = 0;
var result = [];
while (indx < thisLen)
{
result.push(this.substr(indx, len));
indx += len;
}
return result;
},
// This encodes a string to json and then escapes it for safe storage in a cookie.
// This function relies on there being JSON support present.
encode = function (str, doEscape)
{
var val = str;
doEscape = doEscape === undefined ? true : doEscape;
try
{
val = JSON.stringify(val);
} catch (e)
{
val = val.toString();
}
if (doEscape)
val = escape(val);
return val;
},
// encode's companion. Reverses the process.
decode = function (str)
{
var val = unescape(str);
try
{
val = JSON.parse(val);
} catch (e) { }
return val;
},
// Gets a config object from the arguments, allowing you to pass in a single object, or a name and a value.
getConfig = function (args)
{
var config;
if (typeof args[0] !== "string")
{
config = args[0];
} else
{
config = {};
config[args[0]] = args[1];
}
return config;
},
// Tests for a function
isFn = function (item) { return typeof item === "function"; },
// Makes a name out of the arguments.
// getName("a", "b", "c") => "a_b_c"
getName = function ()
{
return Array.prototype.join.call(arguments, "_");
};
// This object takes care of all things cookie.
var cookie = (function ()
{
// Iterator that will give you each cookie stored under a particular name.
function forEachCookie(name, callback)
{
var cookies = document.cookie.split(";"),
nameRe = new RegExp("^" + name + "_\\d+$"),
cookie, thisName, thisValue;
for (var i = 0, len = cookies.length; i < len; i++)
{
cookie = cookies[i].split("=");
thisName = trim.call(cookie.shift());
if (nameRe.test(thisName))
{
thisValue = unescape(cookie.join("="));
callback(thisName, thisValue);
}
}
}
// This formulates cookie data into a string, and then writes it to document.cookie
function write(config)
{
var name = config.name,
value = config.value,
expireDate = config.expireDate,
domainName = config.domain,
pathName = config.path;
expireDate = expireDate instanceof Date ? expireDate.toUTCString() : expireDate;
var expire = expireDate ? "; expires=" + expireDate : '';
var path = pathName ? "; path=" + escape(pathName) : '';
var domain = domainName ? "; domain=" + escape(domainName) : '';
var ck = '' + name + "=" + value + expire + domain + path;
document.cookie = ck;
return ck;
}
// Return our API object
return {
// This is a setting that can be modified at any time
// It is not recommended to have a cookie exceed this length
// Any cookie longer than this will be split into multiple cookies seamlessly, so we don't have to worry about the limitation
maxLength: 4000
// The config object is a hash of key value pairs. Each key represents a new cookie that will be set.
// The prefix will be appended with an underscore to the beginning of each cookie name.
// As long as the JSON library is loaded, values can be anything. Otherwise, stick to strings here.
, set: function (config, prefix)
{
var name, value, writeConfig;
for (name in config)
{
if (!hasProperty.call(config, name)) continue;
this.remove(name);
value = config[name];
value = encode(value);
value = divide.call(value, this.maxLength - (name.length + 10));
for (var i = 0, len = value.length; i < len; i++)
{
writeConfig = {};
writeConfig.name = getName(prefix, name, i);
writeConfig.value = value[i];
write(writeConfig);
}
}
}
// The values will be JSON decoded automatically.
, get: function (name, prefix)
{
var value = "";
forEachCookie(getName(prefix, name), function (thisName, thisValue)
{
value += thisValue;
});
value = trim(value);
if (value)
value = decode(value);
return value === '' ? null : value;
}
// Deletes cookies associated with name
, remove: function (name)
{
var scope = this;
forEachCookie(name, function (thisName, thisValue)
{
scope.write({
name: thisName,
value: '',
expireDate: new Date(0)
});
});
}
};
})();
// The basic funcions for interaction with either localStorage or sessionStorage
var domStorage = {
set: function (config, object)
{
var name, value;
for (name in config)
{
if (!hasProperty.call(config, name)) continue;
value = config[name];
value = encode(value, false);
object.setItem(name, value);
}
}
, get: function (name, object)
{
var result = object.getItem(name);
if (result)
result = decode(result);
return result;
}
};
// Assemble our object
var domStore = {
cookie: cookie
, prefix: location.host
};
function makeStorageObject(key, object)
{
// These functions decide between DOMStorage and cookies, depending on browser support
this[key] = {
storage: object && isFn(object.setItem) && isFn(object.getItem) ? object : null
, prefix: getName(domStore.prefix, key)
// Arguments accepted here are:
// (string) name, (mixed) value
// or
// (object) config with key value pairs that match the name, value args above
, set: function ()
{
var config = getConfig(arguments),
storage = this.storage;
if (storage)
domStorage.set(config, storage);
else
cookie.set(config, this.prefix);
}
// Again, values come back JSON decoded (if the browser supports it)
// load json2.js to make sure older browsers support this feature.
, get: function (name)
{
var storage = this.storage;
if (storage)
return domStorage.get(name, storage);
else
return cookie.get(name, this.prefix);
}
};
}
// Make sure we don't get any errors trying to access these objects
var local = null, session = null;
try
{
local = localStorage;
session = sessionStorage;
}
catch (e) { }
makeStorageObject.call(domStore, "local", local);
makeStorageObject.call(domStore, "session", session);
// Export our object
this.domStore = domStore;
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment