Skip to content

Instantly share code, notes, and snippets.

@nutbread

nutbread/Save.js Secret

Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nutbread/ac22d7f9419c55e3f96f to your computer and use it in GitHub Desktop.
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
/**
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;
})();
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