shelf.js
Version:
A modular, powerful wrapper library for persistent objects in the browser and Node.js
318 lines (263 loc) • 8.84 kB
JavaScript
/**
* ## Cookie storage for Shelf.js
* Copyright 2014 Stefano Balietti
*
* Original library from:
* See http://code.google.com/p/cookies/
*/
(function(exports) {
var store = exports.store;
if (!store) {
throw new Error('cookie.shelf.js: shelf.js core not found.');
}
if ('undefined' === typeof window) {
throw new Error('cookie.shelf.js: window object not found.');
}
var cookie = (function() {
var resolveOptions, assembleOptionsString, parseCookies, constructor;
var defaultOptions = {
expiresAt: null,
path: '/',
domain: null,
secure: false
};
/**
* resolveOptions - receive an options object and ensure all options
* are present and valid, replacing with defaults where necessary
*
* @access private
* @static
* @parameter Object options - optional options to start with
* @return Object complete and valid options object
*/
resolveOptions = function(options){
var returnValue, expireDate;
if(typeof options !== 'object' || options === null){
returnValue = defaultOptions;
}
else {
returnValue = {
expiresAt: defaultOptions.expiresAt,
path: defaultOptions.path,
domain: defaultOptions.domain,
secure: defaultOptions.secure
};
if (typeof options.expiresAt === 'object' && options.expiresAt instanceof Date) {
returnValue.expiresAt = options.expiresAt;
}
else if (typeof options.hoursToLive === 'number' && options.hoursToLive !== 0){
expireDate = new Date();
expireDate.setTime(expireDate.getTime() + (options.hoursToLive * 60 * 60 * 1000));
returnValue.expiresAt = expireDate;
}
if (typeof options.path === 'string' && options.path !== '') {
returnValue.path = options.path;
}
if (typeof options.domain === 'string' && options.domain !== '') {
returnValue.domain = options.domain;
}
if (options.secure === true) {
returnValue.secure = options.secure;
}
}
return returnValue;
};
/**
* assembleOptionsString - analyze options and assemble appropriate string for setting a cookie with those options
*
* @access private
* @static
* @parameter options OBJECT - optional options to start with
* @return STRING - complete and valid cookie setting options
*/
assembleOptionsString = function (options) {
options = resolveOptions(options);
return (
(typeof options.expiresAt === 'object' && options.expiresAt instanceof Date ? '; expires=' + options.expiresAt.toGMTString() : '') +
'; path=' + options.path +
(typeof options.domain === 'string' ? '; domain=' + options.domain : '') +
(options.secure === true ? '; secure' : '')
);
};
/**
* parseCookies - retrieve document.cookie string and break it into a hash with values decoded and unserialized
*
* @access private
* @static
* @return OBJECT - hash of cookies from document.cookie
*/
parseCookies = function() {
var cookies = {}, i, pair, name, value, separated = document.cookie.split(';'), unparsedValue;
for(i = 0; i < separated.length; i = i + 1){
pair = separated[i].split('=');
name = pair[0].replace(/^\s*/, '').replace(/\s*$/, '');
try {
value = decodeURIComponent(pair[1]);
}
catch(e1) {
value = pair[1];
}
// if (JSON && 'object' === typeof JSON && 'function' === typeof JSON.parse) {
// try {
// unparsedValue = value;
// value = JSON.parse(value);
// }
// catch (e2) {
// value = unparsedValue;
// }
// }
cookies[name] = store.parse(value);
}
return cookies;
};
constructor = function(){};
/**
* get - get one, several, or all cookies
*
* @access public
* @paramater Mixed cookieName - String:name of single cookie; Array:list of multiple cookie names; Void (no param):if you want all cookies
* @return Mixed - Value of cookie as set; Null:if only one cookie is requested and is not found; Object:hash of multiple or all cookies (if multiple or all requested);
*/
constructor.prototype.get = function(cookieName) {
var returnValue, item, cookies = parseCookies();
if(typeof cookieName === 'string') {
returnValue = (typeof cookies[cookieName] !== 'undefined') ? cookies[cookieName] : null;
}
else if (typeof cookieName === 'object' && cookieName !== null) {
returnValue = {};
for (item in cookieName) {
if (typeof cookies[cookieName[item]] !== 'undefined') {
returnValue[cookieName[item]] = cookies[cookieName[item]];
}
else {
returnValue[cookieName[item]] = null;
}
}
}
else {
returnValue = cookies;
}
return returnValue;
};
/**
* filter - get array of cookies whose names match the provided RegExp
*
* @access public
* @paramater Object RegExp - The regular expression to match against cookie names
* @return Mixed - Object:hash of cookies whose names match the RegExp
*/
constructor.prototype.filter = function (cookieNameRegExp) {
var cookieName, returnValue = {}, cookies = parseCookies();
if (typeof cookieNameRegExp === 'string') {
cookieNameRegExp = new RegExp(cookieNameRegExp);
}
for (cookieName in cookies) {
if (cookieName.match(cookieNameRegExp)) {
returnValue[cookieName] = cookies[cookieName];
}
}
return returnValue;
};
/**
* set - set or delete a cookie with desired options
*
* @access public
* @paramater String cookieName - name of cookie to set
* @paramater Mixed value - Any JS value. If not a string, will be JSON encoded; NULL to delete
* @paramater Object options - optional list of cookie options to specify
* @return void
*/
constructor.prototype.set = function(cookieName, value, options){
if (typeof options !== 'object' || options === null) {
options = {};
}
if (typeof value === 'undefined' || value === null) {
value = '';
options.hoursToLive = -8760;
}
else if (typeof value !== 'string'){
// if(typeof JSON === 'object' && JSON !== null && typeof store.stringify === 'function') {
//
// value = JSON.stringify(value);
// }
// else {
// throw new Error('cookies.set() received non-string value and could not serialize.');
// }
value = store.stringify(value);
}
var optionsString = assembleOptionsString(options);
document.cookie = cookieName + '=' + encodeURIComponent(value) + optionsString;
};
/**
* del - delete a cookie (domain and path options must match those with which the cookie was set; this is really an alias for set() with parameters simplified for this use)
*
* @access public
* @paramater MIxed cookieName - String name of cookie to delete, or Bool true to delete all
* @paramater Object options - optional list of cookie options to specify (path, domain)
* @return void
*/
constructor.prototype.del = function(cookieName, options) {
var allCookies = {}, name;
if(typeof options !== 'object' || options === null) {
options = {};
}
if(typeof cookieName === 'boolean' && cookieName === true) {
allCookies = this.get();
}
else if(typeof cookieName === 'string') {
allCookies[cookieName] = true;
}
for(name in allCookies) {
if(typeof name === 'string' && name !== '') {
this.set(name, null, options);
}
}
};
/**
* test - test whether the browser is accepting cookies
*
* @access public
* @return Boolean
*/
constructor.prototype.test = function() {
var returnValue = false, testName = 'cT', testValue = 'data';
this.set(testName, testValue);
if(this.get(testName) === testValue) {
this.del(testName);
returnValue = true;
}
return returnValue;
};
/**
* setOptions - set default options for calls to cookie methods
*
* @access public
* @param Object options - list of cookie options to specify
* @return void
*/
constructor.prototype.setOptions = function(options) {
if(typeof options !== 'object') {
options = null;
}
defaultOptions = resolveOptions(options);
};
return new constructor();
})();
// if cookies are supported by the browser
if (cookie.test()) {
store.addType("cookie", function(key, value, options) {
if ('undefined' === typeof key) {
return cookie.get();
}
if ('undefined' === typeof value) {
return cookie.get(key);
}
// Set to NULL means delete
if (value === null) {
cookie.del(key);
return null;
}
return cookie.set(key, value, options);
});
}
}(this));