Last active
December 18, 2015 11:39
-
-
Save kalley/5776979 to your computer and use it in GitHub Desktop.
plugin to facilitate using lz-string (http://pieroxy.net/blog/pages/lz-string/index.html) to compress values before adding them to localStorage using a webworker (technically, you could use anything you want, since the url for the worker gets passed in per instance). Also added "exists" method to check if a key exists in localStorage already. Ad…
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
// jquery.localCompress | |
// get, set return promises | |
(function($, localStorage) { | |
$.localCompress = function(workerURL) { | |
var initWorker = function(onmessage, type, value) { | |
var worker = new Worker(workerURL); | |
worker.onmessage = onmessage; | |
worker.postMessage({ | |
type: type, | |
value: value | |
}); | |
}; | |
return { | |
get: function(key) { | |
var storageDfd = $.Deferred(); | |
var item = localStorage.getItem(key); | |
if ( item ) { | |
initWorker(function(ev) { | |
storageDfd.resolve(JSON.parse(ev.data)); | |
}, 'decompress', item); | |
} else { | |
storageDfd.reject(null); | |
} | |
return storageDfd; | |
}, | |
set: function(key, val) { | |
var storageDfd = $.Deferred(); | |
var self = this; | |
storageDfd.then(function(compressed) { | |
try { | |
localStorage.setItem(key, compressed); | |
} catch(err) { | |
$(window).trigger('storageError', [err]); | |
} | |
self.length = localStorage.length; | |
}); | |
initWorker(function(ev) { | |
storageDfd.resolve(ev.data); | |
}, 'compress', JSON.stringify(val)); | |
return storageDfd; | |
}, | |
remove: function(key) { | |
var returnVal = localStorage.removeItem(key); | |
this.length = localStorage.length; | |
return returnVal; | |
}, | |
clear: function() { | |
var returnVal = localStorage.clear(); | |
this.length = localStorage.length; | |
return returnVal; | |
}, | |
key: function(index) { | |
return localStorage.key(index); | |
}, | |
exists: function(key) { | |
var exists = false; | |
for ( var i = 0; i < this.length; ++i ) { | |
if ( this.key(i) === key ) { | |
exists = true; | |
} | |
} | |
return exists; | |
}, | |
length: localStorage.length | |
}; | |
}; | |
})(jQuery, localStorage); |
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
// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net> | |
// This work is free. You can redistribute it and/or modify it | |
// under the terms of the WTFPL, Version 2 | |
// For more information see LICENSE.txt or http://www.wtfpl.net/ | |
// | |
// See the rationale behind the optimizations here: | |
// http://pieroxy.net/blog/pages/lz-string/testing.html | |
// | |
// LZ-based compression algorithm, version 1.1.0 | |
var LZString = { | |
compress: function (uncompressed) { | |
var i, value, | |
context_dictionary= {}, | |
context_dictionaryToCreate= {}, | |
context_c="", | |
context_wc="", | |
context_w="", | |
context_enlargeIn= 2, // Compensate for the first entry which should not count | |
context_dictSize= 3, | |
context_numBits= 2, | |
context_result= "", | |
context_data_string="", | |
context_data_val=0, | |
context_data_position=0, | |
ii; | |
for (ii = 0; ii < uncompressed.length; ii += 1) { | |
context_c = uncompressed.charAt(ii); | |
if (!context_dictionary.hasOwnProperty(context_c)) { | |
context_dictionary[context_c] = context_dictSize++; | |
context_dictionaryToCreate[context_c] = true; | |
} | |
context_wc = context_w + context_c; | |
if (context_dictionary.hasOwnProperty(context_wc)) { | |
context_w = context_wc; | |
} else { | |
if (context_dictionaryToCreate.hasOwnProperty(context_w)) { | |
if (context_w.charCodeAt(0)<256) { | |
for (i=0 ; i<context_numBits ; i++) { | |
context_data_val = (context_data_val << 1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
} | |
value = context_w.charCodeAt(0); | |
for (i=0 ; i<8 ; i++) { | |
context_data_val = (context_data_val << 1) | (value&1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = value >> 1; | |
} | |
} else { | |
value = 1; | |
for (i=0 ; i<context_numBits ; i++) { | |
context_data_val = (context_data_val << 1) | value; | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = 0; | |
} | |
value = context_w.charCodeAt(0); | |
for (i=0 ; i<16 ; i++) { | |
context_data_val = (context_data_val << 1) | (value&1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = value >> 1; | |
} | |
} | |
context_enlargeIn--; | |
if (context_enlargeIn == 0) { | |
context_enlargeIn = Math.pow(2, context_numBits); | |
context_numBits++; | |
} | |
delete context_dictionaryToCreate[context_w]; | |
} else { | |
value = context_dictionary[context_w]; | |
for (i=0 ; i<context_numBits ; i++) { | |
context_data_val = (context_data_val << 1) | (value&1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = value >> 1; | |
} | |
} | |
context_enlargeIn--; | |
if (context_enlargeIn == 0) { | |
context_enlargeIn = Math.pow(2, context_numBits); | |
context_numBits++; | |
} | |
// Add wc to the dictionary. | |
context_dictionary[context_wc] = context_dictSize++; | |
context_w = String(context_c); | |
} | |
} | |
// Output the code for w. | |
if (context_w !== "") { | |
if (context_dictionaryToCreate.hasOwnProperty(context_w)) { | |
if (context_w.charCodeAt(0)<256) { | |
for (i=0 ; i<context_numBits ; i++) { | |
context_data_val = (context_data_val << 1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
} | |
value = context_w.charCodeAt(0); | |
for (i=0 ; i<8 ; i++) { | |
context_data_val = (context_data_val << 1) | (value&1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = value >> 1; | |
} | |
} else { | |
value = 1; | |
for (i=0 ; i<context_numBits ; i++) { | |
context_data_val = (context_data_val << 1) | value; | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = 0; | |
} | |
value = context_w.charCodeAt(0); | |
for (i=0 ; i<16 ; i++) { | |
context_data_val = (context_data_val << 1) | (value&1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = value >> 1; | |
} | |
} | |
context_enlargeIn--; | |
if (context_enlargeIn == 0) { | |
context_enlargeIn = Math.pow(2, context_numBits); | |
context_numBits++; | |
} | |
delete context_dictionaryToCreate[context_w]; | |
} else { | |
value = context_dictionary[context_w]; | |
for (i=0 ; i<context_numBits ; i++) { | |
context_data_val = (context_data_val << 1) | (value&1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = value >> 1; | |
} | |
} | |
context_enlargeIn--; | |
if (context_enlargeIn == 0) { | |
context_enlargeIn = Math.pow(2, context_numBits); | |
context_numBits++; | |
} | |
} | |
// Mark the end of the stream | |
value = 2; | |
for (i=0 ; i<context_numBits ; i++) { | |
context_data_val = (context_data_val << 1) | (value&1); | |
if (context_data_position == 15) { | |
context_data_position = 0; | |
context_data_string += String.fromCharCode(context_data_val); | |
context_data_val = 0; | |
} else { | |
context_data_position++; | |
} | |
value = value >> 1; | |
} | |
// Flush the last char | |
while (true) { | |
context_data_val = (context_data_val << 1); | |
if (context_data_position == 15) { | |
context_data_string += String.fromCharCode(context_data_val); | |
break; | |
} | |
else context_data_position++; | |
} | |
return context_data_string; | |
}, | |
readBits : function(numBits, data) { | |
var bits = 0, resb; | |
var maxpower = Math.pow(2,numBits); | |
var power=1; | |
while (power!=maxpower) { | |
resb = data.val & data.position; | |
data.position >>= 1; | |
if (data.position == 0) { | |
data.position = 32768; | |
data.val = data.string.charCodeAt(data.index++); | |
} | |
bits |= (resb>0 ? 1 : 0) * power; | |
power <<= 1; | |
} | |
return bits; | |
}, | |
decompress: function (compressed) { | |
var dictionary = [], | |
next, | |
enlargeIn = 4, | |
dictSize = 4, | |
numBits = 3, | |
entry = "", | |
result = "", | |
i, | |
w, | |
bits, resb, maxpower, power, | |
c, | |
errorCount=0, | |
literal, | |
data = {string:compressed, val:compressed.charCodeAt(0), position:32768, index:1}; | |
for (i = 0; i < 3; i += 1) { | |
dictionary[i] = i; | |
} | |
bits = 0; | |
maxpower = Math.pow(2,2); | |
power=1; | |
while (power!=maxpower) { | |
resb = data.val & data.position; | |
data.position >>= 1; | |
if (data.position == 0) { | |
data.position = 32768; | |
data.val = data.string.charCodeAt(data.index++); | |
} | |
bits |= (resb>0 ? 1 : 0) * power; | |
power <<= 1; | |
} | |
switch (next = bits) { | |
case 0: | |
bits = 0; | |
maxpower = Math.pow(2,8); | |
power=1; | |
while (power!=maxpower) { | |
resb = data.val & data.position; | |
data.position >>= 1; | |
if (data.position == 0) { | |
data.position = 32768; | |
data.val = data.string.charCodeAt(data.index++); | |
} | |
bits |= (resb>0 ? 1 : 0) * power; | |
power <<= 1; | |
} | |
c = String.fromCharCode(bits); | |
break; | |
case 1: | |
bits = 0; | |
maxpower = Math.pow(2,16); | |
power=1; | |
while (power!=maxpower) { | |
resb = data.val & data.position; | |
data.position >>= 1; | |
if (data.position == 0) { | |
data.position = 32768; | |
data.val = data.string.charCodeAt(data.index++); | |
} | |
bits |= (resb>0 ? 1 : 0) * power; | |
power <<= 1; | |
} | |
c = String.fromCharCode(bits); | |
break; | |
case 2: | |
return ""; | |
} | |
dictionary[3] = c; | |
w = result = c; | |
while (true) { | |
bits = 0; | |
maxpower = Math.pow(2,numBits); | |
power=1; | |
while (power!=maxpower) { | |
resb = data.val & data.position; | |
data.position >>= 1; | |
if (data.position == 0) { | |
data.position = 32768; | |
data.val = data.string.charCodeAt(data.index++); | |
} | |
bits |= (resb>0 ? 1 : 0) * power; | |
power <<= 1; | |
} | |
switch (c = bits) { | |
case 0: | |
if (errorCount++ > 10000) return "Error"; | |
bits = 0; | |
maxpower = Math.pow(2,8); | |
power=1; | |
while (power!=maxpower) { | |
resb = data.val & data.position; | |
data.position >>= 1; | |
if (data.position == 0) { | |
data.position = 32768; | |
data.val = data.string.charCodeAt(data.index++); | |
} | |
bits |= (resb>0 ? 1 : 0) * power; | |
power <<= 1; | |
} | |
dictionary[dictSize++] = String.fromCharCode(bits); | |
c = dictSize-1; | |
enlargeIn--; | |
break; | |
case 1: | |
bits = 0; | |
maxpower = Math.pow(2,16); | |
power=1; | |
while (power!=maxpower) { | |
resb = data.val & data.position; | |
data.position >>= 1; | |
if (data.position == 0) { | |
data.position = 32768; | |
data.val = data.string.charCodeAt(data.index++); | |
} | |
bits |= (resb>0 ? 1 : 0) * power; | |
power <<= 1; | |
} | |
dictionary[dictSize++] = String.fromCharCode(bits); | |
c = dictSize-1; | |
enlargeIn--; | |
break; | |
case 2: | |
return result; | |
} | |
if (enlargeIn == 0) { | |
enlargeIn = Math.pow(2, numBits); | |
numBits++; | |
} | |
if (dictionary[c]) { | |
entry = dictionary[c]; | |
} else { | |
if (c === dictSize) { | |
entry = w + w.charAt(0); | |
} else { | |
return null; | |
} | |
} | |
result += entry; | |
// Add w+entry[0] to the dictionary. | |
dictionary[dictSize++] = w + entry.charAt(0); | |
enlargeIn--; | |
w = entry; | |
if (enlargeIn == 0) { | |
enlargeIn = Math.pow(2, numBits); | |
numBits++; | |
} | |
} | |
return result; | |
} | |
}; | |
// This is the worker. Above is lz-string.js | |
self.addEventListener('message', function(ev) { | |
var value = ev.data.value; | |
var type = ev.data.type; | |
value = LZString[type](value); | |
self.postMessage(value); | |
self.close(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment