Created
January 11, 2013 15:02
-
-
Save rfessler/4511299 to your computer and use it in GitHub Desktop.
storageExample using json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.rwb1 {background-color: red;} | |
.rwb2 {background-color: yellow;} | |
#container { | |
width: 200px; | |
height: 200px; | |
padding: 10px; | |
margin: 0 auto; | |
text-align: center; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<html lang="en-US"> | |
<head> | |
<meta charset="UTF-8"> | |
<title> | |
</title> | |
<link rel="stylesheet" href="a.css"> | |
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js?v1.7.2" type="text/javascript"> </script> | |
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.23/jquery-ui.min.js?v1.8.23" type="text/javascript"> </script> | |
<script src="jquery/jquery-jstorage.js" type="text/javascript"></script> | |
<script src="a.js" type="text/javascript"></script> | |
</head> | |
<body> | |
<div id="container" > | |
<p>click on this box to do work i.e., turn color to red & remove this text.</p> | |
</div> | |
<hr> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var jsonObj; | |
$(document).ready(function(ready) { | |
$selection = $('#container'); | |
$selection.addClass('rwb2'); // red | |
// stringify selector | |
jsonObj = JSON.stringify($('#container')); | |
// place selector in storage | |
$.jStorage.set('currentpageselector', jsonObj) | |
$('#container').on('click', function(el){ | |
_this = $(this); | |
// get selector string out of storage | |
var jsonStr = $.jStorage.get('currentpageselector'); | |
// parse the selector string | |
var obj = $.parseJSON(jsonStr); | |
// create the jquery object | |
var _selector = $(obj.selector); | |
// do work i.e., addclass/removeClass | |
_selector.addClass('rwb1').removeClass('rwb2'); | |
_selector.text('Done!!'); | |
}); | |
}); | |
/** | |
* just extra original code | |
* @type {Object} | |
* =============================== | |
var myObj = { | |
level_one: { | |
level_two: { | |
key: 'val' | |
}, | |
level_two_too: { | |
level_three: { | |
key: 'val' | |
} | |
} | |
}, | |
level_one_too: { | |
key: 'val' | |
} | |
}; | |
$('#container').removeClass('rwb1'); | |
str = JSON.stringify(myObj); | |
$('#container').text(str); | |
console.log('string'); | |
console.log(str); | |
console.log('object'); | |
console.log($.parseJSON(str)); | |
// var obj = $.parseJSON(jsonObj); | |
// var _this = $(obj.selector); | |
// _this.addClass('rwb2'); | |
// or | |
// var obj = $.parseJSON(JSON.stringify($('#container'))); | |
// var _this = $(obj.selector); | |
// _this.addClass('rwb2') ; | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ----------------------------- JSTORAGE ------------------------------------- | |
* Simple local storage wrapper to save data on the browser side, supporting | |
* all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+ | |
* | |
* Copyright (c) 2010 - 2012 Andris Reinman, [email protected] | |
* Project homepage: www.jstorage.info | |
* | |
* Licensed under MIT-style license: | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
*/ | |
(function () { | |
var | |
/* jStorage version */ | |
JSTORAGE_VERSION = "0.3.1", | |
/* detect a dollar object or create one if not found */ | |
$ = window.jQuery || window.$ || (window.$ = {}), | |
/* check for a JSON handling support */ | |
JSON = { | |
parse: | |
window.JSON && (window.JSON.parse || window.JSON.decode) || | |
String.prototype.evalJSON && function (str) { return String(str).evalJSON(); } || | |
$.parseJSON || | |
$.evalJSON, | |
stringify: | |
Object.toJSON || | |
window.JSON && (window.JSON.stringify || window.JSON.encode) || | |
$.toJSON | |
}; | |
// Break if no JSON support was found | |
if (!JSON.parse || !JSON.stringify) { | |
throw new Error("No JSON support found, include //cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js to page"); | |
} | |
var | |
/* This is the object, that holds the cached values */ | |
_storage = {}, | |
/* Actual browser storage (localStorage or globalStorage['domain']) */ | |
_storage_service = { jStorage: "{}" }, | |
/* DOM element for older IE versions, holds userData behavior */ | |
_storage_elm = null, | |
/* How much space does the storage take */ | |
_storage_size = 0, | |
/* which backend is currently used */ | |
_backend = false, | |
/* onchange observers */ | |
_observers = {}, | |
/* timeout to wait after onchange event */ | |
_observer_timeout = false, | |
/* last update time */ | |
_observer_update = 0, | |
/* pubsub observers */ | |
_pubsub_observers = {}, | |
/* skip published items older than current timestamp */ | |
_pubsub_last = +new Date(), | |
/* Next check for TTL */ | |
_ttl_timeout, | |
/** | |
* XML encoding and decoding as XML nodes can't be JSON'ized | |
* XML nodes are encoded and decoded if the node is the value to be saved | |
* but not if it's as a property of another object | |
* Eg. - | |
* $.jStorage.set("key", xmlNode); // IS OK | |
* $.jStorage.set("key", {xml: xmlNode}); // NOT OK | |
*/ | |
_XMLService = { | |
/** | |
* Validates a XML node to be XML | |
* based on jQuery.isXML function | |
*/ | |
isXML: function (elm) { | |
var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement; | |
return documentElement ? documentElement.nodeName !== "HTML" : false; | |
}, | |
/** | |
* Encodes a XML node to string | |
* based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/ | |
*/ | |
encode: function (xmlNode) { | |
if (!this.isXML(xmlNode)) { | |
return false; | |
} | |
try { // Mozilla, Webkit, Opera | |
return new XMLSerializer().serializeToString(xmlNode); | |
} catch (E1) { | |
try { // IE | |
return xmlNode.xml; | |
} catch (E2) { } | |
} | |
return false; | |
}, | |
/** | |
* Decodes a XML node from string | |
* loosely based on http://outwestmedia.com/jquery-plugins/xmldom/ | |
*/ | |
decode: function (xmlString) { | |
var dom_parser = ("DOMParser" in window && (new DOMParser()).parseFromString) || | |
(window.ActiveXObject && function (_xmlString) { | |
var xml_doc = new ActiveXObject('Microsoft.XMLDOM'); | |
xml_doc.async = 'false'; | |
xml_doc.loadXML(_xmlString); | |
return xml_doc; | |
}), | |
resultXML; | |
if (!dom_parser) { | |
return false; | |
} | |
resultXML = dom_parser.call("DOMParser" in window && (new DOMParser()) || window, xmlString, 'text/xml'); | |
return this.isXML(resultXML) ? resultXML : false; | |
} | |
}, | |
_localStoragePolyfillSetKey = function () { }; | |
////////////////////////// PRIVATE METHODS //////////////////////// | |
/** | |
* Initialization function. Detects if the browser supports DOM Storage | |
* or userData behavior and behaves accordingly. | |
*/ | |
function _init() { | |
/* Check if browser supports localStorage */ | |
var localStorageReallyWorks = false; | |
if ("localStorage" in window) { | |
try { | |
window.localStorage.setItem('_tmptest', 'tmpval'); | |
localStorageReallyWorks = true; | |
window.localStorage.removeItem('_tmptest'); | |
} catch (BogusQuotaExceededErrorOnIos5) { | |
// Thanks be to iOS5 Private Browsing mode which throws | |
// QUOTA_EXCEEDED_ERRROR DOM Exception 22. | |
} | |
} | |
if (localStorageReallyWorks) { | |
try { | |
if (window.localStorage) { | |
_storage_service = window.localStorage; | |
_backend = "localStorage"; | |
_observer_update = _storage_service.jStorage_update; | |
} | |
} catch (E3) { /* Firefox fails when touching localStorage and cookies are disabled */ } | |
} | |
/* Check if browser supports globalStorage */ | |
else if ("globalStorage" in window) { | |
try { | |
if (window.globalStorage) { | |
_storage_service = window.globalStorage[window.location.hostname]; | |
_backend = "globalStorage"; | |
_observer_update = _storage_service.jStorage_update; | |
} | |
} catch (E4) { /* Firefox fails when touching localStorage and cookies are disabled */ } | |
} | |
/* Check if browser supports userData behavior */ | |
else { | |
_storage_elm = document.createElement('link'); | |
if (_storage_elm.addBehavior) { | |
/* Use a DOM element to act as userData storage */ | |
_storage_elm.style.behavior = 'url(#default#userData)'; | |
/* userData element needs to be inserted into the DOM! */ | |
document.getElementsByTagName('head')[0].appendChild(_storage_elm); | |
try { | |
_storage_elm.load("jStorage"); | |
} catch (E) { | |
// try to reset cache | |
_storage_elm.setAttribute("jStorage", "{}"); | |
_storage_elm.save("jStorage"); | |
_storage_elm.load("jStorage"); | |
} | |
var data = "{}"; | |
try { | |
data = _storage_elm.getAttribute("jStorage"); | |
} catch (E5) { } | |
try { | |
_observer_update = _storage_elm.getAttribute("jStorage_update"); | |
} catch (E6) { } | |
_storage_service.jStorage = data; | |
_backend = "userDataBehavior"; | |
} else { | |
_storage_elm = null; | |
return; | |
} | |
} | |
// Load data from storage | |
_load_storage(); | |
// remove dead keys | |
_handleTTL(); | |
// create localStorage and sessionStorage polyfills if needed | |
_createPolyfillStorage("local"); | |
_createPolyfillStorage("session"); | |
// start listening for changes | |
_setupObserver(); | |
// initialize publish-subscribe service | |
_handlePubSub(); | |
// handle cached navigation | |
if ("addEventListener" in window) { | |
window.addEventListener("pageshow", function (event) { | |
if (event.persisted) { | |
_storageObserver(); | |
} | |
}, false); | |
} | |
} | |
/** | |
* Create a polyfill for localStorage (type="local") or sessionStorage (type="session") | |
* | |
* @param {String} type Either "local" or "session" | |
* @param {Boolean} forceCreate If set to true, recreate the polyfill (needed with flush) | |
*/ | |
function _createPolyfillStorage(type, forceCreate) { | |
var _skipSave = false, | |
_length = 0, | |
i, | |
storage, | |
storage_source = {}; | |
var rand = Math.random(); | |
if (!forceCreate && typeof window[type + "Storage"] != "undefined") { | |
return; | |
} | |
// Use globalStorage for localStorage if available | |
if (type == "local" && window.globalStorage) { | |
localStorage = window.globalStorage[window.location.hostname]; | |
return; | |
} | |
// only IE6/7 from this point on | |
if (_backend != "userDataBehavior") { | |
return; | |
} | |
// Remove existing storage element if available | |
if (forceCreate && window[type + "Storage"] && window[type + "Storage"].parentNode) { | |
window[type + "Storage"].parentNode.removeChild(window[type + "Storage"]); | |
} | |
storage = document.createElement("button"); | |
document.getElementsByTagName('head')[0].appendChild(storage); | |
if (type == "local") { | |
storage_source = _storage; | |
} else if (type == "session") { | |
_sessionStoragePolyfillUpdate(); | |
} | |
for (i in storage_source) { | |
if (storage_source.hasOwnProperty(i) && i != "__jstorage_meta" && i != "length" && typeof storage_source[i] != "undefined") { | |
if (!(i in storage)) { | |
_length++; | |
} | |
storage[i] = storage_source[i]; | |
} | |
} | |
// Polyfill API | |
/** | |
* Indicates how many keys are stored in the storage | |
*/ | |
storage.length = _length; | |
/** | |
* Returns the key of the nth stored value | |
* | |
* @param {Number} n Index position | |
* @return {String} Key name of the nth stored value | |
*/ | |
storage.key = function (n) { | |
var count = 0, i; | |
_sessionStoragePolyfillUpdate(); | |
for (i in storage_source) { | |
if (storage_source.hasOwnProperty(i) && i != "__jstorage_meta" && i != "length" && typeof storage_source[i] != "undefined") { | |
if (count == n) { | |
return i; | |
} | |
count++; | |
} | |
} | |
} | |
/** | |
* Returns the current value associated with the given key | |
* | |
* @param {String} key key name | |
* @return {Mixed} Stored value | |
*/ | |
storage.getItem = function (key) { | |
_sessionStoragePolyfillUpdate(); | |
if (type == "session") { | |
return storage_source[key]; | |
} | |
return $.jStorage.get(key); | |
} | |
/** | |
* Sets or updates value for a give key | |
* | |
* @param {String} key Key name to be updated | |
* @param {String} value String value to be stored | |
*/ | |
storage.setItem = function (key, value) { | |
if (typeof value == "undefined") { | |
return; | |
} | |
storage[key] = (value || "").toString(); | |
} | |
/** | |
* Removes key from the storage | |
* | |
* @param {String} key Key name to be removed | |
*/ | |
storage.removeItem = function (key) { | |
if (type == "local") { | |
return $.jStorage.deleteKey(key); | |
} | |
storage[key] = undefined; | |
_skipSave = true; | |
if (key in storage) { | |
storage.removeAttribute(key); | |
} | |
_skipSave = false; | |
} | |
/** | |
* Clear storage | |
*/ | |
storage.clear = function () { | |
if (type == "session") { | |
window.name = ""; | |
_createPolyfillStorage("session", true); | |
return; | |
} | |
$.jStorage.flush(); | |
} | |
if (type == "local") { | |
_localStoragePolyfillSetKey = function (key, value) { | |
if (key == "length") { | |
return; | |
} | |
_skipSave = true; | |
if (typeof value == "undefined") { | |
if (key in storage) { | |
_length--; | |
storage.removeAttribute(key); | |
} | |
} else { | |
if (!(key in storage)) { | |
_length++; | |
} | |
storage[key] = (value || "").toString(); | |
} | |
storage.length = _length; | |
_skipSave = false; | |
} | |
} | |
function _sessionStoragePolyfillUpdate() { | |
if (type != "session") { | |
return; | |
} | |
try { | |
storage_source = JSON.parse(window.name || "{}"); | |
} catch (E) { | |
storage_source = {}; | |
} | |
} | |
function _sessionStoragePolyfillSave() { | |
if (type != "session") { | |
return; | |
} | |
window.name = JSON.stringify(storage_source); | |
}; | |
storage.attachEvent("onpropertychange", function (e) { | |
if (e.propertyName == "length") { | |
return; | |
} | |
if (_skipSave || e.propertyName == "length") { | |
return; | |
} | |
if (type == "local") { | |
if (!(e.propertyName in storage_source) && typeof storage[e.propertyName] != "undefined") { | |
_length++; | |
} | |
} else if (type == "session") { | |
_sessionStoragePolyfillUpdate(); | |
if (typeof storage[e.propertyName] != "undefined" && !(e.propertyName in storage_source)) { | |
storage_source[e.propertyName] = storage[e.propertyName]; | |
_length++; | |
} else if (typeof storage[e.propertyName] == "undefined" && e.propertyName in storage_source) { | |
delete storage_source[e.propertyName]; | |
_length--; | |
} else { | |
storage_source[e.propertyName] = storage[e.propertyName]; | |
} | |
_sessionStoragePolyfillSave(); | |
storage.length = _length; | |
return; | |
} | |
$.jStorage.set(e.propertyName, storage[e.propertyName]); | |
storage.length = _length; | |
}); | |
window[type + "Storage"] = storage; | |
} | |
/** | |
* Reload data from storage when needed | |
*/ | |
function _reloadData() { | |
var data = "{}"; | |
if (_backend == "userDataBehavior") { | |
_storage_elm.load("jStorage"); | |
try { | |
data = _storage_elm.getAttribute("jStorage"); | |
} catch (E5) { } | |
try { | |
_observer_update = _storage_elm.getAttribute("jStorage_update"); | |
} catch (E6) { } | |
_storage_service.jStorage = data; | |
} | |
_load_storage(); | |
// remove dead keys | |
_handleTTL(); | |
_handlePubSub(); | |
} | |
/** | |
* Sets up a storage change observer | |
*/ | |
function _setupObserver() { | |
if (_backend == "localStorage" || _backend == "globalStorage") { | |
if ("addEventListener" in window) { | |
window.addEventListener("storage", _storageObserver, false); | |
} else { | |
document.attachEvent("onstorage", _storageObserver); | |
} | |
} else if (_backend == "userDataBehavior") { | |
setInterval(_storageObserver, 1000); | |
} | |
} | |
/** | |
* Fired on any kind of data change, needs to check if anything has | |
* really been changed | |
*/ | |
function _storageObserver() { | |
var updateTime; | |
// cumulate change notifications with timeout | |
clearTimeout(_observer_timeout); | |
_observer_timeout = setTimeout(function () { | |
if (_backend == "localStorage" || _backend == "globalStorage") { | |
updateTime = _storage_service.jStorage_update; | |
} else if (_backend == "userDataBehavior") { | |
_storage_elm.load("jStorage"); | |
try { | |
updateTime = _storage_elm.getAttribute("jStorage_update"); | |
} catch (E5) { } | |
} | |
if (updateTime && updateTime != _observer_update) { | |
_observer_update = updateTime; | |
_checkUpdatedKeys(); | |
} | |
}, 25); | |
} | |
/** | |
* Reloads the data and checks if any keys are changed | |
*/ | |
function _checkUpdatedKeys() { | |
var oldCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)), | |
newCrc32List; | |
_reloadData(); | |
newCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)); | |
var key, | |
updated = [], | |
removed = []; | |
for (key in oldCrc32List) { | |
if (oldCrc32List.hasOwnProperty(key)) { | |
if (!newCrc32List[key]) { | |
removed.push(key); | |
continue; | |
} | |
if (oldCrc32List[key] != newCrc32List[key] && String(oldCrc32List[key]).substr(0, 2) == "2.") { | |
updated.push(key); | |
} | |
} | |
} | |
for (key in newCrc32List) { | |
if (newCrc32List.hasOwnProperty(key)) { | |
if (!oldCrc32List[key]) { | |
updated.push(key); | |
} | |
} | |
} | |
_fireObservers(updated, "updated"); | |
_fireObservers(removed, "deleted"); | |
} | |
/** | |
* Fires observers for updated keys | |
* | |
* @param {Array|String} keys Array of key names or a key | |
* @param {String} action What happened with the value (updated, deleted, flushed) | |
*/ | |
function _fireObservers(keys, action) { | |
keys = [].concat(keys || []); | |
if (action == "flushed") { | |
keys = []; | |
for (var key in _observers) { | |
if (_observers.hasOwnProperty(key)) { | |
keys.push(key); | |
} | |
} | |
action = "deleted"; | |
} | |
for (var i = 0, len = keys.length; i < len; i++) { | |
if (_observers[keys[i]]) { | |
for (var j = 0, jlen = _observers[keys[i]].length; j < jlen; j++) { | |
_observers[keys[i]][j](keys[i], action); | |
} | |
} | |
} | |
} | |
/** | |
* Publishes key change to listeners | |
*/ | |
function _publishChange() { | |
var updateTime = (+new Date()).toString(); | |
if (_backend == "localStorage" || _backend == "globalStorage") { | |
_storage_service.jStorage_update = updateTime; | |
} else if (_backend == "userDataBehavior") { | |
_storage_elm.setAttribute("jStorage_update", updateTime); | |
_storage_elm.save("jStorage"); | |
} | |
_storageObserver(); | |
} | |
/** | |
* Loads the data from the storage based on the supported mechanism | |
*/ | |
function _load_storage() { | |
/* if jStorage string is retrieved, then decode it */ | |
if (_storage_service.jStorage) { | |
try { | |
_storage = JSON.parse(String(_storage_service.jStorage)); | |
} catch (E6) { _storage_service.jStorage = "{}"; } | |
} else { | |
_storage_service.jStorage = "{}"; | |
} | |
_storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0; | |
if (!_storage.__jstorage_meta) { | |
_storage.__jstorage_meta = {}; | |
} | |
if (!_storage.__jstorage_meta.CRC32) { | |
_storage.__jstorage_meta.CRC32 = {}; | |
} | |
} | |
/** | |
* This functions provides the "save" mechanism to store the jStorage object | |
*/ | |
function _save() { | |
_dropOldEvents(); // remove expired events | |
try { | |
_storage_service.jStorage = JSON.stringify(_storage); | |
// If userData is used as the storage engine, additional | |
if (_storage_elm) { | |
_storage_elm.setAttribute("jStorage", _storage_service.jStorage); | |
_storage_elm.save("jStorage"); | |
} | |
_storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0; | |
} catch (E7) { /* probably cache is full, nothing is saved this way*/ } | |
} | |
/** | |
* Function checks if a key is set and is string or numberic | |
* | |
* @param {String} key Key name | |
*/ | |
function _checkKey(key) { | |
if (!key || (typeof key != "string" && typeof key != "number")) { | |
throw new TypeError('Key name must be string or numeric'); | |
} | |
if (key == "__jstorage_meta") { | |
throw new TypeError('Reserved key name'); | |
} | |
return true; | |
} | |
/** | |
* Removes expired keys | |
*/ | |
function _handleTTL() { | |
var curtime, i, TTL, CRC32, nextExpire = Infinity, changed = false, deleted = []; | |
clearTimeout(_ttl_timeout); | |
if (!_storage.__jstorage_meta || typeof _storage.__jstorage_meta.TTL != "object") { | |
// nothing to do here | |
return; | |
} | |
curtime = +new Date(); | |
TTL = _storage.__jstorage_meta.TTL; | |
CRC32 = _storage.__jstorage_meta.CRC32; | |
for (i in TTL) { | |
if (TTL.hasOwnProperty(i)) { | |
if (TTL[i] <= curtime) { | |
delete TTL[i]; | |
delete CRC32[i]; | |
delete _storage[i]; | |
changed = true; | |
deleted.push(i); | |
} else if (TTL[i] < nextExpire) { | |
nextExpire = TTL[i]; | |
} | |
} | |
} | |
// set next check | |
if (nextExpire != Infinity) { | |
_ttl_timeout = setTimeout(_handleTTL, nextExpire - curtime); | |
} | |
// save changes | |
if (changed) { | |
_save(); | |
_publishChange(); | |
_fireObservers(deleted, "deleted"); | |
} | |
} | |
/** | |
* Checks if there's any events on hold to be fired to listeners | |
*/ | |
function _handlePubSub() { | |
if (!_storage.__jstorage_meta.PubSub) { | |
return; | |
} | |
var pubelm, | |
_pubsubCurrent = _pubsub_last; | |
for (var i = len = _storage.__jstorage_meta.PubSub.length - 1; i >= 0; i--) { | |
pubelm = _storage.__jstorage_meta.PubSub[i]; | |
if (pubelm[0] > _pubsub_last) { | |
_pubsubCurrent = pubelm[0]; | |
_fireSubscribers(pubelm[1], pubelm[2]); | |
} | |
} | |
_pubsub_last = _pubsubCurrent; | |
} | |
/** | |
* Fires all subscriber listeners for a pubsub channel | |
* | |
* @param {String} channel Channel name | |
* @param {Mixed} payload Payload data to deliver | |
*/ | |
function _fireSubscribers(channel, payload) { | |
if (_pubsub_observers[channel]) { | |
for (var i = 0, len = _pubsub_observers[channel].length; i < len; i++) { | |
// send immutable data that can't be modified by listeners | |
_pubsub_observers[channel][i](channel, JSON.parse(JSON.stringify(payload))); | |
} | |
} | |
} | |
/** | |
* Remove old events from the publish stream (at least 2sec old) | |
*/ | |
function _dropOldEvents() { | |
if (!_storage.__jstorage_meta.PubSub) { | |
return; | |
} | |
var retire = +new Date() - 2000; | |
for (var i = 0, len = _storage.__jstorage_meta.PubSub.length; i < len; i++) { | |
if (_storage.__jstorage_meta.PubSub[i][0] <= retire) { | |
// deleteCount is needed for IE6 | |
_storage.__jstorage_meta.PubSub.splice(i, _storage.__jstorage_meta.PubSub.length - i); | |
break; | |
} | |
} | |
if (!_storage.__jstorage_meta.PubSub.length) { | |
delete _storage.__jstorage_meta.PubSub; | |
} | |
} | |
/** | |
* Publish payload to a channel | |
* | |
* @param {String} channel Channel name | |
* @param {Mixed} payload Payload to send to the subscribers | |
*/ | |
function _publish(channel, payload) { | |
if (!_storage.__jstorage_meta) { | |
_storage.__jstorage_meta = {}; | |
} | |
if (!_storage.__jstorage_meta.PubSub) { | |
_storage.__jstorage_meta.PubSub = []; | |
} | |
_storage.__jstorage_meta.PubSub.unshift([+new Date, channel, payload]); | |
_save(); | |
_publishChange(); | |
} | |
/** | |
* JS Implementation of MurmurHash2 | |
* | |
* SOURCE: https://github.com/garycourt/murmurhash-js (MIT licensed) | |
* | |
* @author <a href="mailto:[email protected]">Gary Court</a> | |
* @see http://github.com/garycourt/murmurhash-js | |
* @author <a href="mailto:[email protected]">Austin Appleby</a> | |
* @see http://sites.google.com/site/murmurhash/ | |
* | |
* @param {string} str ASCII only | |
* @param {number} seed Positive integer only | |
* @return {number} 32-bit positive integer hash | |
*/ | |
function murmurhash2_32_gc(str, seed) { | |
var | |
l = str.length, | |
h = seed ^ l, | |
i = 0, | |
k; | |
while (l >= 4) { | |
k = | |
((str.charCodeAt(i) & 0xff)) | | |
((str.charCodeAt(++i) & 0xff) << 8) | | |
((str.charCodeAt(++i) & 0xff) << 16) | | |
((str.charCodeAt(++i) & 0xff) << 24); | |
k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16)); | |
k ^= k >>> 24; | |
k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16)); | |
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k; | |
l -= 4; | |
++i; | |
} | |
switch (l) { | |
case 3: h ^= (str.charCodeAt(i + 2) & 0xff) << 16; | |
case 2: h ^= (str.charCodeAt(i + 1) & 0xff) << 8; | |
case 1: h ^= (str.charCodeAt(i) & 0xff); | |
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)); | |
} | |
h ^= h >>> 13; | |
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)); | |
h ^= h >>> 15; | |
return h >>> 0; | |
} | |
////////////////////////// PUBLIC INTERFACE ///////////////////////// | |
$.jStorage = { | |
/* Version number */ | |
version: JSTORAGE_VERSION, | |
/** | |
* Sets a key's value. | |
* | |
* @param {String} key Key to set. If this value is not set or not | |
* a string an exception is raised. | |
* @param {Mixed} value Value to set. This can be any value that is JSON | |
* compatible (Numbers, Strings, Objects etc.). | |
* @param {Object} [options] - possible options to use | |
* @param {Number} [options.TTL] - optional TTL value | |
* @return {Mixed} the used value | |
*/ | |
set: function (key, value, options) { | |
_checkKey(key); | |
options = options || {}; | |
// undefined values are deleted automatically | |
if (typeof value == "undefined") { | |
this.deleteKey(key); | |
return value; | |
} | |
if (_XMLService.isXML(value)) { | |
value = { _is_xml: true, xml: _XMLService.encode(value) }; | |
} else if (typeof value == "function") { | |
return undefined; // functions can't be saved! | |
} else if (value && typeof value == "object") { | |
// clone the object before saving to _storage tree | |
value = JSON.parse(JSON.stringify(value)); | |
} | |
_storage[key] = value; | |
_storage.__jstorage_meta.CRC32[key] = "2." + murmurhash2_32_gc(JSON.stringify(value)); | |
this.setTTL(key, options.TTL || 0); // also handles saving and _publishChange | |
_localStoragePolyfillSetKey(key, value); | |
_fireObservers(key, "updated"); | |
return value; | |
}, | |
/** | |
* Looks up a key in cache | |
* | |
* @param {String} key - Key to look up. | |
* @param {mixed} def - Default value to return, if key didn't exist. | |
* @return {Mixed} the key value, default value or null | |
*/ | |
get: function (key, def) { | |
_checkKey(key); | |
if (key in _storage) { | |
if (_storage[key] && typeof _storage[key] == "object" && _storage[key]._is_xml) { | |
return _XMLService.decode(_storage[key].xml); | |
} else { | |
return _storage[key]; | |
} | |
} | |
return typeof (def) == 'undefined' ? null : def; | |
}, | |
/** | |
* Deletes a key from cache. | |
* | |
* @param {String} key - Key to delete. | |
* @return {Boolean} true if key existed or false if it didn't | |
*/ | |
deleteKey: function (key) { | |
_checkKey(key); | |
if (key in _storage) { | |
delete _storage[key]; | |
// remove from TTL list | |
if (typeof _storage.__jstorage_meta.TTL == "object" && | |
key in _storage.__jstorage_meta.TTL) { | |
delete _storage.__jstorage_meta.TTL[key]; | |
} | |
delete _storage.__jstorage_meta.CRC32[key]; | |
_localStoragePolyfillSetKey(key, undefined); | |
_save(); | |
_publishChange(); | |
_fireObservers(key, "deleted"); | |
return true; | |
} | |
return false; | |
}, | |
/** | |
* Sets a TTL for a key, or remove it if ttl value is 0 or below | |
* | |
* @param {String} key - key to set the TTL for | |
* @param {Number} ttl - TTL timeout in milliseconds | |
* @return {Boolean} true if key existed or false if it didn't | |
*/ | |
setTTL: function (key, ttl) { | |
var curtime = +new Date(); | |
_checkKey(key); | |
ttl = Number(ttl) || 0; | |
if (key in _storage) { | |
if (!_storage.__jstorage_meta.TTL) { | |
_storage.__jstorage_meta.TTL = {}; | |
} | |
// Set TTL value for the key | |
if (ttl > 0) { | |
_storage.__jstorage_meta.TTL[key] = curtime + ttl; | |
} else { | |
delete _storage.__jstorage_meta.TTL[key]; | |
} | |
_save(); | |
_handleTTL(); | |
_publishChange(); | |
return true; | |
} | |
return false; | |
}, | |
/** | |
* Gets remaining TTL (in milliseconds) for a key or 0 when no TTL has been set | |
* | |
* @param {String} key Key to check | |
* @return {Number} Remaining TTL in milliseconds | |
*/ | |
getTTL: function (key) { | |
var curtime = +new Date(), ttl; | |
_checkKey(key); | |
if (key in _storage && _storage.__jstorage_meta.TTL && _storage.__jstorage_meta.TTL[key]) { | |
ttl = _storage.__jstorage_meta.TTL[key] - curtime; | |
return ttl || 0; | |
} | |
return 0; | |
}, | |
/** | |
* Deletes everything in cache. | |
* | |
* @return {Boolean} Always true | |
*/ | |
flush: function () { | |
_storage = { __jstorage_meta: { CRC32: {}} }; | |
_createPolyfillStorage("local", true); | |
_save(); | |
_publishChange(); | |
_fireObservers(null, "flushed"); | |
return true; | |
}, | |
/** | |
* Returns a read-only copy of _storage | |
* | |
* @return {Object} Read-only copy of _storage | |
*/ | |
storageObj: function () { | |
function F() { } | |
F.prototype = _storage; | |
return new F(); | |
}, | |
/** | |
* Returns an index of all used keys as an array | |
* ['key1', 'key2',..'keyN'] | |
* | |
* @return {Array} Used keys | |
*/ | |
index: function () { | |
var index = [], i; | |
for (i in _storage) { | |
if (_storage.hasOwnProperty(i) && i != "__jstorage_meta") { | |
index.push(i); | |
} | |
} | |
return index; | |
}, | |
/** | |
* How much space in bytes does the storage take? | |
* | |
* @return {Number} Storage size in chars (not the same as in bytes, | |
* since some chars may take several bytes) | |
*/ | |
storageSize: function () { | |
return _storage_size; | |
}, | |
/** | |
* Which backend is currently in use? | |
* | |
* @return {String} Backend name | |
*/ | |
currentBackend: function () { | |
return _backend; | |
}, | |
/** | |
* Test if storage is available | |
* | |
* @return {Boolean} True if storage can be used | |
*/ | |
storageAvailable: function () { | |
return !!_backend; | |
}, | |
/** | |
* Register change listeners | |
* | |
* @param {String} key Key name | |
* @param {Function} callback Function to run when the key changes | |
*/ | |
listenKeyChange: function (key, callback) { | |
_checkKey(key); | |
if (!_observers[key]) { | |
_observers[key] = []; | |
} | |
_observers[key].push(callback); | |
}, | |
/** | |
* Remove change listeners | |
* | |
* @param {String} key Key name to unregister listeners against | |
* @param {Function} [callback] If set, unregister the callback, if not - unregister all | |
*/ | |
stopListening: function (key, callback) { | |
_checkKey(key); | |
if (!_observers[key]) { | |
return; | |
} | |
if (!callback) { | |
delete _observers[key]; | |
return; | |
} | |
for (var i = _observers[key].length - 1; i >= 0; i--) { | |
if (_observers[key][i] == callback) { | |
_observers[key].splice(i, 1); | |
} | |
} | |
}, | |
/** | |
* Subscribe to a Publish/Subscribe event stream | |
* | |
* @param {String} channel Channel name | |
* @param {Function} callback Function to run when the something is published to the channel | |
*/ | |
subscribe: function (channel, callback) { | |
channel = (channel || "").toString(); | |
if (!channel) { | |
throw new TypeError('Channel not defined'); | |
} | |
if (!_pubsub_observers[channel]) { | |
_pubsub_observers[channel] = []; | |
} | |
_pubsub_observers[channel].push(callback); | |
}, | |
/** | |
* Publish data to an event stream | |
* | |
* @param {String} channel Channel name | |
* @param {Mixed} payload Payload to deliver | |
*/ | |
publish: function (channel, payload) { | |
channel = (channel || "").toString(); | |
if (!channel) { | |
throw new TypeError('Channel not defined'); | |
} | |
_publish(channel, payload); | |
}, | |
/** | |
* Reloads the data from browser storage | |
*/ | |
reInit: function () { | |
_reloadData(); | |
} | |
}; | |
// Initialize jStorage | |
_init(); | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
{ | |
"folders": | |
[ | |
{ | |
"file_exclude_patterns": | |
[ | |
//"*.sublime-workspace" | |
] | |
}, | |
{ | |
"path": "/C/Users/rfessler/Documents/Dropbox/Projects/storage" | |
} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"auto_complete": | |
{ | |
"selected_items": | |
[ | |
] | |
}, | |
"buffers": | |
[ | |
{ | |
"contents": ".rwb1 {background-color: red;}\n.rwb2 {background-color: yellow;}\n\n#container {\n width: 200px;\n height: 200px;\n padding: 10px;\n margin: 0 auto;\n text-align: center;\n}\n\n\n", | |
"settings": | |
{ | |
"buffer_size": 183, | |
"line_ending": "Windows", | |
"name": "a.css" | |
} | |
}, | |
{ | |
"contents": "<!DOCTYPE HTML>\n<html lang=\"en-US\">\n \n <head>\n <meta charset=\"UTF-8\">\n <title>\n </title>\n <link rel=\"stylesheet\" href=\"a.css\">\n <script src=\"http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js?v1.7.2\" type=\"text/javascript\"> </script>\n <script src=\"http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.23/jquery-ui.min.js?v1.8.23\" type=\"text/javascript\"> </script> \n <script src=\"jquery/jquery-jstorage.js\" type=\"text/javascript\"></script>\n <script src=\"a.js\" type=\"text/javascript\"></script> \n </head>\n \n <body>\n <div id=\"container\" >\n <p>click on this box to do work i.e., turn color to red & remove this text.</p>\n </div>\n <hr>\n\n </body>\n\n</html>\n", | |
"settings": | |
{ | |
"buffer_size": 755, | |
"line_ending": "Windows", | |
"name": "a.html" | |
} | |
}, | |
{ | |
"contents": "var jsonObj;\n\n $(document).ready(function(ready) {\n \n $selection = $('#container');\n $selection.addClass('rwb2'); // red\n\n // stringify selector\n jsonObj = JSON.stringify($('#container'));\n \n // place selector in storage\n $.jStorage.set('currentpageselector', jsonObj)\n\n\n \n $('#container').on('click', function(el){\n _this = $(this);\n\n // get selector string out of storage\n var jsonStr = $.jStorage.get('currentpageselector');\n \n // parse the selector string\n var obj = $.parseJSON(jsonStr);\n\n // create the jquery object \n var _selector = $(obj.selector);\n\n // do work i.e., addclass/removeClass\n _selector.addClass('rwb1').removeClass('rwb2');\n _selector.text('Done!!');\n });\n \n });\n\n\n\n\n\n\n /**\n * just extra original code\n * @type {Object}\n * ===============================\n var myObj = {\n level_one: {\n level_two: {\n key: 'val'\n },\n level_two_too: {\n level_three: {\n key: 'val'\n }\n }\n },\n level_one_too: {\n key: 'val'\n }\n };\n\n $('#container').removeClass('rwb1');\n \n str = JSON.stringify(myObj);\n $('#container').text(str);\n console.log('string');\n console.log(str);\n console.log('object');\n console.log($.parseJSON(str)); \n\n // var obj = $.parseJSON(jsonObj);\n // var _this = $(obj.selector);\n // _this.addClass('rwb2');\n\n // or \n // var obj = $.parseJSON(JSON.stringify($('#container')));\n // var _this = $(obj.selector);\n // _this.addClass('rwb2') ;\n \n */\n", | |
"settings": | |
{ | |
"buffer_size": 1927, | |
"line_ending": "Windows", | |
"name": "a.js" | |
} | |
}, | |
{ | |
"contents": "/*\n* ----------------------------- JSTORAGE -------------------------------------\n* Simple local storage wrapper to save data on the browser side, supporting\n* all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+\n*\n* Copyright (c) 2010 - 2012 Andris Reinman, [email protected]\n* Project homepage: www.jstorage.info\n*\n* Licensed under MIT-style license:\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n(function () {\n var\n /* jStorage version */\n JSTORAGE_VERSION = \"0.3.1\",\n\n /* detect a dollar object or create one if not found */\n $ = window.jQuery || window.$ || (window.$ = {}),\n\n /* check for a JSON handling support */\n JSON = {\n parse:\n window.JSON && (window.JSON.parse || window.JSON.decode) ||\n String.prototype.evalJSON && function (str) { return String(str).evalJSON(); } ||\n $.parseJSON ||\n $.evalJSON,\n stringify:\n Object.toJSON ||\n window.JSON && (window.JSON.stringify || window.JSON.encode) ||\n $.toJSON\n };\n\n // Break if no JSON support was found\n if (!JSON.parse || !JSON.stringify) {\n throw new Error(\"No JSON support found, include //cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js to page\");\n }\n\n var\n /* This is the object, that holds the cached values */\n _storage = {},\n\n /* Actual browser storage (localStorage or globalStorage['domain']) */\n _storage_service = { jStorage: \"{}\" },\n\n /* DOM element for older IE versions, holds userData behavior */\n _storage_elm = null,\n\n /* How much space does the storage take */\n _storage_size = 0,\n\n /* which backend is currently used */\n _backend = false,\n\n /* onchange observers */\n _observers = {},\n\n /* timeout to wait after onchange event */\n _observer_timeout = false,\n\n /* last update time */\n _observer_update = 0,\n\n /* pubsub observers */\n _pubsub_observers = {},\n\n /* skip published items older than current timestamp */\n _pubsub_last = +new Date(),\n\n /* Next check for TTL */\n _ttl_timeout,\n\n /**\n * XML encoding and decoding as XML nodes can't be JSON'ized\n * XML nodes are encoded and decoded if the node is the value to be saved\n * but not if it's as a property of another object\n * Eg. -\n * $.jStorage.set(\"key\", xmlNode); // IS OK\n * $.jStorage.set(\"key\", {xml: xmlNode}); // NOT OK\n */\n _XMLService = {\n /**\n * Validates a XML node to be XML\n * based on jQuery.isXML function\n */\n isXML: function (elm) {\n var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement;\n return documentElement ? documentElement.nodeName !== \"HTML\" : false;\n },\n\n /**\n * Encodes a XML node to string\n * based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/\n */\n encode: function (xmlNode) {\n if (!this.isXML(xmlNode)) {\n return false;\n }\n try { // Mozilla, Webkit, Opera\n return new XMLSerializer().serializeToString(xmlNode);\n } catch (E1) {\n try { // IE\n return xmlNode.xml;\n } catch (E2) { }\n }\n return false;\n },\n\n /**\n * Decodes a XML node from string\n * loosely based on http://outwestmedia.com/jquery-plugins/xmldom/\n */\n decode: function (xmlString) {\n var dom_parser = (\"DOMParser\" in window && (new DOMParser()).parseFromString) ||\n (window.ActiveXObject && function (_xmlString) {\n var xml_doc = new ActiveXObject('Microsoft.XMLDOM');\n xml_doc.async = 'false';\n xml_doc.loadXML(_xmlString);\n return xml_doc;\n }),\n resultXML;\n if (!dom_parser) {\n return false;\n }\n resultXML = dom_parser.call(\"DOMParser\" in window && (new DOMParser()) || window, xmlString, 'text/xml');\n return this.isXML(resultXML) ? resultXML : false;\n }\n },\n\n _localStoragePolyfillSetKey = function () { };\n\n ////////////////////////// PRIVATE METHODS ////////////////////////\n\n /**\n * Initialization function. Detects if the browser supports DOM Storage\n * or userData behavior and behaves accordingly.\n */\n function _init() {\n /* Check if browser supports localStorage */\n var localStorageReallyWorks = false;\n if (\"localStorage\" in window) {\n try {\n window.localStorage.setItem('_tmptest', 'tmpval');\n localStorageReallyWorks = true;\n window.localStorage.removeItem('_tmptest');\n } catch (BogusQuotaExceededErrorOnIos5) {\n // Thanks be to iOS5 Private Browsing mode which throws\n // QUOTA_EXCEEDED_ERRROR DOM Exception 22.\n }\n }\n\n if (localStorageReallyWorks) {\n try {\n if (window.localStorage) {\n _storage_service = window.localStorage;\n _backend = \"localStorage\";\n _observer_update = _storage_service.jStorage_update;\n }\n } catch (E3) { /* Firefox fails when touching localStorage and cookies are disabled */ }\n }\n /* Check if browser supports globalStorage */\n else if (\"globalStorage\" in window) {\n try {\n if (window.globalStorage) {\n _storage_service = window.globalStorage[window.location.hostname];\n _backend = \"globalStorage\";\n _observer_update = _storage_service.jStorage_update;\n }\n } catch (E4) { /* Firefox fails when touching localStorage and cookies are disabled */ }\n }\n /* Check if browser supports userData behavior */\n else {\n _storage_elm = document.createElement('link');\n if (_storage_elm.addBehavior) {\n /* Use a DOM element to act as userData storage */\n _storage_elm.style.behavior = 'url(#default#userData)';\n\n /* userData element needs to be inserted into the DOM! */\n document.getElementsByTagName('head')[0].appendChild(_storage_elm);\n\n try {\n _storage_elm.load(\"jStorage\");\n } catch (E) {\n // try to reset cache\n _storage_elm.setAttribute(\"jStorage\", \"{}\");\n _storage_elm.save(\"jStorage\");\n _storage_elm.load(\"jStorage\");\n }\n\n var data = \"{}\";\n try {\n data = _storage_elm.getAttribute(\"jStorage\");\n } catch (E5) { }\n\n try {\n _observer_update = _storage_elm.getAttribute(\"jStorage_update\");\n } catch (E6) { }\n\n _storage_service.jStorage = data;\n _backend = \"userDataBehavior\";\n } else {\n _storage_elm = null;\n return;\n }\n }\n\n // Load data from storage\n _load_storage();\n\n // remove dead keys\n _handleTTL();\n\n // create localStorage and sessionStorage polyfills if needed\n _createPolyfillStorage(\"local\");\n _createPolyfillStorage(\"session\");\n\n // start listening for changes\n _setupObserver();\n\n // initialize publish-subscribe service\n _handlePubSub();\n\n // handle cached navigation\n if (\"addEventListener\" in window) {\n window.addEventListener(\"pageshow\", function (event) {\n if (event.persisted) {\n _storageObserver();\n }\n }, false);\n }\n }\n\n /**\n * Create a polyfill for localStorage (type=\"local\") or sessionStorage (type=\"session\")\n *\n * @param {String} type Either \"local\" or \"session\"\n * @param {Boolean} forceCreate If set to true, recreate the polyfill (needed with flush)\n */\n function _createPolyfillStorage(type, forceCreate) {\n var _skipSave = false,\n _length = 0,\n i,\n storage,\n storage_source = {};\n\n var rand = Math.random();\n\n if (!forceCreate && typeof window[type + \"Storage\"] != \"undefined\") {\n return;\n }\n\n // Use globalStorage for localStorage if available\n if (type == \"local\" && window.globalStorage) {\n localStorage = window.globalStorage[window.location.hostname];\n return;\n }\n\n // only IE6/7 from this point on\n if (_backend != \"userDataBehavior\") {\n return;\n }\n\n // Remove existing storage element if available\n if (forceCreate && window[type + \"Storage\"] && window[type + \"Storage\"].parentNode) {\n window[type + \"Storage\"].parentNode.removeChild(window[type + \"Storage\"]);\n }\n\n storage = document.createElement(\"button\");\n document.getElementsByTagName('head')[0].appendChild(storage);\n\n if (type == \"local\") {\n storage_source = _storage;\n } else if (type == \"session\") {\n _sessionStoragePolyfillUpdate();\n }\n\n for (i in storage_source) {\n if (storage_source.hasOwnProperty(i) && i != \"__jstorage_meta\" && i != \"length\" && typeof storage_source[i] != \"undefined\") {\n if (!(i in storage)) {\n _length++;\n }\n storage[i] = storage_source[i];\n }\n }\n\n // Polyfill API\n\n /**\n * Indicates how many keys are stored in the storage\n */\n storage.length = _length;\n\n /**\n * Returns the key of the nth stored value\n *\n * @param {Number} n Index position\n * @return {String} Key name of the nth stored value\n */\n storage.key = function (n) {\n var count = 0, i;\n _sessionStoragePolyfillUpdate();\n for (i in storage_source) {\n if (storage_source.hasOwnProperty(i) && i != \"__jstorage_meta\" && i != \"length\" && typeof storage_source[i] != \"undefined\") {\n if (count == n) {\n return i;\n }\n count++;\n }\n }\n }\n\n /**\n * Returns the current value associated with the given key\n *\n * @param {String} key key name\n * @return {Mixed} Stored value\n */\n storage.getItem = function (key) {\n _sessionStoragePolyfillUpdate();\n if (type == \"session\") {\n return storage_source[key];\n }\n return $.jStorage.get(key);\n }\n\n /**\n * Sets or updates value for a give key\n *\n * @param {String} key Key name to be updated\n * @param {String} value String value to be stored\n */\n storage.setItem = function (key, value) {\n if (typeof value == \"undefined\") {\n return;\n }\n storage[key] = (value || \"\").toString();\n }\n\n /**\n * Removes key from the storage\n *\n * @param {String} key Key name to be removed\n */\n storage.removeItem = function (key) {\n if (type == \"local\") {\n return $.jStorage.deleteKey(key);\n }\n\n storage[key] = undefined;\n\n _skipSave = true;\n if (key in storage) {\n storage.removeAttribute(key);\n }\n _skipSave = false;\n }\n\n /**\n * Clear storage\n */\n storage.clear = function () {\n if (type == \"session\") {\n window.name = \"\";\n _createPolyfillStorage(\"session\", true);\n return;\n }\n $.jStorage.flush();\n }\n\n if (type == \"local\") {\n _localStoragePolyfillSetKey = function (key, value) {\n if (key == \"length\") {\n return;\n }\n _skipSave = true;\n if (typeof value == \"undefined\") {\n if (key in storage) {\n _length--;\n storage.removeAttribute(key);\n }\n } else {\n if (!(key in storage)) {\n _length++;\n }\n storage[key] = (value || \"\").toString();\n }\n storage.length = _length;\n _skipSave = false;\n }\n }\n\n function _sessionStoragePolyfillUpdate() {\n if (type != \"session\") {\n return;\n }\n try {\n storage_source = JSON.parse(window.name || \"{}\");\n } catch (E) {\n storage_source = {};\n }\n }\n\n function _sessionStoragePolyfillSave() {\n if (type != \"session\") {\n return;\n }\n window.name = JSON.stringify(storage_source);\n };\n\n storage.attachEvent(\"onpropertychange\", function (e) {\n if (e.propertyName == \"length\") {\n return;\n }\n\n if (_skipSave || e.propertyName == \"length\") {\n return;\n }\n\n if (type == \"local\") {\n if (!(e.propertyName in storage_source) && typeof storage[e.propertyName] != \"undefined\") {\n _length++;\n }\n } else if (type == \"session\") {\n _sessionStoragePolyfillUpdate();\n if (typeof storage[e.propertyName] != \"undefined\" && !(e.propertyName in storage_source)) {\n storage_source[e.propertyName] = storage[e.propertyName];\n _length++;\n } else if (typeof storage[e.propertyName] == \"undefined\" && e.propertyName in storage_source) {\n delete storage_source[e.propertyName];\n _length--;\n } else {\n storage_source[e.propertyName] = storage[e.propertyName];\n }\n\n _sessionStoragePolyfillSave();\n storage.length = _length;\n return;\n }\n\n $.jStorage.set(e.propertyName, storage[e.propertyName]);\n storage.length = _length;\n });\n\n window[type + \"Storage\"] = storage;\n }\n\n /**\n * Reload data from storage when needed\n */\n function _reloadData() {\n var data = \"{}\";\n\n if (_backend == \"userDataBehavior\") {\n _storage_elm.load(\"jStorage\");\n\n try {\n data = _storage_elm.getAttribute(\"jStorage\");\n } catch (E5) { }\n\n try {\n _observer_update = _storage_elm.getAttribute(\"jStorage_update\");\n } catch (E6) { }\n\n _storage_service.jStorage = data;\n }\n\n _load_storage();\n\n // remove dead keys\n _handleTTL();\n\n _handlePubSub();\n }\n\n /**\n * Sets up a storage change observer\n */\n function _setupObserver() {\n if (_backend == \"localStorage\" || _backend == \"globalStorage\") {\n if (\"addEventListener\" in window) {\n window.addEventListener(\"storage\", _storageObserver, false);\n } else {\n document.attachEvent(\"onstorage\", _storageObserver);\n }\n } else if (_backend == \"userDataBehavior\") {\n setInterval(_storageObserver, 1000);\n }\n }\n\n /**\n * Fired on any kind of data change, needs to check if anything has\n * really been changed\n */\n function _storageObserver() {\n var updateTime;\n // cumulate change notifications with timeout\n clearTimeout(_observer_timeout);\n _observer_timeout = setTimeout(function () {\n if (_backend == \"localStorage\" || _backend == \"globalStorage\") {\n updateTime = _storage_service.jStorage_update;\n } else if (_backend == \"userDataBehavior\") {\n _storage_elm.load(\"jStorage\");\n try {\n updateTime = _storage_elm.getAttribute(\"jStorage_update\");\n } catch (E5) { }\n }\n\n if (updateTime && updateTime != _observer_update) {\n _observer_update = updateTime;\n _checkUpdatedKeys();\n }\n }, 25);\n }\n\n /**\n * Reloads the data and checks if any keys are changed\n */\n function _checkUpdatedKeys() {\n var oldCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32)),\n newCrc32List;\n\n _reloadData();\n newCrc32List = JSON.parse(JSON.stringify(_storage.__jstorage_meta.CRC32));\n\n var key,\n updated = [],\n removed = [];\n\n for (key in oldCrc32List) {\n if (oldCrc32List.hasOwnProperty(key)) {\n if (!newCrc32List[key]) {\n removed.push(key);\n continue;\n }\n if (oldCrc32List[key] != newCrc32List[key] && String(oldCrc32List[key]).substr(0, 2) == \"2.\") {\n updated.push(key);\n }\n }\n }\n\n for (key in newCrc32List) {\n if (newCrc32List.hasOwnProperty(key)) {\n if (!oldCrc32List[key]) {\n updated.push(key);\n }\n }\n }\n\n _fireObservers(updated, \"updated\");\n _fireObservers(removed, \"deleted\");\n }\n\n /**\n * Fires observers for updated keys\n *\n * @param {Array|String} keys Array of key names or a key\n * @param {String} action What happened with the value (updated, deleted, flushed)\n */\n function _fireObservers(keys, action) {\n keys = [].concat(keys || []);\n if (action == \"flushed\") {\n keys = [];\n for (var key in _observers) {\n if (_observers.hasOwnProperty(key)) {\n keys.push(key);\n }\n }\n action = \"deleted\";\n }\n for (var i = 0, len = keys.length; i < len; i++) {\n if (_observers[keys[i]]) {\n for (var j = 0, jlen = _observers[keys[i]].length; j < jlen; j++) {\n _observers[keys[i]][j](keys[i], action);\n }\n }\n }\n }\n\n /**\n * Publishes key change to listeners\n */\n function _publishChange() {\n var updateTime = (+new Date()).toString();\n\n if (_backend == \"localStorage\" || _backend == \"globalStorage\") {\n _storage_service.jStorage_update = updateTime;\n } else if (_backend == \"userDataBehavior\") {\n _storage_elm.setAttribute(\"jStorage_update\", updateTime);\n _storage_elm.save(\"jStorage\");\n }\n\n _storageObserver();\n }\n\n /**\n * Loads the data from the storage based on the supported mechanism\n */\n function _load_storage() {\n /* if jStorage string is retrieved, then decode it */\n if (_storage_service.jStorage) {\n try {\n _storage = JSON.parse(String(_storage_service.jStorage));\n } catch (E6) { _storage_service.jStorage = \"{}\"; }\n } else {\n _storage_service.jStorage = \"{}\";\n }\n _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;\n\n if (!_storage.__jstorage_meta) {\n _storage.__jstorage_meta = {};\n }\n if (!_storage.__jstorage_meta.CRC32) {\n _storage.__jstorage_meta.CRC32 = {};\n }\n }\n\n /**\n * This functions provides the \"save\" mechanism to store the jStorage object\n */\n function _save() {\n _dropOldEvents(); // remove expired events\n try {\n _storage_service.jStorage = JSON.stringify(_storage);\n // If userData is used as the storage engine, additional\n if (_storage_elm) {\n _storage_elm.setAttribute(\"jStorage\", _storage_service.jStorage);\n _storage_elm.save(\"jStorage\");\n }\n _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;\n } catch (E7) { /* probably cache is full, nothing is saved this way*/ }\n }\n\n /**\n * Function checks if a key is set and is string or numberic\n *\n * @param {String} key Key name\n */\n function _checkKey(key) {\n if (!key || (typeof key != \"string\" && typeof key != \"number\")) {\n throw new TypeError('Key name must be string or numeric');\n }\n if (key == \"__jstorage_meta\") {\n throw new TypeError('Reserved key name');\n }\n return true;\n }\n\n /**\n * Removes expired keys\n */\n function _handleTTL() {\n var curtime, i, TTL, CRC32, nextExpire = Infinity, changed = false, deleted = [];\n\n clearTimeout(_ttl_timeout);\n\n if (!_storage.__jstorage_meta || typeof _storage.__jstorage_meta.TTL != \"object\") {\n // nothing to do here\n return;\n }\n\n curtime = +new Date();\n TTL = _storage.__jstorage_meta.TTL;\n\n CRC32 = _storage.__jstorage_meta.CRC32;\n for (i in TTL) {\n if (TTL.hasOwnProperty(i)) {\n if (TTL[i] <= curtime) {\n delete TTL[i];\n delete CRC32[i];\n delete _storage[i];\n changed = true;\n deleted.push(i);\n } else if (TTL[i] < nextExpire) {\n nextExpire = TTL[i];\n }\n }\n }\n\n // set next check\n if (nextExpire != Infinity) {\n _ttl_timeout = setTimeout(_handleTTL, nextExpire - curtime);\n }\n\n // save changes\n if (changed) {\n _save();\n _publishChange();\n _fireObservers(deleted, \"deleted\");\n }\n }\n\n /**\n * Checks if there's any events on hold to be fired to listeners\n */\n function _handlePubSub() {\n if (!_storage.__jstorage_meta.PubSub) {\n return;\n }\n var pubelm,\n _pubsubCurrent = _pubsub_last;\n\n for (var i = len = _storage.__jstorage_meta.PubSub.length - 1; i >= 0; i--) {\n pubelm = _storage.__jstorage_meta.PubSub[i];\n if (pubelm[0] > _pubsub_last) {\n _pubsubCurrent = pubelm[0];\n _fireSubscribers(pubelm[1], pubelm[2]);\n }\n }\n\n _pubsub_last = _pubsubCurrent;\n }\n\n /**\n * Fires all subscriber listeners for a pubsub channel\n *\n * @param {String} channel Channel name\n * @param {Mixed} payload Payload data to deliver\n */\n function _fireSubscribers(channel, payload) {\n if (_pubsub_observers[channel]) {\n for (var i = 0, len = _pubsub_observers[channel].length; i < len; i++) {\n // send immutable data that can't be modified by listeners\n _pubsub_observers[channel][i](channel, JSON.parse(JSON.stringify(payload)));\n }\n }\n }\n\n /**\n * Remove old events from the publish stream (at least 2sec old)\n */\n function _dropOldEvents() {\n if (!_storage.__jstorage_meta.PubSub) {\n return;\n }\n\n var retire = +new Date() - 2000;\n\n for (var i = 0, len = _storage.__jstorage_meta.PubSub.length; i < len; i++) {\n if (_storage.__jstorage_meta.PubSub[i][0] <= retire) {\n // deleteCount is needed for IE6\n _storage.__jstorage_meta.PubSub.splice(i, _storage.__jstorage_meta.PubSub.length - i);\n break;\n }\n }\n\n if (!_storage.__jstorage_meta.PubSub.length) {\n delete _storage.__jstorage_meta.PubSub;\n }\n }\n\n /**\n * Publish payload to a channel\n *\n * @param {String} channel Channel name\n * @param {Mixed} payload Payload to send to the subscribers\n */\n function _publish(channel, payload) {\n if (!_storage.__jstorage_meta) {\n _storage.__jstorage_meta = {};\n }\n if (!_storage.__jstorage_meta.PubSub) {\n _storage.__jstorage_meta.PubSub = [];\n }\n\n _storage.__jstorage_meta.PubSub.unshift([+new Date, channel, payload]);\n\n _save();\n _publishChange();\n }\n\n /**\n * JS Implementation of MurmurHash2\n *\n * SOURCE: https://github.com/garycourt/murmurhash-js (MIT licensed)\n *\n * @author <a href=\"mailto:[email protected]\">Gary Court</a>\n * @see http://github.com/garycourt/murmurhash-js\n * @author <a href=\"mailto:[email protected]\">Austin Appleby</a>\n * @see http://sites.google.com/site/murmurhash/\n *\n * @param {string} str ASCII only\n * @param {number} seed Positive integer only\n * @return {number} 32-bit positive integer hash\n */\n\n function murmurhash2_32_gc(str, seed) {\n var\n l = str.length,\n h = seed ^ l,\n i = 0,\n k;\n\n while (l >= 4) {\n k =\n ((str.charCodeAt(i) & 0xff)) |\n ((str.charCodeAt(++i) & 0xff) << 8) |\n ((str.charCodeAt(++i) & 0xff) << 16) |\n ((str.charCodeAt(++i) & 0xff) << 24);\n\n k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n k ^= k >>> 24;\n k = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;\n\n l -= 4;\n ++i;\n }\n\n switch (l) {\n case 3: h ^= (str.charCodeAt(i + 2) & 0xff) << 16;\n case 2: h ^= (str.charCodeAt(i + 1) & 0xff) << 8;\n case 1: h ^= (str.charCodeAt(i) & 0xff);\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n }\n\n h ^= h >>> 13;\n h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n h ^= h >>> 15;\n\n return h >>> 0;\n }\n\n ////////////////////////// PUBLIC INTERFACE /////////////////////////\n\n $.jStorage = {\n /* Version number */\n version: JSTORAGE_VERSION,\n\n /**\n * Sets a key's value.\n *\n * @param {String} key Key to set. If this value is not set or not\n * a string an exception is raised.\n * @param {Mixed} value Value to set. This can be any value that is JSON\n * compatible (Numbers, Strings, Objects etc.).\n * @param {Object} [options] - possible options to use\n * @param {Number} [options.TTL] - optional TTL value\n * @return {Mixed} the used value\n */\n set: function (key, value, options) {\n _checkKey(key);\n\n options = options || {};\n\n // undefined values are deleted automatically\n if (typeof value == \"undefined\") {\n this.deleteKey(key);\n return value;\n }\n\n if (_XMLService.isXML(value)) {\n value = { _is_xml: true, xml: _XMLService.encode(value) };\n } else if (typeof value == \"function\") {\n return undefined; // functions can't be saved!\n } else if (value && typeof value == \"object\") {\n // clone the object before saving to _storage tree\n value = JSON.parse(JSON.stringify(value));\n }\n\n _storage[key] = value;\n\n _storage.__jstorage_meta.CRC32[key] = \"2.\" + murmurhash2_32_gc(JSON.stringify(value));\n\n this.setTTL(key, options.TTL || 0); // also handles saving and _publishChange\n\n _localStoragePolyfillSetKey(key, value);\n\n _fireObservers(key, \"updated\");\n return value;\n },\n\n /**\n * Looks up a key in cache\n *\n * @param {String} key - Key to look up.\n * @param {mixed} def - Default value to return, if key didn't exist.\n * @return {Mixed} the key value, default value or null\n */\n get: function (key, def) {\n _checkKey(key);\n if (key in _storage) {\n if (_storage[key] && typeof _storage[key] == \"object\" && _storage[key]._is_xml) {\n return _XMLService.decode(_storage[key].xml);\n } else {\n return _storage[key];\n }\n }\n return typeof (def) == 'undefined' ? null : def;\n },\n\n /**\n * Deletes a key from cache.\n *\n * @param {String} key - Key to delete.\n * @return {Boolean} true if key existed or false if it didn't\n */\n deleteKey: function (key) {\n _checkKey(key);\n if (key in _storage) {\n delete _storage[key];\n // remove from TTL list\n if (typeof _storage.__jstorage_meta.TTL == \"object\" &&\n key in _storage.__jstorage_meta.TTL) {\n delete _storage.__jstorage_meta.TTL[key];\n }\n\n delete _storage.__jstorage_meta.CRC32[key];\n _localStoragePolyfillSetKey(key, undefined);\n\n _save();\n _publishChange();\n _fireObservers(key, \"deleted\");\n return true;\n }\n return false;\n },\n\n /**\n * Sets a TTL for a key, or remove it if ttl value is 0 or below\n *\n * @param {String} key - key to set the TTL for\n * @param {Number} ttl - TTL timeout in milliseconds\n * @return {Boolean} true if key existed or false if it didn't\n */\n setTTL: function (key, ttl) {\n var curtime = +new Date();\n _checkKey(key);\n ttl = Number(ttl) || 0;\n if (key in _storage) {\n if (!_storage.__jstorage_meta.TTL) {\n _storage.__jstorage_meta.TTL = {};\n }\n\n // Set TTL value for the key\n if (ttl > 0) {\n _storage.__jstorage_meta.TTL[key] = curtime + ttl;\n } else {\n delete _storage.__jstorage_meta.TTL[key];\n }\n\n _save();\n\n _handleTTL();\n\n _publishChange();\n return true;\n }\n return false;\n },\n\n /**\n * Gets remaining TTL (in milliseconds) for a key or 0 when no TTL has been set\n *\n * @param {String} key Key to check\n * @return {Number} Remaining TTL in milliseconds\n */\n getTTL: function (key) {\n var curtime = +new Date(), ttl;\n _checkKey(key);\n if (key in _storage && _storage.__jstorage_meta.TTL && _storage.__jstorage_meta.TTL[key]) {\n ttl = _storage.__jstorage_meta.TTL[key] - curtime;\n return ttl || 0;\n }\n return 0;\n },\n\n /**\n * Deletes everything in cache.\n *\n * @return {Boolean} Always true\n */\n flush: function () {\n _storage = { __jstorage_meta: { CRC32: {}} };\n _createPolyfillStorage(\"local\", true);\n _save();\n _publishChange();\n _fireObservers(null, \"flushed\");\n return true;\n },\n\n /**\n * Returns a read-only copy of _storage\n *\n * @return {Object} Read-only copy of _storage\n */\n storageObj: function () {\n function F() { }\n F.prototype = _storage;\n return new F();\n },\n\n /**\n * Returns an index of all used keys as an array\n * ['key1', 'key2',..'keyN']\n *\n * @return {Array} Used keys\n */\n index: function () {\n var index = [], i;\n for (i in _storage) {\n if (_storage.hasOwnProperty(i) && i != \"__jstorage_meta\") {\n index.push(i);\n }\n }\n return index;\n },\n\n /**\n * How much space in bytes does the storage take?\n *\n * @return {Number} Storage size in chars (not the same as in bytes,\n * since some chars may take several bytes)\n */\n storageSize: function () {\n return _storage_size;\n },\n\n /**\n * Which backend is currently in use?\n *\n * @return {String} Backend name\n */\n currentBackend: function () {\n return _backend;\n },\n\n /**\n * Test if storage is available\n *\n * @return {Boolean} True if storage can be used\n */\n storageAvailable: function () {\n return !!_backend;\n },\n\n /**\n * Register change listeners\n *\n * @param {String} key Key name\n * @param {Function} callback Function to run when the key changes\n */\n listenKeyChange: function (key, callback) {\n _checkKey(key);\n if (!_observers[key]) {\n _observers[key] = [];\n }\n _observers[key].push(callback);\n },\n\n /**\n * Remove change listeners\n *\n * @param {String} key Key name to unregister listeners against\n * @param {Function} [callback] If set, unregister the callback, if not - unregister all\n */\n stopListening: function (key, callback) {\n _checkKey(key);\n\n if (!_observers[key]) {\n return;\n }\n\n if (!callback) {\n delete _observers[key];\n return;\n }\n\n for (var i = _observers[key].length - 1; i >= 0; i--) {\n if (_observers[key][i] == callback) {\n _observers[key].splice(i, 1);\n }\n }\n },\n\n /**\n * Subscribe to a Publish/Subscribe event stream\n *\n * @param {String} channel Channel name\n * @param {Function} callback Function to run when the something is published to the channel\n */\n subscribe: function (channel, callback) {\n channel = (channel || \"\").toString();\n if (!channel) {\n throw new TypeError('Channel not defined');\n }\n if (!_pubsub_observers[channel]) {\n _pubsub_observers[channel] = [];\n }\n _pubsub_observers[channel].push(callback);\n },\n\n /**\n * Publish data to an event stream\n *\n * @param {String} channel Channel name\n * @param {Mixed} payload Payload to deliver\n */\n publish: function (channel, payload) {\n channel = (channel || \"\").toString();\n if (!channel) {\n throw new TypeError('Channel not defined');\n }\n\n _publish(channel, payload);\n },\n\n /**\n * Reloads the data from browser storage\n */\n reInit: function () {\n _reloadData();\n }\n };\n\n // Initialize jStorage\n _init();\n})();", | |
"settings": | |
{ | |
"buffer_size": 29752, | |
"line_ending": "Windows", | |
"name": "jquery-jstorage.js" | |
} | |
}, | |
{ | |
"file": "a.html", | |
"settings": | |
{ | |
"buffer_size": 755, | |
"line_ending": "Windows" | |
} | |
} | |
], | |
"build_system": "Packages/User/Firefox-preview.sublime-build", | |
"command_palette": | |
{ | |
"height": 375.0, | |
"selected_items": | |
[ | |
[ | |
"gis", | |
"Gist: Open Gist" | |
], | |
[ | |
"sscss", | |
"Set Syntax: CSS" | |
], | |
[ | |
"ssja", | |
"Set Syntax: jQuery (JavaScript)" | |
], | |
[ | |
"sshtm", | |
"Set Syntax: HTML" | |
], | |
[ | |
"gist", | |
"Gist: Open Gist" | |
], | |
[ | |
"tid", | |
"Tidy HTML" | |
], | |
[ | |
"html", | |
"Set Syntax: HTML" | |
], | |
[ | |
"tidy", | |
"Tidy HTML" | |
], | |
[ | |
"mark", | |
"Set Syntax: Markdown" | |
], | |
[ | |
"javas", | |
"Set Syntax: JavaScript" | |
], | |
[ | |
"pack", | |
"Package Control: Disable Package" | |
], | |
[ | |
"insta", | |
"Package Control: Install Package" | |
], | |
[ | |
"exo", | |
"Export to HTML: Show Export Menu" | |
], | |
[ | |
"showex", | |
"Export to HTML: Show Export Menu" | |
], | |
[ | |
"expo", | |
"Export to HTML: Show Export Menu" | |
], | |
[ | |
"exp", | |
"Export to HTML: Show Export Menu" | |
], | |
[ | |
"inst", | |
"Package Control: Install Package" | |
], | |
[ | |
"prin", | |
"Print to HTML: print as HTML via browser" | |
], | |
[ | |
"packa", | |
"Package Control: Upgrade Package" | |
], | |
[ | |
"pri", | |
"Print to HTML: print as HTML via browser" | |
], | |
[ | |
"print", | |
"Package Control: Install Package" | |
], | |
[ | |
"prett", | |
"HTMLPrettify: Prettify" | |
], | |
[ | |
"pret", | |
"HTMLPrettify: Prettify" | |
], | |
[ | |
"f", | |
"HTMLPrettify: Prettify" | |
], | |
[ | |
"javasc", | |
"Set Syntax: JavaScript" | |
], | |
[ | |
"java", | |
"Project: Save As" | |
], | |
[ | |
"markd", | |
"Set Syntax: Markdown" | |
], | |
[ | |
"ins", | |
"Package Control: Install Package" | |
], | |
[ | |
"htm", | |
"Set Syntax: HTML" | |
], | |
[ | |
"spec", | |
"CSSpecific: Check specifity" | |
], | |
[ | |
"css", | |
"Set Syntax: CSS" | |
], | |
[ | |
"packag", | |
"Package Control: Remove Package" | |
], | |
[ | |
"csscom", | |
"Sort via CSScomb" | |
], | |
[ | |
"cssco", | |
"Sort via CSScomb" | |
], | |
[ | |
"cssc", | |
"Sort via CSScomb" | |
], | |
[ | |
"sort", | |
"Sort via CSScomb" | |
], | |
[ | |
"comb", | |
"Sort via CSScomb" | |
], | |
[ | |
"install", | |
"Package Control: Install Package" | |
], | |
[ | |
"spe", | |
"CSSpecific: Check specifity" | |
], | |
[ | |
"i", | |
"Package Control: Install Package" | |
], | |
[ | |
"filenew", | |
"File: New View into File" | |
], | |
[ | |
"pref", | |
"Preferences: Prefixr Key Bindings – Default" | |
], | |
[ | |
"snipp", | |
"Snippet: CSS - clearfix" | |
], | |
[ | |
"in", | |
"Package Control: Install Package" | |
], | |
[ | |
"sni", | |
"Snippet: nav - Placeholder" | |
], | |
[ | |
"side", | |
"View: Toggle Open Files in Side Bar" | |
], | |
[ | |
"syntas", | |
"Set Syntax: Tasks" | |
], | |
[ | |
"todo", | |
"Set Syntax: mdTodo" | |
], | |
[ | |
"too", | |
"Todo: Add" | |
], | |
[ | |
"instal", | |
"Package Control: Install Package" | |
] | |
], | |
"width": 386.0 | |
}, | |
"console": | |
{ | |
"height": 133.0 | |
}, | |
"distraction_free": | |
{ | |
"menu_visible": true, | |
"show_minimap": false, | |
"show_open_files": false, | |
"show_tabs": false, | |
"side_bar_visible": false, | |
"status_bar_visible": false | |
}, | |
"file_history": | |
[ | |
"/C/Users/rfessler/Documents/Dropbox/PSPadProjects/errordiv re-design/errordiv re-design project.sublime-project", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/User/Preferences.sublime-settings", | |
"/C/Users/rfessler/Documents/Dropbox/Projects/storage/a.html", | |
"/C/Users/rfessler/Documents/Dropbox/Projects/storage/a.js", | |
"/C/Users/rfessler/Documents/Dropbox/Projects/storage/a.css", | |
"/D/_SearsClean Update Proj Originals/master.css", | |
"/D/_SearsClean Update Proj Originals/SearsCleanMaster.Master", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/Default/Preferences.sublime-settings", | |
"/C/Users/rfessler/AppData/Local/Temp/SearsCleanMaster.Master", | |
"/D/update-customer.js", | |
"/D/address-info.js", | |
"/D/customerdetail phone number section.js", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/Default/Default (Windows).sublime-keymap", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/User/Default (Windows).sublime-keymap", | |
"/C/Windows/System32/drivers/etc/hosts", | |
"/D/temp2.js", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/SublimePrint/SublimePrint.sublime-settings", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/SublimePrint/SublimePrintSelection.py", | |
"/D/temp.html", | |
"/C/Users/rfessler/Documents/Dropbox/PSPadProjects/errordiv re-design/default.html", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/ExportHtml/Default.sublime-commands", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/ExportHtml/readme.md", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/ExportHtml/ExportHtml.sublime-settings", | |
"/c/users/rfessler/appdata/local/temp/tmpo1dpls.html", | |
"/C/Users/rfessler/Documents/Visual Studio 2010/Projects/SearsClean/SearsClientAccessWeb/css/global - Copy.css", | |
"/C/Users/rfessler/Documents/Visual Studio 2010/Projects/SearsClean/SearsClientAccessWeb/css/global.css", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/SublimePrint/SublimePrintSelection.pyc", | |
"/C/Users/rfessler/Documents/GitHub/Work/README_NOW.md", | |
"/C/Users/rfessler/Documents/GitHub/Work/README", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/User/Firefox-preview.sublime-build", | |
"/C/temp/css/pretty-global.css", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/CSScomb/Context.sublime-menu", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/CSScomb/CSScomb.py", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/CSScomb/CSScomb.sublime-commands", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/CSScomb/Main.sublime-menu", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/CSScomb/README.md", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/Prefixr/Default (Windows).sublime-keymap", | |
"/C/temp/css/delimit.txt", | |
"/C/temp/css/combine2.bat", | |
"/C/temp/css/combine.bat", | |
"/C/temp/css/scaw.css", | |
"/C/Users/rfessler/AppData/Roaming/Sublime Text 2/Packages/CSS Snippets/README.md" | |
], | |
"find": | |
{ | |
"height": 35.0 | |
}, | |
"find_in_files": | |
{ | |
"height": 0.0, | |
"where_history": | |
[ | |
"" | |
] | |
}, | |
"find_state": | |
{ | |
"case_sensitive": false, | |
"find_history": | |
[ | |
"~", | |
"[", | |
"\"numbers\": false,", | |
"\"numbers\": true", | |
"tr", | |
"/n", | |
" ", | |
"div", | |
"\"></", | |
"detect_slow", | |
"hide", | |
"/**", | |
"start", | |
"/**", | |
"START - css file seperator" | |
], | |
"highlight": true, | |
"in_selection": false, | |
"preserve_case": false, | |
"regex": false, | |
"replace_history": | |
[ | |
"\"numbers\": true,", | |
"\"numbers\": false", | |
"\\n", | |
"/n" | |
], | |
"reverse": false, | |
"show_context": true, | |
"use_buffer2": true, | |
"whole_word": false, | |
"wrap": true | |
}, | |
"groups": | |
[ | |
{ | |
"selected": 4, | |
"sheets": | |
[ | |
{ | |
"buffer": 0, | |
"settings": | |
{ | |
"buffer_size": 183, | |
"regions": | |
{ | |
}, | |
"selection": | |
[ | |
[ | |
183, | |
183 | |
] | |
], | |
"settings": | |
{ | |
"gist_description": "storageExample using json", | |
"gist_filename": "a.css", | |
"gist_html_url": "https://gist.github.com/4511299", | |
"gist_url": "https://api.github.com/gists/4511299", | |
"syntax": "Packages/Text/Plain text.tmLanguage" | |
}, | |
"translation.x": 0.0, | |
"translation.y": 0.0, | |
"zoom_level": 1.0 | |
}, | |
"type": "text" | |
}, | |
{ | |
"buffer": 1, | |
"settings": | |
{ | |
"buffer_size": 755, | |
"regions": | |
{ | |
}, | |
"selection": | |
[ | |
[ | |
755, | |
755 | |
] | |
], | |
"settings": | |
{ | |
"gist_description": "storageExample using json", | |
"gist_filename": "a.html", | |
"gist_html_url": "https://gist.github.com/4511299", | |
"gist_url": "https://api.github.com/gists/4511299", | |
"syntax": "Packages/Text/Plain text.tmLanguage" | |
}, | |
"translation.x": 0.0, | |
"translation.y": 0.0, | |
"zoom_level": 1.0 | |
}, | |
"type": "text" | |
}, | |
{ | |
"buffer": 2, | |
"settings": | |
{ | |
"buffer_size": 1927, | |
"regions": | |
{ | |
}, | |
"selection": | |
[ | |
[ | |
235, | |
235 | |
] | |
], | |
"settings": | |
{ | |
"gist_description": "storageExample using json", | |
"gist_filename": "a.js", | |
"gist_html_url": "https://gist.github.com/4511299", | |
"gist_url": "https://api.github.com/gists/4511299", | |
"syntax": "Packages/Text/Plain text.tmLanguage" | |
}, | |
"translation.x": 0.0, | |
"translation.y": 0.0, | |
"zoom_level": 1.0 | |
}, | |
"type": "text" | |
}, | |
{ | |
"buffer": 3, | |
"settings": | |
{ | |
"buffer_size": 29752, | |
"regions": | |
{ | |
}, | |
"selection": | |
[ | |
[ | |
29752, | |
29752 | |
] | |
], | |
"settings": | |
{ | |
"gist_description": "storageExample using json", | |
"gist_filename": "jquery-jstorage.js", | |
"gist_html_url": "https://gist.github.com/4511299", | |
"gist_url": "https://api.github.com/gists/4511299", | |
"syntax": "Packages/Text/Plain text.tmLanguage" | |
}, | |
"translation.x": 0.0, | |
"translation.y": 0.0, | |
"zoom_level": 1.0 | |
}, | |
"type": "text" | |
}, | |
{ | |
"buffer": 4, | |
"file": "a.html", | |
"settings": | |
{ | |
"buffer_size": 755, | |
"regions": | |
{ | |
}, | |
"selection": | |
[ | |
[ | |
571, | |
571 | |
] | |
], | |
"settings": | |
{ | |
"syntax": "Packages/HTML/HTML.tmLanguage", | |
"tab_size": 4, | |
"translate_tabs_to_spaces": true | |
}, | |
"translation.x": 0.0, | |
"translation.y": 0.0, | |
"zoom_level": 1.0 | |
}, | |
"type": "text" | |
} | |
] | |
} | |
], | |
"incremental_find": | |
{ | |
"height": 35.0 | |
}, | |
"input": | |
{ | |
"height": 31.0 | |
}, | |
"layout": | |
{ | |
"cells": | |
[ | |
[ | |
0, | |
0, | |
1, | |
1 | |
] | |
], | |
"cols": | |
[ | |
0.0, | |
1.0 | |
], | |
"rows": | |
[ | |
0.0, | |
1.0 | |
] | |
}, | |
"menu_visible": true, | |
"output.csspecific": | |
{ | |
"height": 124.0 | |
}, | |
"output.exec": | |
{ | |
"height": 119.0 | |
}, | |
"replace": | |
{ | |
"height": 64.0 | |
}, | |
"save_all_on_build": true, | |
"select_file": | |
{ | |
"height": 0.0, | |
"selected_items": | |
[ | |
], | |
"width": 0.0 | |
}, | |
"select_project": | |
{ | |
"height": 500.0, | |
"selected_items": | |
[ | |
[ | |
"", | |
"/C/Users/rfessler/Documents/Dropbox/Projects/LeftNavUserControls/LeftNavigation.sublime-project" | |
] | |
], | |
"width": 380.0 | |
}, | |
"show_minimap": true, | |
"show_open_files": true, | |
"show_tabs": true, | |
"side_bar_visible": true, | |
"side_bar_width": 173.0, | |
"status_bar_visible": true | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment