1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 06:47:58 +01:00

Merge branch 'master' into vimperator-2.1

Conflicts:
	common/content/liberator.js
This commit is contained in:
Kris Maglione
2008-12-21 16:15:16 -05:00
29 changed files with 554 additions and 410 deletions

View File

@@ -746,15 +746,14 @@ function Buffer() //{{{
// get file size
const ACCESS_READ = Ci.nsICache.ACCESS_READ;
const cacheService = Cc["@mozilla.org/network/cache-service;1"].getService(Ci.nsICacheService);
let cacheKey = doc.location.toString().replace(/#.*$/, "");
for (let proto in util.Array.iterator(["HTTP", "FTP"]))
{
try
{
var cacheEntryDescriptor = cacheService.createSession(proto, 0, true)
.openCacheEntry(cacheKey, ACCESS_READ, false);
var cacheEntryDescriptor = service["cache"].createSession(proto, 0, true)
.openCacheEntry(cacheKey, ACCESS_READ, false);
break;
}
catch (e) {}

View File

@@ -176,7 +176,7 @@ Command.prototype = {
let matches = args.match(/(.*)<<\s*(\S+)$/);
if (matches && matches[2])
{
commandline.inputMultiline(new RegExp("^" + matches[2] + "$", "m"),
commandline.inputMultiline(RegExp("^" + matches[2] + "$", "m"),
function (args) { exec(matches[1] + "\n" + args); });
return;
}

View File

@@ -128,7 +128,7 @@ function CompletionContext(editor, name, offset) //{{{
* results.
*/
this.filters = [function (item) {
let text = Array.concat(this.getKey(item, "text"));
let text = Array.concat(item.text);
for (let [i, str] in Iterator(text))
{
if (this.match(String(str)))
@@ -318,6 +318,22 @@ CompletionContext.prototype = {
get message() this._message || (this.waitingForTab ? "Waiting for <Tab>" : null),
set message(val) this._message = val,
get proto()
{
let res = {};
for (let i in Iterator(this.keys))
{
let [k, v] = i;
let _k = "_" + k;
if (typeof v == "function")
res.__defineGetter__(k, function () _k in this ? this[_k] : (this[_k] = v(this.item)));
else
res.__defineGetter__(k, function () _k in this ? this[_k] : (this[_k] = this.item[v]));
res.__defineSetter__(k, function (val) this[_k] = val);
}
return res;
},
get regenerate() this._generate && (!this.completions || !this.itemCache[this.key] || this.cache.offset != this.offset),
set regenerate(val) { if (val) delete this.itemCache[this.key] },
@@ -327,7 +343,7 @@ CompletionContext.prototype = {
this.itemCache = {};
this.cache.offset = this.offset;
if (!this.itemCache[this.key])
this.itemCache[this.key] = this._generate.call(this);
this.itemCache[this.key] = this._generate.call(this) || [];
return this.itemCache[this.key];
},
set generate(arg)
@@ -404,7 +420,8 @@ CompletionContext.prototype = {
let self = this;
delete this._substrings;
let filtered = this.filterFunc(items.map(function (item) ({ text: self.getKey({ item: item }, "text"), item: item })));
let proto = this.proto;
let filtered = this.filterFunc(items.map(function (item) ({ __proto__: proto, item: item })));
if (this.maxItems)
filtered = filtered.slice(0, this.maxItems);
@@ -658,17 +675,10 @@ function Completion() //{{{
////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
try
{
var completionService = Cc["@mozilla.org/browser/global-history;2"].getService(Ci.nsIAutoCompleteSearch);
}
catch (e) {}
const EVAL_TMP = "__liberator_eval_tmp";
function Javascript()
{
let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
const OFFSET = 0, CHAR = 1, STATEMENTS = 2, DOTS = 3, FULL_STATEMENTS = 4, COMMA = 5, FUNCTIONS = 6;
let stack = [];
let functions = [];
@@ -1334,9 +1344,9 @@ function Completion() //{{{
context.format = bookmarks.format;
for (let val in Iterator(extra || []))
{
let [k, v] = val; // Need let block here for closure.
let [k, v] = val; // Need block scope here for the closure
if (v)
context.filters.push(function (item) this._match(v, this.getKey(item, k)));
context.filters.push(function (item) this._match(v, item[k]));
}
// Need to make a copy because set completions() checks instanceof Array,
// and this may be an Array from another window.
@@ -1384,7 +1394,7 @@ function Completion() //{{{
io.getRuntimeDirectories("colors").forEach(function (dir) {
context.fork(dir.path, 0, null, function (context) {
context.filter = dir.path + io.pathSeparator + context.filter;
completion.file(context, true);
completion.file(context);
context.title = ["Color Scheme"];
context.quote = ["", function (text) text.replace(/\.vimp$/, ""), ""];
});
@@ -1404,10 +1414,10 @@ function Completion() //{{{
context.completions = config.dialogs;
},
directory: function directory(context, tail)
directory: function directory(context, full)
{
this.file(context, tail);
context.filters.push(function (item) this.getKey(item, "description") == "Directory");
this.file(context, full);
context.filters.push(function ({ item: f }) f.isDirectory());
},
environment: function environment(context)
@@ -1468,40 +1478,40 @@ function Completion() //{{{
// TODO: support file:// and \ or / path separators on both platforms
// if "tail" is true, only return names without any directory components
file: function file(context, tail)
file: function file(context, full)
{
let [dir] = context.filter.match(/^(?:.*[\/\\])?/);
// dir == "" is expanded inside readDirectory to the current dir
let [dir] = context.filter.match(/^(?:.*[\/\\])?/);
context.title = ["Path", "Type"];
if (tail)
if (!full)
context.advance(dir.length);
context.keys = { text: 0, description: 1, icon: 2 };
context.title = [full ? "Path" : "Filename", "Type"];
context.keys = {
text: !full ? "leafName" : function (f) dir + f.leafName,
description: function (f) f.isDirectory() ? "Directory" : "File",
isdir: function (f) f.isDirectory(),
icon: function (f) f.isDirectory() ? "resource://gre/res/html/folder.png"
: "moz-icon://" + f.leafName
};
context.compare = function (a, b)
b.isdir - a.isdir || String.localeCompare(a.text, b.text);
if (options["wildignore"])
{
let wigRegexp = RegExp("(^" + options.get("wildignore").values.join("|") + ")$");
context.filters.push(function ({item: f}) f.isDirectory() || !wigRegexp.test(f.leafName));
}
// context.background = true;
context.key = dir;
context.generate = function generate_file()
{
context.cache.dir = dir;
try
{
let files = io.readDirectory(dir);
if (options["wildignore"])
{
let wigRegexp = RegExp("(^" + options["wildignore"].replace(",", "|", "g") + ")$");
files = files.filter(function (f) f.isDirectory() || !wigRegexp.test(f.leafName))
}
return files.map(
function (file) [tail ? file.leafName : dir + file.leafName,
file.isDirectory() ? "Directory" : "File",
file.isDirectory() ? "resource://gre/res/html/folder.png"
: "moz-icon://" + file.leafName]
);
return io.readDirectory(dir);
}
catch (e) {}
return [];
};
},
@@ -1541,7 +1551,7 @@ function Completion() //{{{
location: function location(context)
{
if (!completionService)
if (!service["autoCompleteSearch"])
return
context.anchored = false;
context.title = ["Smart Completions"];
@@ -1557,8 +1567,8 @@ function Completion() //{{{
for (i in util.range(0, result.matchCount))
];
});
completionService.stopSearch();
completionService.startSearch(context.filter, "", context.result, {
service["autoCompleteSearch"].stopSearch();
service["autoCompleteSearch"].startSearch(context.filter, "", context.result, {
onSearchResult: function onSearchResult(search, result)
{
context.result = result;
@@ -1638,11 +1648,10 @@ function Completion() //{{{
preference: function preference(context)
{
let prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
context.anchored = false;
context.title = ["Firefox Preference", "Value"];
context.keys = { text: function (item) item, description: function (item) options.getPref(item) };
context.completions = prefs.getChildList("", { value: 0 });
context.completions = service["pref"].getChildList("", { value: 0 });
},
search: function search(context, noSuggest)
@@ -1689,12 +1698,11 @@ function Completion() //{{{
if (!context.filter)
return;
let ss = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
let engineList = (engineAliases || options["suggestengines"] || "google").split(",");
let completions = [];
engineList.forEach(function (name) {
let engine = ss.getEngineByAlias(name);
let engine = service["browserSearch"].getEngineByAlias(name);
if (!engine)
return;
let [,word] = /^\s*(\S+)/.exec(context.filter) || [];
@@ -1717,9 +1725,7 @@ function Completion() //{{{
context.title = ["Shell Command", "Path"];
context.generate = function ()
{
const environmentService = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
let dirNames = environmentService.get("PATH").split(RegExp(liberator.has("Win32") ? ";" : ":"));
let dirNames = service["environment"].get("PATH").split(RegExp(liberator.has("Win32") ? ";" : ":"));
let commands = [];
for (let [,dirName] in Iterator(dirNames))
@@ -1780,7 +1786,7 @@ function Completion() //{{{
if (tags)
context.filters.push(function (item) tags.
every(function (tag) (context.getKey(item, "tags") || []).
every(function (tag) (item.tags || []).
some(function (t) !compare(tag, t))));
context.anchored = false;
@@ -1799,8 +1805,8 @@ function Completion() //{{{
// and all that don't match the tokens.
let tokens = context.filter.split(/\s+/);
context.filters.push(function (item) tokens.every(
function (tok) contains(context.getKey(item, "url"), tok) ||
contains(context.getKey(item, "title"), tok)));
function (tok) contains(item.url, tok) ||
contains(item.title, tok)));
let re = RegExp(tokens.filter(util.identity).map(util.escapeRegex).join("|"), "g");
function highlight(item, text, i) process[i].call(this, item, template.highlightRegexp(text, re));

View File

@@ -817,13 +817,13 @@ function Events() //{{{
if (!filter)
return macros;
let re = new RegExp(filter);
let re = RegExp(filter);
return ([macro, keys] for ([macro, keys] in macros) if (re.test(macro)));
},
deleteMacros: function (filter)
{
let re = new RegExp(filter);
let re = RegExp(filter);
for (let [item,] in macros)
{
@@ -1300,7 +1300,7 @@ function Events() //{{{
let stop = true; // set to false if we should NOT consume this event but let Firefox handle it
let win = document.commandDispatcher.focusedWindow;
if (win && win.document.designMode == "on" && !config.isComposeWindow)
if (win && win.document && win.document.designMode == "on" && !config.isComposeWindow)
return false;
// menus have their own command handlers
@@ -1549,10 +1549,9 @@ function Events() //{{{
// XXX: function may later be needed to detect a canceled synchronous openURL()
onStateChange: function (webProgress, request, flags, status)
{
const nsIWebProgressListener = Ci.nsIWebProgressListener;
// STATE_IS_DOCUMENT | STATE_IS_WINDOW is important, because we also
// receive statechange events for loading images and other parts of the web page
if (flags & (nsIWebProgressListener.STATE_IS_DOCUMENT | nsIWebProgressListener.STATE_IS_WINDOW))
if (flags & (Ci.nsIWebProgressListener.STATE_IS_DOCUMENT | Ci.nsIWebProgressListener.STATE_IS_WINDOW))
{
// This fires when the load event is initiated
// only thrown for the current tab, not when another tab changes
@@ -1581,12 +1580,11 @@ function Events() //{{{
// for notifying the user about secure web pages
onSecurityChange: function (webProgress, aRequest, aState)
{
const nsIWebProgressListener = Ci.nsIWebProgressListener;
if (aState & nsIWebProgressListener.STATE_IS_INSECURE)
if (aState & Ci.nsIWebProgressListener.STATE_IS_INSECURE)
statusline.setClass("insecure");
else if (aState & nsIWebProgressListener.STATE_IS_BROKEN)
else if (aState & Ci.nsIWebProgressListener.STATE_IS_BROKEN)
statusline.setClass("broken");
else if (aState & nsIWebProgressListener.STATE_IS_SECURE)
else if (aState & Ci.nsIWebProgressListener.STATE_IS_SECURE)
statusline.setClass("secure");
},
onStatusChange: function (webProgress, request, status, message)
@@ -1646,9 +1644,8 @@ function Events() //{{{
prefObserver: {
register: function ()
{
const prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
this._branch = prefService.getBranch(""); // better way to monitor all changes?
this._branch.QueryInterface(Ci.nsIPrefBranch2);
this._branch = service["pref"].getBranch("") // better way to monitor all changes?
.QueryInterface(Ci.nsIPrefBranch2);
this._branch.addObserver("", this, false);
},

View File

@@ -138,9 +138,7 @@ function Search() //{{{
var highlightObj = {
search: function (aWord, matchCase)
{
var finder = Cc["@mozilla.org/embedcomp/rangefind;1"]
.createInstance()
.QueryInterface(Ci.nsIFind);
var finder = service.getFind();
if (matchCase !== undefined)
finder.caseSensitive = matchCase;

11
common/content/help.js Normal file
View File

@@ -0,0 +1,11 @@
const win = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher)
.activeWindow;
const liberator = win.liberator;
let page = liberator.findHelp(decodeURIComponent(document.location.search.substr(1)));
let url = "chrome://liberator/locale/" + page;
win.getBrowser().loadURIWithFlags(url, Components.interfaces.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY, null, null, null);

7
common/content/help.xul Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript;version=1.8"
src="chrome://liberator/content/help.js"/>
</window>

View File

@@ -66,12 +66,9 @@ function IO() //{{{
const WINDOWS = liberator.has("Win32");
const EXTENSION_NAME = config.name.toLowerCase(); // "vimperator" or "muttator"
const ioService = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
const environmentService = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
const directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
const downloadManager = Cc["@mozilla.org/download-manager;1"].createInstance(Ci.nsIDownloadManager);
var processDir = directoryService.get("CurWorkD", Ci.nsIFile);
var processDir = service["directory"].get("CurWorkD", Ci.nsIFile);
var cwd = processDir;
var oldcwd = null;
@@ -79,8 +76,7 @@ function IO() //{{{
var scriptNames = [];
// default option values
var cdpath = "," + (environmentService.get("CDPATH").replace(/[:;]/g, ",") || ",");
var runtimepath = "~/" + (WINDOWS ? "" : ".") + EXTENSION_NAME;
var cdpath = "," + (service["environment"].get("CDPATH").replace(/[:;]/g, ",") || ",");
var shell, shellcmdflag;
if (WINDOWS)
@@ -92,7 +88,7 @@ function IO() //{{{
}
else
{
shell = environmentService.get("SHELL") || "sh";
shell = service["environment"].get("SHELL") || "sh";
shellcmdflag = "-c";
}
@@ -120,7 +116,7 @@ function IO() //{{{
let path = ioManager.getFile(head);
try
{
path.appendRelativePath(ioManager.expandPath(tail)); // FIXME: should only expand env vars and normalise path separators
path.appendRelativePath(ioManager.expandPath(tail, true)); // FIXME: should only expand env vars and normalise path separators
if (path.exists() && path.normalize)
path.normalize();
}
@@ -135,7 +131,7 @@ function IO() //{{{
{
try
{
Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile).initWithPath(path);
service.getFile().initWithPath(path);
return true;
}
catch (e)
@@ -179,7 +175,7 @@ function IO() //{{{
options.add(["runtimepath", "rtp"],
"List of directories searched for runtime files",
"stringlist", runtimepath,
"stringlist", IO.runtimePath,
{ setter: function (value) expandPathList(value) });
options.add(["shell", "sh"],
@@ -410,46 +406,7 @@ function IO() //{{{
pathSeparator: WINDOWS ? "\\" : "/",
expandPath: function (path)
{
// TODO: proper pathname separator translation like Vim - this should be done elsewhere
if (WINDOWS)
path = path.replace("/", "\\", "g");
// expand any $ENV vars - this is naive but so is Vim and we like to be compatible
// TODO: Vim does not expand variables set to an empty string (and documents it).
// Kris reckons we shouldn't replicate this 'bug'. --djk
// TODO: should we be doing this for all paths?
function expand(path) path.replace(
!WINDOWS ? /\$(\w+)\b|\${(\w+)}/g
: /\$(\w+)\b|\${(\w+)}|%(\w+)%/g,
function (m, n1, n2, n3) environmentService.get(n1 || n2 || n3) || m
);
path = expand(path);
// expand ~
if ((WINDOWS ? /^~(?:$|\\)/ : /^~(?:$|\/)/).test(path))
{
// Try $(VIMPERATOR|MUTTATOR)_HOME || $HOME first, on all systems
let home = environmentService.get(config.name.toUpperCase() + "_HOME") ||
environmentService.get("HOME");
// Windows has its own ideosynchratic $HOME variables.
if (!home && WINDOWS)
home = environmentService.get("USERPROFILE") ||
environmentService.get("HOMEDRIVE") + environmentService.get("HOMEPATH");
path = home + path.substr(1);
}
// TODO: Vim expands paths twice, once before checking for ~, once
// after, but doesn't document it. Is this just a bug? --Kris
path = expand(path);
// FIXME: Should we be doing this here? I think it should be done
// by the arg parser or nowhere. --Kris
return path.replace("\\ ", " ", "g");
},
expandPath: IO.expandPath,
// TODO: there seems to be no way, short of a new component, to change
// Firefox's CWD - see // https://bugzilla.mozilla.org/show_bug.cgi?id=280953
@@ -522,7 +479,7 @@ function IO() //{{{
// also expands relative paths
getFile: function (path, noCheckPWD)
{
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
let file = service.getFile();
if (/file:\/\//.test(path))
{
@@ -563,7 +520,7 @@ function IO() //{{{
break;
}
let file = directoryService.get("TmpD", Ci.nsIFile);
let file = service["directory"].get("TmpD", Ci.nsIFile);
file.append(tmpName);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
@@ -589,8 +546,7 @@ function IO() //{{{
while (entries.hasMoreElements())
{
let entry = entries.getNext();
entry.QueryInterface(Ci.nsIFile);
array.push(entry);
array.push(entry.QueryInterface(Ci.nsIFile));
}
if (sort)
return array.sort(function (a, b) b.isDirectory() - a.isDirectory() || String.localeCompare(a.path, b.path));
@@ -670,7 +626,7 @@ function IO() //{{{
}
else
{
let dirs = environmentService.get("PATH").split(WINDOWS ? ";" : ":");
let dirs = service["environment"].get("PATH").split(WINDOWS ? ";" : ":");
// Windows tries the cwd first TODO: desirable?
if (WINDOWS)
dirs = [io.getCurrentDirectory().path].concat(dirs);
@@ -688,7 +644,7 @@ lookup:
// automatically try to add the executable path extensions on windows
if (WINDOWS)
{
let extensions = environmentService.get("PATHEXT").split(";");
let extensions = service["environment"].get("PATHEXT").split(";");
for (let [,extension] in Iterator(extensions))
{
file = joinPaths(dir, program + extension);
@@ -707,7 +663,7 @@ lookup:
return -1;
}
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
let process = service.getProcess();
process.init(file);
process.run(blocking, args, args.length);
@@ -821,7 +777,7 @@ lookup:
liberator.echomsg("sourcing " + filename.quote(), 2);
let str = ioManager.readFile(file);
let uri = ioService.newFileURI(file);
let uri = service["io"].newFileURI(file);
// handle pure javascript files specially
if (/\.js$/.test(filename))
@@ -965,4 +921,48 @@ lookup:
}; //}}}
IO.__defineGetter__("runtimePath", function () service["environment"].get(config.name.toUpperCase() + "_RUNTIME") ||
"~/" + (liberator.has("Win32") ? "" : ".") + config.name.toLowerCase());
IO.expandPath = function (path, relative)
{
// TODO: proper pathname separator translation like Vim - this should be done elsewhere
const WINDOWS = liberator.has("Win32");
if (WINDOWS)
path = path.replace("/", "\\", "g");
// expand any $ENV vars - this is naive but so is Vim and we like to be compatible
// TODO: Vim does not expand variables set to an empty string (and documents it).
// Kris reckons we shouldn't replicate this 'bug'. --djk
// TODO: should we be doing this for all paths?
function expand(path) path.replace(
!WINDOWS ? /\$(\w+)\b|\${(\w+)}/g
: /\$(\w+)\b|\${(\w+)}|%(\w+)%/g,
function (m, n1, n2, n3) service["environment"].get(n1 || n2 || n3) || m
);
path = expand(path);
// expand ~
if (!relative && (WINDOWS ? /^~(?:$|\\)/ : /^~(?:$|\/)/).test(path))
{
// Try $HOME first, on all systems
let home = service["environment"].get("HOME");
// Windows has its own ideosyncratic $HOME variables.
if (!home && WINDOWS)
home = service["environment"].get("USERPROFILE") ||
service["environment"].get("HOMEDRIVE") + service["environment"].get("HOMEPATH");
path = home + path.substr(1);
}
// TODO: Vim expands paths twice, once before checking for ~, once
// after, but doesn't document it. Is this just a bug? --Kris
path = expand(path);
// FIXME: Should we be doing this here? I think it should be done
// by the arg parser or nowhere. --Kris
return path.replace("\\ ", " ", "g");
};
// vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -31,7 +31,8 @@
let prefix = [BASE];
["liberator.js",
["service.js",
"liberator.js",
"config.js",
"util.js",
"style.js",

View File

@@ -51,7 +51,6 @@ const liberator = (function () //{{{
////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
const threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
function Runnable(self, func, args)
{
this.self = self;
@@ -685,18 +684,18 @@ const liberator = (function () //{{{
return false; // so you can do: if (...) return liberator.beep();
},
newThread: function () threadManager.newThread(0),
newThread: function () service["threadManager"].newThread(0),
callAsync: function (thread, self, func)
{
hread = thread || threadManager.newThread(0);
hread = thread || service["threadManager"].newThread(0);
thread.dispatch(new Runnable(self, func, Array.slice(arguments, 2)), thread.DISPATCH_NORMAL);
},
// be sure to call GUI related methods like alert() or dump() ONLY in the main thread
callFunctionInThread: function (thread, func)
{
thread = thread || threadManager.newThread(0);
thread = thread || service["threadManager"].newThread(0);
// DISPATCH_SYNC is necessary, otherwise strange things will happen
thread.dispatch(new Runnable(null, func, Array.slice(arguments, 2)), thread.DISPATCH_SYNC);
@@ -768,8 +767,7 @@ const liberator = (function () //{{{
loadScript: function (uri, context)
{
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScript(uri, context);
service["subscriptLoader"].loadSubScript(uri, context);
},
eval: function (str, context)
@@ -903,8 +901,7 @@ const liberator = (function () //{{{
// if clearFocusedElement, also blur a focused link
focusContent: function (clearFocusedElement)
{
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
if (window != ww.activeWindow)
if (window != service["windowWatcher"].activeWindow)
return;
let elem = config.mainWidget || window.content;
@@ -937,12 +934,33 @@ const liberator = (function () //{{{
hasExtension: function (name)
{
let manager = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
let extensions = manager.getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
let extensions = service["extensionManager"].getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
return extensions.some(function (e) e.name == name);
},
findHelp: function (topic)
{
let items = completion.runCompleter("help", topic);
let partialMatch = null;
function format(item) item[1] + "#" + encodeURIComponent(item[0]);
for (let [i, item] in Iterator(items))
{
if (item[0] == topic)
return format(item);
else if (partialMatch == -1 && item[0].indexOf(topic) > -1)
{
partialMatch = item;
}
}
if (partialMatch)
return format(partialMatch);
return null;
},
help: function (topic)
{
let where = (options["newtab"] && options.get("newtab").has("all", "help"))
@@ -956,43 +974,16 @@ const liberator = (function () //{{{
liberator.open("chrome://liberator/locale/" + helpFile, where);
else
liberator.echomsg("Sorry, help file " + helpFile.quote() + " not found");
return;
}
function jumpToTag(file, tag)
{
liberator.open("chrome://liberator/locale/" + file, where);
// TODO: it would be better to wait for pageLoad
setTimeout(function () {
let elem = buffer.evaluateXPath('//*[@class="tag" and text()="' + tag + '"]').snapshotItem(0);
if (elem)
buffer.scrollTo(0, elem.getBoundingClientRect().top - 10); // 10px context
else
liberator.dump('no element: ' + '@class="tag" and text()="' + tag + '"\n' );
}, 500);
}
let page = this.findHelp(topic);
if (page == null)
return liberator.echoerr("E149: Sorry, no help for " + topic);
let items = completion.runCompleter("help", topic);
let partialMatch = -1;
for (let [i, item] in Iterator(items))
{
if (item[0] == topic)
{
jumpToTag(item[1], item[0]);
return;
}
else if (partialMatch == -1 && item[0].indexOf(topic) > -1)
{
partialMatch = i;
}
}
if (partialMatch > -1)
jumpToTag(items[partialMatch][1], items[partialMatch][0]);
else
liberator.echoerr("E149: Sorry, no help for " + topic);
liberator.open("chrome://liberator/locale/" + page, where);
if (where == this.CURRENT_TAB)
content.postMessage("fragmentChange", "*");
},
globalVariables: {},
@@ -1062,8 +1053,7 @@ const liberator = (function () //{{{
if (typeof msg == "object")
msg = util.objectToString(msg, false);
const consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.logStringMessage(config.name.toLowerCase() + ": " + msg);
service["console"].logStringMessage(config.name.toLowerCase() + ": " + msg);
},
// open one or more URLs
@@ -1100,7 +1090,6 @@ const liberator = (function () //{{{
{
let url = Array.concat(urls)[0];
let postdata = Array.concat(urls)[1];
let whichwindow = window;
// decide where to load the first url
switch (where)
@@ -1121,10 +1110,9 @@ const liberator = (function () //{{{
break;
case liberator.NEW_WINDOW:
const wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
window.open();
whichwindow = wm.getMostRecentWindow("navigator:browser");
whichwindow.loadURI(url, null, postdata);
service["windowMediator"].getMostRecentWindow("navigator:browser")
.loadURI(url, null, postdata);
break;
default:
@@ -1164,11 +1152,8 @@ const liberator = (function () //{{{
else
options.setPref("browser.startup.page", 1); // start with default homepage session
const nsIAppStartup = Ci.nsIAppStartup;
if (force)
Cc["@mozilla.org/toolkit/app-startup;1"]
.getService(nsIAppStartup)
.quit(nsIAppStartup.eForceQuit);
service["appStartup"].quit(Ci.nsIAppStartup.eForceQuit);
else
window.goQuitApplication();
},
@@ -1196,31 +1181,26 @@ const liberator = (function () //{{{
restart: function ()
{
const nsIAppStartup = Ci.nsIAppStartup;
// notify all windows that an application quit has been requested.
const os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
const cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
os.notifyObservers(cancelQuit, "quit-application-requested", null);
var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
service["observer"].notifyObservers(cancelQuit, "quit-application-requested", null);
// something aborted the quit process.
if (cancelQuit.data)
return;
// notify all windows that an application quit has been granted.
os.notifyObservers(null, "quit-application-granted", null);
service["observer"].notifyObservers(null, "quit-application-granted", null);
// enumerate all windows and call shutdown handlers
const wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
let windows = wm.getEnumerator(null);
let windows = service["windowMediator"].getEnumerator(null);
while (windows.hasMoreElements())
{
let win = windows.getNext();
if (("tryToClose" in win) && !win.tryToClose())
return;
}
Cc["@mozilla.org/toolkit/app-startup;1"].getService(nsIAppStartup)
.quit(nsIAppStartup.eRestart | nsIAppStartup.eAttemptQuit);
service["appStartup"].quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
},
// TODO: move to {muttator,vimperator,...}.js
@@ -1245,6 +1225,19 @@ const liberator = (function () //{{{
config.dialogs = config.dialogs || [];
config.helpFiles = config.helpFiles || [];
try
{
let infoPath = service.getFile();
infoPath.initWithPath(IO.expandPath(IO.runtimePath.replace(/,.*/, "")));
infoPath.append("info");
infoPath.append(service["profile"].selectedProfile.name);
storage.infoPath = infoPath;
}
catch (e)
{
liberator.reportError(e);
}
liberator.triggerObserver("load");
// commands must always be the first module to be initialized
@@ -1286,18 +1279,24 @@ const liberator = (function () //{{{
// make sourcing asynchronous, otherwise commands that open new tabs won't work
setTimeout(function () {
let rcFile = io.getRCFile("~");
if (rcFile)
io.source(rcFile.path, true);
let init = service["environment"].get(config.name.toUpperCase() + "_INIT");
if (init)
liberator.execute(init);
else
liberator.log("No user RC file found", 3);
{
let rcFile = io.getRCFile("~");
if (rcFile)
io.source(rcFile.path, true);
else
liberator.log("No user RC file found", 3);
}
if (options["exrc"])
{
let localRcFile = io.getRCFile(io.getCurrentDirectory().path);
if (localRcFile)
io.source(localRcFile.path, true);
let localRCFile = io.getRCFile(io.getCurrentDirectory().path);
if (localRCFile)
io.source(localRCFile.path, true);
}
if (options["loadplugins"])
@@ -1337,7 +1336,7 @@ const liberator = (function () //{{{
sleep: function (delay)
{
let mainThread = threadManager.mainThread;
let mainThread = service["threadManager"].mainThread;
let end = Date.now() + delay;
while (Date.now() < end)
@@ -1347,8 +1346,8 @@ const liberator = (function () //{{{
callInMainThread: function (callback, self)
{
let mainThread = threadManager.mainThread;
if (!threadManager.isMainThread)
let mainThread = service["threadManager"].mainThread;
if (!service["threadManager"].isMainThread)
mainThread.dispatch({ run: callback.call(self) }, mainThread.DISPATCH_NORMAL);
else
callback.call(self);
@@ -1356,7 +1355,7 @@ const liberator = (function () //{{{
threadYield: function (flush, interruptable)
{
let mainThread = threadManager.mainThread;
let mainThread = service["threadManager"].mainThread;
liberator.interrupted = false;
do
{
@@ -1395,10 +1394,8 @@ const liberator = (function () //{{{
get windows()
{
const wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
let windows = [];
let enumerator = wm.getEnumerator("navigator:browser");
let enumerator = service["windowMediator"].getEnumerator("navigator:browser");
while (enumerator.hasMoreElements())
windows.push(enumerator.getNext());

View File

@@ -59,7 +59,7 @@ Map.prototype = {
execute: function (motion, count, argument)
{
var args = [];
let args = [];
if (this.flags & Mappings.flags.MOTION)
args.push(motion);
@@ -98,7 +98,7 @@ function Mappings() //{{{
function addMap(map, userMap)
{
var where = userMap ? user : main;
let where = userMap ? user : main;
map.modes.forEach(function (mode) {
if (!(mode in where))
where[mode] = [];
@@ -108,7 +108,7 @@ function Mappings() //{{{
function getMap(mode, cmd, stack)
{
var maps = stack[mode] || [];
let maps = stack[mode] || [];
for (let [,map] in Iterator(maps))
{
@@ -121,8 +121,8 @@ function Mappings() //{{{
function removeMap(mode, cmd)
{
var maps = user[mode] || [];
var names;
let maps = user[mode] || [];
let names;
for (let [i, map] in Iterator(maps))
{
@@ -305,7 +305,7 @@ function Mappings() //{{{
addUserMap: function (modes, keys, description, action, extra)
{
keys = keys.map(expandLeader);
var map = new Map(modes, keys, description || "User defined mapping", action, extra);
let map = new Map(modes, keys, description || "User defined mapping", action, extra);
// remove all old mappings to this key sequence
for (let [,name] in Iterator(map.names))
@@ -353,7 +353,7 @@ function Mappings() //{{{
getMapLeader: function ()
{
var leaderRef = liberator.variableReference("mapleader");
let leaderRef = liberator.variableReference("mapleader");
return leaderRef[0] ? leaderRef[0][leaderRef[1]] : "\\";
},

View File

@@ -54,13 +54,13 @@ const modes = (function () //{{{
return "-- PASS THROUGH --";
// when recording a macro
var macromode = "";
let macromode = "";
if (modes.isRecording)
macromode = "recording";
else if (modes.isReplaying)
macromode = "replaying";
var ext = "";
let ext = "";
if (extended & modes.MENU) // TODO: desirable?
ext += " (menu)";
ext += " --" + macromode;
@@ -199,7 +199,7 @@ const modes = (function () //{{{
pop: function (silent)
{
var a = modeStack.pop();
let a = modeStack.pop();
if (a)
this.set(a[0], a[1], silent);
else

View File

@@ -117,7 +117,7 @@ Option.prototype = {
scope = this.scope;
}
var aValue;
let aValue;
if (liberator.has("tabs") && (scope & options.OPTION_SCOPE_LOCAL))
aValue = tabs.options[this.name];
@@ -306,7 +306,6 @@ function Options() //{{{
const SAVED = "liberator.saved.";
const prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
const optionHash = {};
const prefContexts = [];
@@ -320,10 +319,7 @@ function Options() //{{{
}
storage.newMap("options", false);
storage.addObserver("options", optionObserver);
liberator.registerObserver("shutdown", function () {
storage.removeObserver("options", optionObserver);
});
storage.addObserver("options", optionObserver, window);
function storePreference(name, value)
{
@@ -334,27 +330,27 @@ function Options() //{{{
prefContexts[prefContexts.length - 1][name] = val;
}
var type = prefService.getPrefType(name);
let type = service["pref"].getPrefType(name);
switch (typeof value)
{
case "string":
if (type == prefService.PREF_INVALID || type == prefService.PREF_STRING)
prefService.setCharPref(name, value);
else if (type == prefService.PREF_INT)
if (type == service["pref"].PREF_INVALID || type == service["pref"].PREF_STRING)
service["pref"].setCharPref(name, value);
else if (type == service["pref"].PREF_INT)
liberator.echoerr("E521: Number required after =: " + name + "=" + value);
else
liberator.echoerr("E474: Invalid argument: " + name + "=" + value);
break;
case "number":
if (type == prefService.PREF_INVALID || type == prefService.PREF_INT)
prefService.setIntPref(name, value);
if (type == service["pref"].PREF_INVALID || type == service["pref"].PREF_INT)
service["pref"].setIntPref(name, value);
else
liberator.echoerr("E474: Invalid argument: " + name + "=" + value);
break;
case "boolean":
if (type == prefService.PREF_INVALID || type == prefService.PREF_BOOL)
prefService.setBoolPref(name, value);
else if (type == prefService.PREF_INT)
if (type == service["pref"].PREF_INVALID || type == service["pref"].PREF_BOOL)
service["pref"].setBoolPref(name, value);
else if (type == service["pref"].PREF_INT)
liberator.echoerr("E521: Number required after =: " + name + "=" + value);
else
liberator.echoerr("E474: Invalid argument: " + name + "=" + value);
@@ -370,22 +366,22 @@ function Options() //{{{
if (forcedDefault != null) // this argument sets defaults for non-user settable options (like extensions.history.comp_history)
defaultValue = forcedDefault;
let branch = defaultBranch ? prefService.getDefaultBranch("") : prefService;
let type = prefService.getPrefType(name);
let branch = defaultBranch ? service["pref"].getDefaultBranch("") : service["pref"];
let type = service["pref"].getPrefType(name);
try
{
switch (type)
{
case prefService.PREF_STRING:
case service["pref"].PREF_STRING:
let value = branch.getComplexValue(name, Ci.nsISupportsString).data;
// try in case it's a localized string (will throw an exception if not)
if (!prefService.prefIsLocked(name) && !prefService.prefHasUserValue(name) &&
if (!service["pref"].prefIsLocked(name) && !service["pref"].prefHasUserValue(name) &&
/^chrome:\/\/.+\/locale\/.+\.properties/.test(value))
value = branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
return value;
case prefService.PREF_INT:
case service["pref"].PREF_INT:
return branch.getIntPref(name);
case prefService.PREF_BOOL:
case service["pref"].PREF_BOOL:
return branch.getBoolPref(name);
default:
return defaultValue;
@@ -439,7 +435,7 @@ function Options() //{{{
if (!args)
{
var str =
let str =
<table>
{
template.map(liberator.globalVariables, function ([i, value]) {
@@ -460,20 +456,20 @@ function Options() //{{{
return;
}
var matches;
let matches;
// 1 - type, 2 - name, 3 - +-., 4 - expr
if (matches = args.match(/([$@&])?([\w:]+)\s*([-+.])?=\s*(.+)/))
{
if (!matches[1])
{
var reference = liberator.variableReference(matches[2]);
let reference = liberator.variableReference(matches[2]);
if (!reference[0] && matches[3])
{
liberator.echoerr("E121: Undefined variable: " + matches[2]);
return;
}
var expr = liberator.evalExpression(matches[4]);
let expr = liberator.evalExpression(matches[4]);
if (expr === undefined)
{
liberator.echoerr("E15: Invalid expression: " + matches[4]);
@@ -506,14 +502,14 @@ function Options() //{{{
// 1 - name
else if (matches = args.match(/^\s*([\w:]+)\s*$/))
{
var reference = liberator.variableReference(matches[1]);
let reference = liberator.variableReference(matches[1]);
if (!reference[0])
{
liberator.echoerr("E121: Undefined variable: " + matches[1]);
return;
}
var value = reference[0][reference[1]];
let value = reference[0][reference[1]];
let prefix = typeof value == "number" ? "#" :
typeof value == "function" ? "*" :
" ";
@@ -567,9 +563,9 @@ function Options() //{{{
{
if (bang)
{
var onlyNonDefault = false;
var reset = false;
var invertBoolean = false;
let onlyNonDefault = false;
let reset = false;
let invertBoolean = false;
if (args[0] == "")
{
@@ -685,7 +681,6 @@ function Options() //{{{
completer: function (context, args, modifiers)
{
let filter = context.filter;
var optionCompletions = [];
if (args.bang) // list completions for about:config entries
{
@@ -758,15 +753,15 @@ function Options() //{{{
"Delete a variable",
function (args)
{
//var names = args.split(/ /);
//let names = args.split(/ /);
//if (typeof names == "string") names = [names];
//var length = names.length;
//let length = names.length;
//for (let i = 0, name = names[i]; i < length; name = names[++i])
for (let [,name] in args)
{
var name = args[i];
var reference = liberator.variableReference(name);
let name = args[i];
let reference = liberator.variableReference(name);
if (!reference[0])
{
if (!args.bang)
@@ -791,9 +786,8 @@ function Options() //{{{
{
completion.setFunctionCompleter(options.get, [function () ([o.name, o.description] for (o in options))]);
completion.setFunctionCompleter([options.getPref, options.safeSetPref, options.setPref, options.resetPref, options.invertPref],
[function () Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch)
.getChildList("", { value: 0 })
.map(function (pref) [pref, ""])]);
[function () service["pref"].getChildList("", { value: 0 })
.map(function (pref) [pref, ""])]);
});
return {
@@ -894,12 +888,12 @@ function Options() //{{{
if (!filter)
filter = "";
var prefArray = prefService.getChildList("", { value: 0 });
let prefArray = service["pref"].getChildList("", { value: 0 });
prefArray.sort();
let prefs = function () {
for each (let pref in prefArray)
{
let userValue = prefService.prefHasUserValue(pref);
let userValue = service["pref"].prefHasUserValue(pref);
if (onlyNonDefault && !userValue || pref.indexOf(filter) == -1)
continue;
@@ -992,13 +986,13 @@ function Options() //{{{
resetPref: function (name)
{
return prefService.clearUserPref(name);
return service["pref"].clearUserPref(name);
},
// this works only for booleans
invertPref: function (name)
{
if (prefService.getPrefType(name) == prefService.PREF_BOOL)
if (service["pref"].getPrefType(name) == service["pref"].PREF_BOOL)
this.setPref(name, !this.getPref(name));
else
liberator.echoerr("E488: Trailing characters: " + name + "!");

35
common/content/service.js Normal file
View File

@@ -0,0 +1,35 @@
/** @scope modules */
let (cc = function (class, iface, meth) { try { return Cc[class][meth || "getService"](iface) } catch (e) {} })
{
/**
* Cached XPCOM services and instances.
*
* @singleton
*/
const service = {
appStartup: cc("@mozilla.org/toolkit/app-startup;1", Ci.nsIAppStartup),
autoCompleteSearch: cc("@mozilla.org/browser/global-history;2", Ci.nsIAutoCompleteSearch),
browserSearch: cc("@mozilla.org/browser/search-service;1", Ci.nsIBrowserSearchService),
cache: cc("@mozilla.org/network/cache-service;1", Ci.nsICacheService),
console: cc("@mozilla.org/consoleservice;1", Ci.nsIConsoleService),
directory: cc("@mozilla.org/file/directory_service;1", Ci.nsIProperties),
environment: cc("@mozilla.org/process/environment;1", Ci.nsIEnvironment),
extensionManager: cc("@mozilla.org/extensions/manager;1", Ci.nsIExtensionManager),
io: cc("@mozilla.org/network/io-service;1", Ci.nsIIOService).QueryInterface(Ci.nsIIOService2),
json: cc("@mozilla.org/dom/json;1", Ci.nsIJSON, "createInstance"),
observer: cc("@mozilla.org/observer-service;1", Ci.nsIObserverService),
profile: cc("@mozilla.org/toolkit/profile-service;1", Ci.nsIToolkitProfileService),
pref: cc("@mozilla.org/preferences-service;1", Ci.nsIPrefService)
.QueryInterface(Ci.nsIPrefBranch).QueryInterface(Ci.nsIPrefBranch2),
sessionStore: cc("@mozilla.org/browser/sessionstore;1", Ci.nsISessionStore),
subscriptLoader: cc("@mozilla.org/moz/jssubscript-loader;1", Ci.mozIJSSubScriptLoader),
threadManager: cc("@mozilla.org/thread-manager;1", Ci.nsIThreadManager),
windowMediator: cc("@mozilla.org/appshell/window-mediator;1", Ci.nsIWindowMediator),
windowWatcher: cc("@mozilla.org/embedcomp/window-watcher;1", Ci.nsIWindowWatcher),
getFile: function () Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile),
getFind: function () Cc["@mozilla.org/embedcomp/rangefind;1"].createInstance(Ci.nsIFind),
getProcess: function () Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess)
};
};

View File

@@ -248,8 +248,8 @@ function Styles(name, store, serial)
const util = modules.util;
const sleep = liberator.sleep;
const storage = modules.storage;
const consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
const ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
const consoleService = service["console"];
const ios = service["io"];
const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
const namespace = '@namespace html "' + XHTML + '";\n' +
'@namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";\n' +

View File

@@ -99,13 +99,11 @@ function Tabs() //{{{
function copyTab(to, from)
{
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
if (!from)
from = getBrowser().mTabContainer.selectedItem;
let tabState = ss.getTabState(from);
ss.setTabState(to, tabState);
let tabState = service["sessionStore"].getTabState(from);
service["sessionStore"].setTabState(to, tabState);
}
// hide tabs initially
@@ -741,9 +739,7 @@ function Tabs() //{{{
get closedTabs()
{
const json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
return json.decode(ss.getClosedTabData(window));
return service["json"].decode(service["sessionStore"].getClosedTabData(window));
},
list: function (filter)
@@ -846,8 +842,7 @@ function Tabs() //{{{
{
if (bypassCache)
{
const nsIWebNavigation = Ci.nsIWebNavigation;
const flags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
const flags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
getBrowser().getBrowserForTab(tab).reloadWithFlags(flags);
}
else
@@ -971,8 +966,7 @@ function Tabs() //{{{
tab = getBrowser().mTabContainer.selectedItem;
window.open();
const wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
let win = wm.getMostRecentWindow("navigator:browser");
let win = service["windowMediator"].getMostRecentWindow("navigator:browser");
copyTab(win.getBrowser().mCurrentTab, tab);
this.remove(tab, 1, false, 1);

View File

@@ -49,8 +49,8 @@ const template = {
}
else
{
var text = this.process[0].call(this, item, item.text || this.getKey(item, "text"));
var desc = this.process[1].call(this, item, this.getKey(item, "description"));
var text = this.process[0].call(this, item, item.text);
var desc = this.process[1].call(this, item, item.description);
}
// <e4x>
@@ -66,27 +66,23 @@ const template = {
},
bookmarkDescription: function (item, text)
{
let extra = this.getKey(item, "extra");
return <>
<a href={item.item.url} highlight="URL">{text}</a>&#160;
{
!(extra && extra.length) ? "" :
<span class="extra-info">
({
template.map(extra, function (e)
<>{e[0]}: <span highlight={e[2]}>{e[1]}</span></>,
<>&#xa0;</>/* Non-breaking space */)
})
</span>
}
</>
},
<>
<a href={item.item.url} highlight="URL">{text}</a>&#160;
{
!(item.extra && item.extra.length) ? "" :
<span class="extra-info">
({
template.map(item.extra, function (e)
<>{e[0]}: <span highlight={e[2]}>{e[1]}</span></>,
<>&#xa0;</>/* Non-breaking space */)
})
</span>
}
</> ,
icon: function (item, text)
{
let icon = this.getKey(item, "icon");
return <><span highlight="CompIcon">{icon ? <img src={icon}/> : <></>}</span><span class="td-strut"/>{text}</>
return <><span highlight="CompIcon">{item.icon ? <img src={item.icon}/> : <></>}</span><span class="td-strut"/>{text}</>
},
filter: function (str) <span highlight="Filter">{str}</span>,

View File

@@ -660,9 +660,8 @@ function CommandLine() //{{{
{
completer: function completer(value)
{
let ss = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
let engines = ss.getEngines({})
.filter(function (engine) engine.supportsResponseType("application/x-suggestions+json"));
let engines = service["browserSearch"].getEngines({})
.filter(function (engine) engine.supportsResponseType("application/x-suggestions+json"));
return engines.map(function (engine) [engine.alias, engine.description]);
},
@@ -809,7 +808,7 @@ function CommandLine() //{{{
command.description,
function (args)
{
var str = echoArgumentToString(args.string, true);
let str = echoArgumentToString(args.string, true);
if (str != null)
command.action(str);
},
@@ -1812,6 +1811,7 @@ function StatusLine() //{{{
}
else
{
url = url.replace(RegExp("^chrome://liberator/locale/(\\S+\\.html)#(.*)"), function (m, n1, n2) n1 + " " + decodeURIComponent(n2) + " [Help]");
url = url.replace(RegExp("^chrome://liberator/locale/(\\S+\\.html)"), "$1 [Help]");
}

View File

@@ -34,9 +34,21 @@ default xml namespace = XHTML;
const util = { //{{{
/**
* Array utility methods.
* @singleton
*/
Array: {
// [["a", "b"], ["c", "d"]] -> { a: "b", c: "d" }
// From Common Lisp, more or less
/**
* Converts an array to an object. As in lisp, an assoc is an
* array of key-value pairs, which maps directly to an object,
* as such:
* [["a", "b"], ["c", "d"]] -> { a: "b", c: "d" }
*
* @param {Array[]} assoc
* @... {string} 0 - Key
* @... 1 - Value
*/
assocToObj: function assocToObj(assoc)
{
let obj = {};
@@ -44,9 +56,18 @@ const util = { //{{{
return obj;
},
// flatten an array: [["foo", ["bar"]], ["baz"], "quux"] -> ["foo", ["bar"], "baz", "quux"]
/**
* Flatten an array, such that all elements of the array are
* joined into a single array:
* [["foo", ["bar"]], ["baz"], "quux"] -> ["foo", ["bar"], "baz", "quux"]
*/
flatten: function flatten(ary) Array.concat.apply([], ary),
/**
* Returns an Iterator for an array's values.
*
* @returns {Iterator(Object)}
*/
iterator: function iterator(ary)
{
let length = ary.length;
@@ -54,6 +75,11 @@ const util = { //{{{
yield ary[i];
},
/**
* Returns an Iterator for the arrays indices and values.
*
* @returns {Iterator([{number}, {Object}])}
*/
iterator2: function (ary)
{
let length = ary.length;
@@ -61,6 +87,14 @@ const util = { //{{{
yield [i, ary[i]];
},
/**
* Filters out all duplicates from an array. If
* <b>unsorted</b> is false, the array is sorted before
* duplicates are removed.
*
* @param {Array} ary
* @param {boolean} unsorted
*/
uniq: function uniq(ary, unsorted)
{
let ret = [];
@@ -83,60 +117,11 @@ const util = { //{{{
}
},
// TODO: class could have better variable names/documentation
Timer: function Timer(minInterval, maxInterval, callback)
{
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.doneAt = 0;
this.latest = 0;
this.notify = function (aTimer)
{
timer.cancel();
this.latest = 0;
/* minInterval is the time between the completion of the command and the next firing. */
this.doneAt = Date.now() + minInterval;
try
{
callback(this.arg);
}
finally
{
this.doneAt = Date.now() + minInterval;
}
};
this.tell = function (arg)
{
if (arg !== undefined)
this.arg = arg;
let now = Date.now();
if (this.doneAt == -1)
timer.cancel();
let timeout = minInterval;
if (now > this.doneAt && this.doneAt > -1)
timeout = 0;
else if (this.latest)
timeout = Math.min(timeout, this.latest - now);
else
this.latest = now + maxInterval;
timer.initWithCallback(this, Math.max(timeout, 0), timer.TYPE_ONE_SHOT);
this.doneAt = -1;
};
this.reset = function ()
{
timer.cancel();
this.doneAt = 0;
};
this.flush = function ()
{
if (this.latest)
this.notify();
};
},
/**
* Returns a shallow copy of <b>obj</b>.
*
* @param {Object} obj
*/
cloneObject: function cloneObject(obj)
{
if (obj instanceof Array)
@@ -147,13 +132,35 @@ const util = { //{{{
return newObj;
},
/**
* Clips a string to a given length. If the input string is longer
* than <b>length</b>, an elipsis is appended.
*
* @param {string} str
* @param {number} length
* @returns {string}
*/
clip: function clip(str, length)
{
return str.length <= length ? str : str.substr(0, length - 3) + "...";
},
/**
* Compares two strings, case insensitively. Return values are as
* in String#localeCompare.
*
* @param {string} a
* @param {string} b
* @returns {number}
*/
compareIgnoreCase: function compareIgnoreCase(a, b) String.localeCompare(a.toLowerCase(), b.toLowerCase()),
/**
* Returns an object representing a Node's computed CSS style.
*
* @param {Node} node
* @returns {Object}
*/
computedStyle: function computedStyle(node)
{
while (node instanceof Text && node.parentNode)
@@ -468,7 +475,7 @@ const util = { //{{{
// and returns an array ['www.google.com/search?q=bla', 'www.osnews.com']
stringToURLArray: function stringToURLArray(str)
{
let urls = str.split(new RegExp("\s*" + options["urlseparator"] + "\s*"));
let urls = str.split(RegExp("\s*" + options["urlseparator"] + "\s*"));
return urls.map(function (url) {
try

View File

@@ -29,10 +29,14 @@ the terms of any one of the MPL, the GPL or the LGPL.
var EXPORTED_SYMBOLS = ["storage", "Timer"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
function Timer(minInterval, maxInterval, callback)
{
let timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.doneAt = 0;
this.latest = 0;
this.notify = function (aTimer)
@@ -75,7 +79,7 @@ function Timer(minInterval, maxInterval, callback)
{
timer.cancel();
this.doneAt = 0;
};
}
this.flush = function ()
{
if (this.latest)
@@ -83,43 +87,95 @@ function Timer(minInterval, maxInterval, callback)
};
}
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService)
function getFile(name)
{
let file = storage.infoPath.clone();
file.append(name);
return file;
}
function readFile(file)
{
let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
let stream = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(Ci.nsIConverterInputStream);
try
{
fileStream.init(file, -1, 0, 0);
stream.init(fileStream, "UTF-8", 4096, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); // 4096 bytes buffering
let hunks = [];
let res = {};
while (stream.readString(4096, res) != 0)
hunks.push(res.value);
stream.close();
fileStream.close();
return hunks.join("");
}
catch (e) {}
}
function writeFile(file, data)
{
if (!file.exists())
file.create(file.NORMAL_FILE_TYPE, 0600);
let fileStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
let stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream);
fileStream.init(file, 0x20 | 0x08 | 0x02, 0600, 0); // PR_TRUNCATE | PR_CREATE | PR_WRITE
stream.init(fileStream, "UTF-8", 0, 0);
stream.writeString(data);
stream.close();
fileStream.close();
}
var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
var prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService)
.getBranch("extensions.liberator.datastore.");
var json = Components.classes["@mozilla.org/dom/json;1"]
.createInstance(Components.interfaces.nsIJSON);
var json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
function getCharPref(name)
{
try
{
return prefService.getComplexValue(name, Components.interfaces.nsISupportsString).data;
return prefService.getComplexValue(name, Ci.nsISupportsString).data;
}
catch (e) {}
}
function setCharPref(name, value)
{
var str = Components.classes['@mozilla.org/supports-string;1']
.createInstance(Components.interfaces.nsISupportsString);
var str = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
str.data = value;
return prefService.setComplexValue(name, Components.interfaces.nsISupportsString, str);
return prefService.setComplexValue(name, Ci.nsISupportsString, str);
}
function loadPref(name, store, type)
{
if (store)
var pref = getCharPref(name);
if (!pref && storage.infoPath)
var file = readFile(getFile(name));
if (pref || file)
var result = json.decode(pref || file);
if (pref)
var result = json.decode(pref);
{
prefService.clearUserPref(name);
savePref({ name: name, store: true, serial: pref })
}
if (result instanceof type)
return result;
}
function savePref(obj)
{
if (obj.store)
setCharPref(obj.name, obj.serial)
if (obj.store && storage.infoPath)
writeFile(getFile(obj.name), obj.serial);
}
var prototype = {
@@ -253,27 +309,41 @@ var storage = {
return this.newObject(key, ArrayStore, store, Array);
},
addObserver: function addObserver(key, callback)
addObserver: function addObserver(key, callback, ref)
{
this.removeDeadObservers();
if (!(key in observers))
observers[key] = [];
if (observers[key].indexOf(callback) == -1)
observers[key].push(callback);
observers[key].push({ ref: ref && Cu.getWeakReference(ref), callback: callback });
},
removeObserver: function (key, callback)
{
this.removeDeadObservers();
if (!(key in observers))
return;
observers[key] = observers[key].filter(function (elem) elem != callback);
observers[key] = observers[key].filter(function (elem) elem.callback != callback);
if (observers[key].length == 0)
delete obsevers[key];
},
removeDeadObservers: function ()
{
for (let [key, ary] in Iterator(observers))
{
observers[key] = ary = ary.filter(function (o) !o.ref || o.ref.get());
if (!ary.length)
delete observers[key];
}
},
fireEvent: function fireEvent(key, event, arg)
{
for each (callback in observers[key])
callback(key, event, arg);
this.removeDeadObservers();
// Safe, since we have our own Array object here.
for each (let observer in observers[key])
observer.callback(key, event, arg);
timers[key].tell();
},

View File

@@ -20,7 +20,10 @@
* IMPORTANT: renamed Startup and Quit autocmd events to VimperatorEnter and
VimperatorLeave respectively
* IMPORTANT: 'verbose' is now by default at 1, set to 0 to not show any status messages
* IMPORTANT: $VIMPERATOR_HOME is no longer used.
* Added ~/.vimperator/info/{profile}/, similar to viminfo
* added $VIMPERATOR_RUNTIME, $VIMPERATOR_INIT
* :hardcopy now supports output redirection to a file on Unix and MacUnix
* add ";f" extended hint mode to focus a frame
* add "r", "l", and "b" to 'guioptions' to toggle the scrollbars.

View File

@@ -59,8 +59,8 @@ function Bookmarks() //{{{
const historyService = PlacesUtils.history;
const bookmarksService = PlacesUtils.bookmarks;
const taggingService = PlacesUtils.tagging;
const searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
const searchService = service.browserSearch;
const ioService = service.io;
const faviconService = Cc["@mozilla.org/browser/favicon-service;1"].getService(Ci.nsIFaviconService);
const Bookmark = new Struct("url", "title", "icon", "keyword", "tags", "id");
@@ -236,10 +236,7 @@ function Bookmarks() //{{{
};
var cache = storage.newObject("bookmark-cache", Cache, false);
storage.addObserver("bookmark-cache", bookmarkObserver);
liberator.registerObserver("shutdown", function () {
storage.removeObserver("bookmark-cache", bookmarkObserver);
});
storage.addObserver("bookmark-cache", bookmarkObserver, window);
liberator.registerObserver("enter", function () {
if (options["preload"])
@@ -562,12 +559,12 @@ function Bookmarks() //{{{
return searchEngines;
},
getSuggestions: function getSuggestions(engine, query, callback)
getSuggestions: function getSuggestions(engineName, query, callback)
{
let ss = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
let ss = service.browserSearch;
const responseType = "application/x-suggestions+json";
let engine = ss.getEngineByAlias(engine);
let engine = ss.getEngineByAlias(engineName);
if (engine && engine.supportsResponseType(responseType))
var queryURI = engine.getSubmission(query, responseType).uri.spec;
if (!queryURI)
@@ -575,7 +572,7 @@ function Bookmarks() //{{{
function process(resp)
{
const json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
const json = service.json;
let results = [];
try
{
@@ -879,7 +876,7 @@ function History() //{{{
let items = completion.runCompleter("history", filter, maxItems);
if (items.length)
return liberator.open([i[0] for each (i in items)], liberator.NEW_TAB);
return liberator.open(items.map(function (i) i.url), liberator.NEW_TAB);
if (filter.length > 0)
liberator.echoerr("E283: No history matching \"" + filter + "\"");
@@ -1006,7 +1003,7 @@ function QuickMarks() //{{{
remove: function remove(filter)
{
var pattern = new RegExp("[" + filter.replace(/\s+/g, "") + "]");
var pattern = RegExp("[" + filter.replace(/\s+/g, "") + "]");
for (let [qmark,] in qmarks)
{

View File

@@ -418,16 +418,13 @@ const config = { //{{{
{
setter: function (value)
{
const ioService = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService2);
ioService.offline = !value;
gPrefService.setBoolPref("browser.offline", ioService.offline);
service.io.offline = !value;
gPrefService.setBoolPref("browser.offline", service.io.offline);
return value;
},
getter: function ()
{
return Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService2).offline;
return service.io.offline;
}
});

View File

@@ -10,9 +10,10 @@ email=stubenschrott@gmx.net
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{lang=en}">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+html; charset={encoding=UTF-8}" />
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset={encoding=UTF-8}" />
<meta name="generator" content="AsciiDoc {asciidoc-version}" />
<link rel="stylesheet" href="xhtml11.css" type="text/css" />
<script type="application/x-javascript;version=1.8" src="help.js"></script>
<title>{doctitle}</title>
</head>
<body>
@@ -73,10 +74,10 @@ HEADER=<div style="float: right; padding-left: 1px;"> <form action="https://www.
[tags]
tag=<span class="tag">|</span>
key=<div class="key">|</div>
option=<span class="option">|</span>
option2=<span class="option">'|'</span>
command=<span class="command">|</span>
mapping=<span class="mapping">|</span>
option=<a class="option" href="#">|</a>
option2=<a class="option" href="#">'|'</a>
command=<a class="command" href="#">|</a>
mapping=<a class="mapping" href="#">|</a>
argument=<span class="argument">|</span>
argument2=<span class="argument">&#123;|&#125;</span>
argument3=<span class="argument">[|]</span>

View File

@@ -68,7 +68,7 @@ ________________________________________________________________________________
||:tabopen[!] [arg1], [arg2], ...|| +
||t||
________________________________________________________________________________
Just like help::open[browsing.html#opening], but opens the resulting web page(s)
Just like [c]:open[c], but opens the resulting web page(s)
in a new tab. When used with [!], the 'tabopen' value of the 'activate' option
is negated.
________________________________________________________________________________

View File

@@ -0,0 +1,27 @@
function checkFragment()
{
let frag = document.location.hash.substr(1);
if (!frag || document.getElementById(frag))
return;
let elem = document.evaluate('//*[@class="tag" and text()="' + frag + '"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);
if (elem)
window.content.scrollTo(0, elem.getBoundingClientRect().top - 10); // 10px context
}
document.addEventListener("load", checkFragment, true);
window.addEventListener("message", function (event) {
if (event.data == "fragmentChange")
checkFragment();
}, true);
document.addEventListener("click", function (event) {
let elem = event.target;
if (/^(option|mapping|command)$/.test(elem.className))
var tag = elem.textContent.replace(/\s.*/, "");
if (elem.className == "command")
tag = tag.replace(/\[.*?\]/g, "");
if (tag)
elem.href = "chrome://liberator/content/help.xul?" + encodeURIComponent(tag);
}, true);

View File

@@ -590,10 +590,11 @@ match being used. The patterns are case insensitive regular expressions.
____
|$VIMPERATOR_RUNTIME|
|\'rtp'| |\'runtimepath'|
||'runtimepath' 'rtp'|| stringlist
____
(default: Unix, Mac: "\~/.vimperator", Windows: "\~/vimperator")
(default: \'$VIMPERATOR_RUNTIME' or Unix, Mac: "\~/.vimperator", Windows: "\~/vimperator")
List of directories searched for runtime files: +
macros/ +

View File

@@ -5,20 +5,20 @@ be documented here.
section:Initialization[initialization,startup]
At startup Vimperator sources a user RC file, containing Ex commands, and any
JavaScript files found in the plugin directory. The RC file may be named
[a].vimperatorrc[a] or [a]\_vimperatorrc[a]. The search order is:
At startup Vimperator can perform user initialization commands. When one of
the following is successfully located, it is executed, and no further
locations are tried.
* Unix and Mac: [a]\~/.vimperatorrc[a] then [a]\~/_vimperatorrc[a]
* Windows - [a]\~/_vimperatorrc[a] then [a]\~/.vimperatorrc[a]
|$VIMPERATOR_INIT|
1. _$VIMPERATOR_INIT_ - May contain a single ex command, usually
[c]:source {file}[c].
2. [a]\~/_vimperatorrc[a] - Windows only. If this file exists, its contents
are executed.
3. [a]\~/.vimperatorrc[a] - If this file exists, its contents are executed.
If 'exrc' is set then any RC file in the current directory is also sourced.
The plugin directory can be in any of the directories in 'runtimepath'. Using
the default value of 'runtimepath' this would be:
* Unix and Mac - [a]\~/.vimperator/plugin[a]
* Windows - [a]\~/vimperator/plugin[a]
The plugin directory can be in any of the directories in 'runtimepath'.
All directories in 'runtimepath' are searched for plugins and they are are all
loaded.
@@ -31,8 +31,6 @@ The user's \'$HOME'(~) directory is determined as follows:
* Windows - if _%HOME%_ is set then this is used, otherwise _%USERPROFILE%_ or finally
_%HOMEDRIVE%%HOMEPATH%_.
_$VIMPERATOR_HOME_ can be used to override the calculated _$HOME_ directory.
section:Saving{nbsp}settings[save-settings]
|:mkv| |:mkvimperatorrc|

View File

@@ -335,6 +335,14 @@ fieldset.paypal {
font-weight: bold;
color: #106326;
}
.option, .mapping, .command {
text-decoration: none;
}
.option:hover, .mapping:hover, .command:hover {
text-decoration: underline;
}
.quoteblock {
margin-left: 140px;
padding-bottom: 10px;