1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-23 13:52:26 +01:00

Add a storage module to persistently store, and share between windows, quickmarks, command/search history, and option values.

This commit is contained in:
Kris Maglione
2008-09-11 02:29:57 +00:00
parent 716ee80452
commit 56155a6032
6 changed files with 298 additions and 109 deletions

View File

@@ -1,5 +1,6 @@
# Firefox # Firefox
content vimperator content/ content vimperator content/
locale vimperator en-US locale/en-US/ resource vimperator content/
locale vimperator en-US locale/en-US/
skin vimperator classic/1.0 skin/ skin vimperator classic/1.0 skin/
overlay chrome://browser/content/browser.xul chrome://vimperator/content/vimperator.xul overlay chrome://browser/content/browser.xul chrome://vimperator/content/vimperator.xul

View File

@@ -790,15 +790,8 @@ liberator.QuickMarks = function () //{{{
////////////////////// PRIVATE SECTION ///////////////////////////////////////// ////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
var qmarks = {}; liberator.storage.newObject("quickmarks", true);
// TODO: move to a storage module var qmarks = liberator.storage.quickmarks;
var savedMarks = liberator.options.getPref("extensions.vimperator.quickmarks", "").split("\n");
// load the saved quickmarks
for (var i = 0; i < savedMarks.length - 1; i += 2)
{
qmarks[savedMarks[i]] = savedMarks[i + 1];
}
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}
////////////////////// MAPPINGS //////////////////////////////////////////////// ////////////////////// MAPPINGS ////////////////////////////////////////////////
@@ -899,28 +892,28 @@ liberator.QuickMarks = function () //{{{
add: function (qmark, location) add: function (qmark, location)
{ {
qmarks[qmark] = location; qmarks.set(qmark, location);
}, },
remove: function (filter) remove: function (filter)
{ {
var pattern = new RegExp("[" + filter.replace(/\s+/g, "") + "]"); var pattern = new RegExp("[" + filter.replace(/\s+/g, "") + "]");
for (var qmark in qmarks) for (var [qmark,] in qmarks)
{ {
if (pattern.test(qmark)) if (pattern.test(qmark))
delete qmarks[qmark]; qmarks.remove(qmark);
} }
}, },
removeAll: function () removeAll: function ()
{ {
qmarks = {}; qmarks.clear();
}, },
jumpTo: function (qmark, where) jumpTo: function (qmark, where)
{ {
var url = qmarks[qmark]; var url = qmarks.get(qmark);
if (url) if (url)
liberator.open(url, where); liberator.open(url, where);
@@ -934,7 +927,7 @@ liberator.QuickMarks = function () //{{{
var uppercaseMarks = []; var uppercaseMarks = [];
var numberMarks = []; var numberMarks = [];
for (var qmark in qmarks) for (var [qmark,] in qmarks)
{ {
if (/[a-z]/.test(qmark)) if (/[a-z]/.test(qmark))
lowercaseMarks.push(qmark); lowercaseMarks.push(qmark);
@@ -972,28 +965,13 @@ liberator.QuickMarks = function () //{{{
for (var i = 0; i < marks.length; i++) for (var i = 0; i < marks.length; i++)
{ {
list += "<tr><td> " + marks[i] + list += "<tr><td> " + marks[i] +
"</td><td style=\"color: green;\">" + liberator.util.escapeHTML(qmarks[marks[i]]) + "</td></tr>"; "</td><td style=\"color: green;\">" + liberator.util.escapeHTML(qmarks.get(marks[i])) + "</td></tr>";
} }
list += "</table>"; list += "</table>";
liberator.commandline.echo(list, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); liberator.commandline.echo(list, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE);
}, },
destroy: function ()
{
// save the quickmarks
var savedQuickMarks = "";
for (var i in qmarks)
{
savedQuickMarks += i + "\n";
savedQuickMarks += qmarks[i] + "\n";
}
liberator.options.setPref("extensions.vimperator.quickmarks", savedQuickMarks);
}
}; };
//}}} //}}}
}; //}}} }; //}}}

View File

@@ -1095,12 +1095,11 @@ const liberator = (function () //{{{
{ {
liberator.autocommands.trigger(liberator.config.name + "LeavePre", ""); liberator.autocommands.trigger(liberator.config.name + "LeavePre", "");
liberator.storage.saveAll();
// save our preferences // save our preferences
liberator.commandline.destroy();
liberator.options.destroy(); liberator.options.destroy();
liberator.events.destroy(); liberator.events.destroy();
if (liberator.has("quickmarks"))
liberator.quickmarks.destroy();
if (liberator.has("bookmarks")) if (liberator.has("bookmarks"))
liberator.bookmarks.destroy(); liberator.bookmarks.destroy();
@@ -1167,6 +1166,8 @@ const liberator = (function () //{{{
//}}} //}}}
})(); //}}} })(); //}}}
Components.utils.import("resource://vimperator/storage.jsi", liberator);
// called when the chrome is fully loaded and before the main window is shown // called when the chrome is fully loaded and before the main window is shown
window.addEventListener("load", liberator.startup, false); window.addEventListener("load", liberator.startup, false);
window.addEventListener("unload", liberator.shutdown, false); window.addEventListener("unload", liberator.shutdown, false);

View File

@@ -36,17 +36,17 @@ liberator.Option = function (names, description, type, defaultValue, extraInfo)
if (!extraInfo) if (!extraInfo)
extraInfo = {}; extraInfo = {};
var value = null; let cannonName = names[0];
this.name = cannonName;
this.name = names[0];
this.names = names; this.names = names;
this.type = type; this.type = type;
this.scope = (extraInfo.scope & liberator.options.OPTION_SCOPE_BOTH) || liberator.options.OPTION_SCOPE_GLOBAL; // XXX set to BOTH by default someday? - kstep this.scope = (extraInfo.scope & liberator.options.OPTION_SCOPE_BOTH) ||
liberator.options.OPTION_SCOPE_GLOBAL;
// XXX set to BOTH by default someday? - kstep
this.description = description || ""; this.description = description || "";
// "", 0 are valid default values // "", 0 are valid default values
this.defaultValue = (defaultValue === undefined) ? null : defaultValue; this.defaultValue = (defaultValue === undefined) ? null : defaultValue;
value = this.defaultValue;
this.setter = extraInfo.setter || null; this.setter = extraInfo.setter || null;
this.getter = extraInfo.getter || null; this.getter = extraInfo.getter || null;
@@ -68,6 +68,10 @@ liberator.Option = function (names, description, type, defaultValue, extraInfo)
} }
} }
this.__defineGetter__("globalvalue", function() liberator.options.store.get(cannonName));
this.__defineSetter__("globalvalue", function(val) liberator.options.store.set(cannonName, val));
this.globalvalue = this.defaultValue;
this.get = function (scope) this.get = function (scope)
{ {
if (scope) if (scope)
@@ -85,7 +89,7 @@ liberator.Option = function (names, description, type, defaultValue, extraInfo)
if (liberator.has("tabs") && (scope & liberator.options.OPTION_SCOPE_LOCAL)) if (liberator.has("tabs") && (scope & liberator.options.OPTION_SCOPE_LOCAL))
aValue = liberator.tabs.options[this.name]; aValue = liberator.tabs.options[this.name];
if ((scope & liberator.options.OPTION_SCOPE_GLOBAL) && (aValue == undefined)) if ((scope & liberator.options.OPTION_SCOPE_GLOBAL) && (aValue == undefined))
aValue = value; aValue = this.globalvalue;
if (this.getter) if (this.getter)
this.getter.call(this, aValue); this.getter.call(this, aValue);
@@ -120,7 +124,7 @@ liberator.Option = function (names, description, type, defaultValue, extraInfo)
if (liberator.has("tabs") && (scope & liberator.options.OPTION_SCOPE_LOCAL)) if (liberator.has("tabs") && (scope & liberator.options.OPTION_SCOPE_LOCAL))
liberator.tabs.options[this.name] = newValue; liberator.tabs.options[this.name] = newValue;
if (scope & liberator.options.OPTION_SCOPE_GLOBAL) if (scope & liberator.options.OPTION_SCOPE_GLOBAL)
value = newValue; this.globalvalue = newValue;
this.hasChanged = true; this.hasChanged = true;
}; };
@@ -131,7 +135,7 @@ liberator.Option = function (names, description, type, defaultValue, extraInfo)
this.hasName = function (name) this.hasName = function (name)
{ {
return this.names.some(function (e) { return e == name; }); return this.names.indexOf(name) >= 0;
}; };
this.isValidValue = function (value) this.isValidValue = function (value)
@@ -155,6 +159,8 @@ liberator.Options = function () //{{{
////////////////////// PRIVATE SECTION ///////////////////////////////////////// ////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{ /////////////////////////////////////////////////////////////////////////////{{{
liberator.storage.newObject("options", false);
var prefService = Components.classes["@mozilla.org/preferences-service;1"] var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch); .getService(Components.interfaces.nsIPrefBranch);
var options = []; var options = [];
@@ -768,8 +774,6 @@ liberator.Options = function () //{{{
{ {
for (var i = 0; i < options.length; i++) for (var i = 0; i < options.length; i++)
yield options[i]; yield options[i];
throw StopIteration;
}, },
add: function (names, description, type, defaultValue, extraInfo) add: function (names, description, type, defaultValue, extraInfo)
@@ -782,9 +786,9 @@ liberator.Options = function () //{{{
if (!option) if (!option)
return false; return false;
for (var i = 0; i < options.length; i++) for (var opt in Iterator(this))
{ {
if (options[i].name == option.name) if (opt.name == option.name)
{ {
// never replace for now // never replace for now
liberator.log("Warning: '" + names[0] + "' already exists, NOT replacing existing option.", 1); liberator.log("Warning: '" + names[0] + "' already exists, NOT replacing existing option.", 1);
@@ -832,19 +836,19 @@ liberator.Options = function () //{{{
if (!scope) if (!scope)
scope = liberator.options.OPTION_SCOPE_BOTH; scope = liberator.options.OPTION_SCOPE_BOTH;
for (var i = 0; i < options.length; i++) for (var opt in Iterator(this))
{ {
name = options[i].name; name = opt.name;
value = options[i].value; value = opt.value;
def = options[i].defaultValue; def = opt.defaultValue;
if (onlyNonDefault && value == def) if (onlyNonDefault && value == def)
continue; continue;
if (!(options[i].scope & scope)) if (!(opt.scope & scope))
continue; continue;
if (options[i].type == "boolean") if (opt.type == "boolean")
{ {
name = value ? " " + name : "no" + name; name = value ? " " + name : "no" + name;
if (value != def) if (value != def)
@@ -882,12 +886,12 @@ liberator.Options = function () //{{{
" Options ---</th></tr>"; " Options ---</th></tr>";
var name, value, defaultValue; var name, value, defaultValue;
for (var i = 0; i < prefArray.length; i++) prefArray.forEach(function (pref)
{ {
var userValue = prefService.prefHasUserValue(prefArray[i]); var userValue = prefService.prefHasUserValue(pref);
if ((!onlyNonDefault || userValue) && prefArray[i].indexOf(filter) >= 0) if ((!onlyNonDefault || userValue) && pref.indexOf(filter) >= 0)
{ {
name = prefArray[i]; name = pref;
value = this.getPref(name); value = this.getPref(name);
if (typeof value == "string") if (typeof value == "string")
value = value.substr(0, 100).replace(/\n/g, " "); value = value.substr(0, 100).replace(/\n/g, " ");
@@ -907,11 +911,13 @@ liberator.Options = function () //{{{
else else
list += "<tr><td> " + name + "=" + value + "</td></tr>"; list += "<tr><td> " + name + "=" + value + "</td></tr>";
} }
} });
list += "</table>"; list += "</table>";
liberator.commandline.echo(list, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); liberator.commandline.echo(list, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE);
}, },
get store() liberator.storage.options,
getPref: function (name, forcedDefault) getPref: function (name, forcedDefault)
{ {
return loadPreference(name, forcedDefault); return loadPreference(name, forcedDefault);

236
content/storage.jsi Normal file
View File

@@ -0,0 +1,236 @@
/***** BEGIN LICENSE BLOCK ***** {{{
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
(c) 2006-2008: Martin Stubenschrott <stubenschrott@gmx.net>
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
}}} ***** END LICENSE BLOCK *****/
var EXPORTED_SYMBOLS = ["storage"];
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var json = Components.classes["@mozilla.org/dom/json;1"]
.createInstance(Components.interfaces.nsIJSON);
function getCharPref(name)
{
try
{
var value = prefService.getComplexValue(name, Components.interfaces.nsISupportsString).data;
// try in case it's a localized string (will throw an exception if not)
if (!prefService.prefIsLocked(name) && !prefService.prefHasUserValue(name) &&
/^chrome:\/\/.+\/locale\/.+\.properties/.test(value))
value = branch.getComplexValue(name, Components.interfaces.nsIPrefLocalizedString).data;
return value;
}
catch (e)
{
return undefined;
}
}
function prefName(key) {
return "extensions.liberator.datastore." + key;
}
function loadPref(name, store, type)
{
if (store)
var pref = getCharPref(prefName(name));
if (pref)
var obj = json.decode(pref);
if (obj instanceof type)
return obj;
}
var prototype = {
fireEvent: function(event, arg) { storage.fireEvent(this.name, event, arg) },
save: function()
{
if(this.store)
prefService.setCharPref(prefName(this.name), this.serial)
},
};
function ObjectStore(name, store)
{
var object = loadPref(name, store, Object) || {};
this.__defineGetter__("store", function() store);
this.__defineGetter__("name", function() name);
this.__defineGetter__("serial", function() json.encode(object));
this.set = function set(key, val)
{
var orig = object[key];
object[key] = val;
if (orig == val)
this.fireEvent("change", key);
else
this.fireEvent("add", key);
};
this.remove = function remove(key)
{
var ret = object[key];
delete object[key];
this.fireEvent("remove", key);
return ret;
};
this.get = function get(val) object[val];
this.clear = function()
{
object = {};
};
this.__iterator__ = function() {
for (let key in object)
yield [key, object[key]];
}
}
ObjectStore.prototype = prototype;
function ArrayStore(name, store)
{
var array = loadPref(name, store, Array) || {};
this.__defineGetter__("store", function() store);
this.__defineGetter__("name", function() name);
this.__defineGetter__("serial", function() json.encode(array));
this.__defineGetter__("length", function() array.length);
this.set = function set(index, value)
{
var orig = array[index];
array[index] = value;
this.fireEvent("change", index);
};
this.push = function push(value)
{
array.push(value);
this.fireEvent("push", array.length);
};
this.pop = function pop(value)
{
var ret = array.pop();
this.fireEvent("pop", array.length);
return ret;
};
this.truncate = function truncate(length, fromEnd)
{
var ret = array.length;
if (array.length > length)
{
if(fromEnd)
array.splice(0, array.length - length);
array.length = length;
}
this.fireEvent("truncate", length);
return ret;
};
// XXX: Awkward.
this.mutate = function mutate(aFuncName)
{
var funcName = aFuncName;
arguments[0] = array;
array = Array[funcName].apply(Array, arguments);
},
this.get = function get(index)
{
return index >= 0 ? array[index] : array[array.length + index];
};
this.__iterator__ = function() {
for(let i = 0; i < array.length; i++)
yield [i, array[i]];
}
}
ArrayStore.prototype = prototype;
var keys = {};
var observers = {};
var storage = {
_addKey: function addKey(key, val)
{
if(key in this)
throw Error; // TODO: Find a better error.
keys[key] = val;
this.__defineGetter__(key, function() keys[key]);
},
newObject: function newObject(key, store)
{
// TODO: Add type checking.
if(key in keys)
return;
this._addKey(key, new ObjectStore(key, store));
},
newArray: function newArray(key, store)
{
// TODO: Add type checking.
if(key in keys)
return;
this._addKey(key, new ArrayStore(key, store));
},
addObserver: function addObserver(key, callback)
{
if(!(key in observers))
observers[key] = [];
if(observers[key].indexOf(key) >= 0)
return;
observers[key].push(callback);
},
removeObserver: function(key, callback)
{
if(!(key in observers))
return;
observers[key] = observers[key].filter(function(elem) elem != callback);
if(obsevers[key].length == 0)
delete obsevers[key];
},
fireEvent: function fireEvent(key, event, arg)
{
for each(callback in observers[key])
callback(key, event, arg);
},
saveAll: function storeAll() {
for each(key in keys)
key.store();
}
};
// vim: set fdm=marker sw=4 sts=4 et ft=javascript:

View File

@@ -43,53 +43,29 @@ liberator.CommandLine = function () //{{{
var completionlist = new liberator.InformationList("liberator-completion", { minItems: 1, maxItems: 10 }); var completionlist = new liberator.InformationList("liberator-completion", { minItems: 1, maxItems: 10 });
var completions = []; var completions = [];
liberator.storage.newArray("history-search", true);
liberator.storage.newArray("history-command", true);
// TODO: clean this up when it's not 3am... // TODO: clean this up when it's not 3am...
var history = { var history = {
get size() { return liberator.options["history"]; }, get mode() (liberator.modes.extended == liberator.modes.EX) ? "command" : "search",
get mode() { return (liberator.modes.extended == liberator.modes.EX) ? "cmd" : "search"; }, get store() liberator.storage["history-" + this.mode],
cmd: null, // ex command history get length() this.store.length,
search: null, // text search history get: function(index) this.store.get(index),
get: function () { return this[this.mode]; },
set: function (lines) { this[this.mode] = lines; },
load: function ()
{
// TODO: move to storage module
this.cmd = liberator.options.getPref("extensions.vimperator.commandline_cmd_history", "").split("\n");
this.search = liberator.options.getPref("extensions.vimperator.commandline_search_history", "").split("\n");
},
save: function ()
{
liberator.options.setPref("extensions.vimperator.commandline_cmd_history", this.cmd.join("\n"));
liberator.options.setPref("extensions.vimperator.commandline_search_history", this.search.join("\n"));
},
add: function (str) add: function (str)
{ {
if (!str) if (!str)
return; return;
var lines = this.get(); this.store.mutate('filter', function(line) line != str);
this.store.push(str);
// remove all old history lines which have this string this.store.truncate(liberator.options["history"], true);
lines = lines.filter(function (line) {
return line != str;
});
// add string to the command line history
if (lines.push(str) > this.size) // remove the first 10% of the history
lines = lines.slice(this.size / 10);
this.set(lines);
} }
}; };
history.load();
var historyIndex = UNINITIALIZED; var historyIndex = UNINITIALIZED;
var historyStart = ""; var historyStart = "";
@@ -643,8 +619,6 @@ liberator.CommandLine = function () //{{{
// user pressed UP or DOWN arrow to cycle history completion // user pressed UP or DOWN arrow to cycle history completion
else if (key == "<Up>" || key == "<Down>") else if (key == "<Up>" || key == "<Down>")
{ {
var lines = history.get();
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@@ -654,18 +628,18 @@ liberator.CommandLine = function () //{{{
// save 'start' position for iterating through the history // save 'start' position for iterating through the history
if (historyIndex == UNINITIALIZED) if (historyIndex == UNINITIALIZED)
{ {
historyIndex = lines.length; historyIndex = history.length;
historyStart = command; historyStart = command;
} }
// search the history for the first item matching the current // search the history for the first item matching the current
// commandline string // commandline string
while (historyIndex >= -1 && historyIndex <= lines.length) while (historyIndex >= -1 && historyIndex <= history.length)
{ {
key == "<Up>" ? historyIndex-- : historyIndex++; key == "<Up>" ? historyIndex-- : historyIndex++;
// user pressed DOWN when there is no newer history item // user pressed DOWN when there is no newer history item
if (historyIndex == lines.length) if (historyIndex == history.length)
{ {
setCommand(historyStart); setCommand(historyStart);
liberator.triggerCallback("change", currentExtendedMode, this.getCommand()); liberator.triggerCallback("change", currentExtendedMode, this.getCommand());
@@ -679,16 +653,16 @@ liberator.CommandLine = function () //{{{
liberator.beep(); liberator.beep();
break; break;
} }
else if (historyIndex >= lines.length + 1) else if (historyIndex >= history.length + 1)
{ {
historyIndex = lines.length; historyIndex = history.length;
liberator.beep(); liberator.beep();
break; break;
} }
if (lines[historyIndex].indexOf(historyStart) == 0) if (history.get(historyIndex).indexOf(historyStart) == 0)
{ {
setCommand(lines[historyIndex]); setCommand(history.get(historyIndex));
liberator.triggerCallback("change", currentExtendedMode, this.getCommand()); liberator.triggerCallback("change", currentExtendedMode, this.getCommand());
break; break;
} }
@@ -1094,13 +1068,6 @@ liberator.CommandLine = function () //{{{
{ {
completionIndex = historyIndex = UNINITIALIZED; completionIndex = historyIndex = UNINITIALIZED;
}, },
// it would be better if we had a destructor in javascript ...
destroy: function ()
{
history.save();
}
}; };
//}}} //}}}
}; //}}} }; //}}}