-
-
Save nutbread/ac22d7f9419c55e3f96f to your computer and use it in GitHub Desktop.
Async saving in Javascript for scripts in Greasemonkey, Tampermonkey, Chrome, and webpage embeding
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
/** | |
Save.get(key, callback) | |
Get the value of an entry from storage | |
@param key : string | |
The key to find the value of | |
@param callback : function(value, okay) | |
The callback to run on completion | |
value: | |
the value found in storage | |
okay: | |
true if no errors, false otherwise | |
Save.set(key, value, [callback]) | |
Set the value of an entry in storage | |
@param key : string | |
The key to set the value of | |
@param value : any | |
The value to store | |
@param callback : function(okay) [optional] | |
The callback to run on completion | |
okay: | |
true if no errors, false otherwise | |
Save.del(key, [callback]) | |
Remove an entry from storage | |
@param key : string | |
The key to remove | |
@param callback : function(okay) [optional] | |
The callback to run on completion | |
okay: | |
true if no errors, false otherwise | |
Save.keys(callback) | |
Get a list of keys of all the items being stored | |
@param callback : function(key_array, okay) | |
The callback to run on completion | |
key_array: | |
An array of keys being stored | |
okay: | |
true if no errors, false otherwise | |
Save.size(callback) | |
Get the total size of storage memory being used | |
@param callback : function(size_in_bytes, okay) | |
The callback to run on completion | |
size_in_bytes: | |
The number of bytes being used | |
okay: | |
true if no errors, false otherwise | |
Save.clear([callback]) | |
Clear all entries from storage | |
@param callback : function(okay) [optional] | |
The callback to run on completion | |
okay: | |
true if no errors, false otherwise | |
Save.set_mode(mode) | |
Sets the saving mode | |
@param mode : string | |
One of [ "userscript" , "local" , "session" , "temp" ] | |
If one of these is not set, it falls back to the next one in the list | |
@return | |
The new mode being used; may not be the same as the desired mode | |
Save.get_mode() | |
Returns the mode being used | |
@return | |
The mode being used | |
Note that the first 6 functions can also be applied onto the following objects as well (if they're not null): | |
Save.userscript | |
Save.local | |
Save.session | |
Save.temp | |
*/ | |
var Save = (function () { | |
// Storage type | |
var using_gmstorage = false, | |
chrome_storage = null, | |
mode = "userscript", | |
modes = [ "userscript" , "local" , "session" , "temp" ], | |
temp_storage = {}, | |
set_mode_functions, object_byte_size, create_generic_save, save; | |
// Session/site saving | |
object_byte_size = function (obj) { | |
try { | |
// Encode as a JSON object | |
obj = JSON.stringify(obj); | |
} | |
catch (e) { | |
// Invalid | |
return 0; | |
} | |
try { | |
// Encode in utf-8 | |
return unescape(encodeURIComponent(obj)).length; | |
} | |
catch (e) {} | |
return obj.length; | |
}; | |
// Generic save | |
create_generic_save = function (obj, object_byte_size) { | |
// Create | |
return { | |
get: function (key, callback) { | |
// Get value | |
var val = obj.getItem(key, undefined); | |
try { | |
val = JSON.parse(val); | |
} | |
catch (e) {} | |
callback.call(null, val, true); | |
}, | |
set: function (key, value, callback) { | |
// Set value | |
var okay = true; | |
try { | |
obj.setItem(key, JSON.stringify(value)); | |
} | |
catch (e) { | |
okay = false; | |
} | |
if (callback) callback.call(null, okay); | |
}, | |
del: function (key, callback) { | |
// Remove | |
obj.removeItem(key); | |
if (callback) callback.call(null, true); | |
}, | |
keys: function (callback) { | |
// List keys | |
var keys = [], | |
i; | |
for (i = 0; i < obj.length; ++i) { | |
keys.push(obj.key(i)); | |
} | |
callback.call(null, keys, true); | |
}, | |
size: function (callback) { | |
var size = 0, | |
key, i; | |
// Count bytes (this may be approximate) | |
for (i = 0; i < obj.length; ++i) { | |
key = obj.key(i); | |
size += object_byte_size(key) + ((obj.getItem(key, null) || "").length || 0); | |
} | |
// Return | |
callback.call(null, size, true); | |
}, | |
clear: function (callback) { | |
// Remove items | |
obj.clear(); | |
if (callback) callback.call(null, true); | |
}, | |
}; | |
}; | |
// Copy functions | |
set_mode_functions = function (new_mode) { | |
// Copy | |
var fns = save[new_mode]; | |
save.get = fns.get; | |
save.set = fns.set; | |
save.del = fns.del; | |
save.keys = fns.keys; | |
save.size = fns.size; | |
save.clear = fns.clear; | |
// Update | |
mode = new_mode; | |
}; | |
// Local storage save | |
save = { | |
get: null, | |
set: null, | |
del: null, | |
keys: null, | |
size: null, | |
clear: null, | |
local: create_generic_save(window.localStorage, object_byte_size), | |
session: create_generic_save(window.sessionStorage, object_byte_size), | |
userscript: null, | |
temp: { | |
get: function (key, callback) { | |
// Get value | |
var val = temp_storage[key]; | |
try { | |
val = JSON.parse(val); | |
} | |
catch (e) {} | |
callback.call(null, val, true); | |
}, | |
set: function (key, value, callback) { | |
// Set value | |
temp_storage[key] = JSON.stringify(value); | |
if (callback) callback.call(null, true); | |
}, | |
del: function (key, callback) { | |
// Remove | |
delete temp_storage[key]; | |
if (callback) callback.call(null, true); | |
}, | |
keys: function (callback) { | |
// List keys | |
var keys = [], | |
k; | |
for (k in temp_storage) { | |
keys.push(k); | |
} | |
callback.call(null, keys, true); | |
}, | |
size: function (callback) { | |
// Get size | |
var size = object_byte_size(temp_storage); | |
callback.call(null, size, true); | |
}, | |
clear: function (callback) { | |
// Clear | |
temp_storage = {}; | |
if (callback) callback.call(null, true); | |
}, | |
}, | |
set_mode: function (new_mode) { | |
var i = modes.indexOf(new_mode); | |
if (i < 0) i = 0; | |
while (save[modes[i]] === null) ++i; | |
set_mode_functions(modes[i]); | |
return mode; | |
}, | |
get_mode: function () { | |
return mode; | |
}, | |
}; | |
create_generic_save = null; | |
// Check for chrome storage | |
try { | |
chrome_storage = chrome.storage.local || null; | |
} | |
catch (e) {} | |
// Check for GM storage | |
try { | |
if (GM_setValue && GM_getValue && GM_deleteValue && GM_listValues) { | |
using_gmstorage = true; | |
} | |
} | |
catch (e) {} | |
// Userscript storage method | |
if (chrome_storage !== null) { | |
// Chrome storage | |
save.userscript = { | |
get: function (key, callback) { | |
chrome_storage.get(key, function (value) { | |
// Final callback | |
callback.call(null, value[key], true); | |
}); | |
}, | |
set: function (key, value, callback) { | |
var obj = {}; | |
obj[key] = value; | |
chrome_storage.set(obj, callback ? function () { | |
// Final callback | |
callback.call(null, true); | |
} : undefined); | |
}, | |
del: function (key, callback) { | |
chrome_storage.remove(key, callback ? function () { | |
// Final callback | |
callback.call(null, true); | |
} : undefined); | |
}, | |
keys: function (callback) { | |
chrome_storage.get(null, function (obj) { | |
// Get keys | |
var keys = [], | |
key; | |
for (key in obj) { | |
keys.push(key); | |
} | |
// Final callback | |
callback.call(null, keys, true); | |
}); | |
}, | |
size: function (callback) { | |
chrome_storage.getBytesInUse(null, function (bytes_used) { | |
// Final callback | |
callback.call(null, bytes_used, true); | |
}); | |
}, | |
clear: function (callback) { | |
chrome_storage.clear(callback ? function () { | |
// Final callback | |
callback.call(null, true); | |
} : undefined); | |
}, | |
}; | |
} | |
else if (using_gmstorage) { | |
// GM storage | |
save.userscript = { | |
get: function (key, callback) { | |
// Get value | |
var val = GM_getValue(key, undefined); | |
try { | |
val = JSON.parse(val); | |
} | |
catch (e) {} | |
callback.call(null, val, true); | |
}, | |
set: function (key, value, callback) { | |
// Set value | |
var okay = true; | |
try { | |
GM_setValue(key, JSON.stringify(value)); | |
} | |
catch (e) { | |
okay = false; | |
} | |
if (callback) callback.call(null, okay); | |
}, | |
del: function (key, callback) { | |
// Remove | |
GM_deleteValue(key); | |
if (callback) callback.call(null, true); | |
}, | |
keys: function (callback) { | |
// List keys | |
var keys = GM_listValues(); | |
callback.call(null, keys, true); | |
}, | |
size: function (callback) { | |
var keys = GM_listValues(), | |
size = 0, | |
i; | |
// Create representation | |
for (i = 0; i < keys.length; ++i) { | |
size += object_byte_size(keys[i]) + ((GM_getValue(keys[i], null) || "").length || 0); | |
} | |
// Return | |
callback.call(null, size, true); | |
}, | |
clear: function (callback) { | |
var keys = GM_listValues(), | |
i; | |
// Create representation | |
for (i = 0; i < keys.length; ++i) { | |
GM_deleteValue(keys[i]); | |
} | |
// Return | |
callback.call(null, true); | |
}, | |
}; | |
} | |
// Expose functions | |
save.set_mode(mode); | |
return save; | |
})(); |
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
Save.set("TEST", "value", function () { | |
console.log("TEST value set"); | |
}); | |
Save.get("TEST", function (value) { | |
console.log("TEST value =", value); | |
}); | |
Save.keys(function (keys) { | |
console.log(keys); | |
for (var i = 0; i < keys.length; ++i) { | |
Save.get(keys[i], function (k, value) { | |
console.log(k + " value =", value); | |
}.bind(null, keys[i])); | |
} | |
}); | |
Save.size(function (bytes) { | |
console.log("Total size: ", bytes); | |
}); | |
Save.del("TEST", function () { | |
console.log("TEST value deleted"); | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment