1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 10:17:59 +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,14 +746,13 @@ function Buffer() //{{{
// get file size // get file size
const ACCESS_READ = Ci.nsICache.ACCESS_READ; 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(/#.*$/, ""); let cacheKey = doc.location.toString().replace(/#.*$/, "");
for (let proto in util.Array.iterator(["HTTP", "FTP"])) for (let proto in util.Array.iterator(["HTTP", "FTP"]))
{ {
try try
{ {
var cacheEntryDescriptor = cacheService.createSession(proto, 0, true) var cacheEntryDescriptor = service["cache"].createSession(proto, 0, true)
.openCacheEntry(cacheKey, ACCESS_READ, false); .openCacheEntry(cacheKey, ACCESS_READ, false);
break; break;
} }

View File

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

View File

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

View File

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

View File

@@ -138,9 +138,7 @@ function Search() //{{{
var highlightObj = { var highlightObj = {
search: function (aWord, matchCase) search: function (aWord, matchCase)
{ {
var finder = Cc["@mozilla.org/embedcomp/rangefind;1"] var finder = service.getFind();
.createInstance()
.QueryInterface(Ci.nsIFind);
if (matchCase !== undefined) if (matchCase !== undefined)
finder.caseSensitive = matchCase; 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 WINDOWS = liberator.has("Win32");
const EXTENSION_NAME = config.name.toLowerCase(); // "vimperator" or "muttator" 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); 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 cwd = processDir;
var oldcwd = null; var oldcwd = null;
@@ -79,8 +76,7 @@ function IO() //{{{
var scriptNames = []; var scriptNames = [];
// default option values // default option values
var cdpath = "," + (environmentService.get("CDPATH").replace(/[:;]/g, ",") || ","); var cdpath = "," + (service["environment"].get("CDPATH").replace(/[:;]/g, ",") || ",");
var runtimepath = "~/" + (WINDOWS ? "" : ".") + EXTENSION_NAME;
var shell, shellcmdflag; var shell, shellcmdflag;
if (WINDOWS) if (WINDOWS)
@@ -92,7 +88,7 @@ function IO() //{{{
} }
else else
{ {
shell = environmentService.get("SHELL") || "sh"; shell = service["environment"].get("SHELL") || "sh";
shellcmdflag = "-c"; shellcmdflag = "-c";
} }
@@ -120,7 +116,7 @@ function IO() //{{{
let path = ioManager.getFile(head); let path = ioManager.getFile(head);
try 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) if (path.exists() && path.normalize)
path.normalize(); path.normalize();
} }
@@ -135,7 +131,7 @@ function IO() //{{{
{ {
try try
{ {
Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile).initWithPath(path); service.getFile().initWithPath(path);
return true; return true;
} }
catch (e) catch (e)
@@ -179,7 +175,7 @@ function IO() //{{{
options.add(["runtimepath", "rtp"], options.add(["runtimepath", "rtp"],
"List of directories searched for runtime files", "List of directories searched for runtime files",
"stringlist", runtimepath, "stringlist", IO.runtimePath,
{ setter: function (value) expandPathList(value) }); { setter: function (value) expandPathList(value) });
options.add(["shell", "sh"], options.add(["shell", "sh"],
@@ -410,46 +406,7 @@ function IO() //{{{
pathSeparator: WINDOWS ? "\\" : "/", pathSeparator: WINDOWS ? "\\" : "/",
expandPath: function (path) expandPath: IO.expandPath,
{
// 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");
},
// TODO: there seems to be no way, short of a new component, to change // 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 // Firefox's CWD - see // https://bugzilla.mozilla.org/show_bug.cgi?id=280953
@@ -522,7 +479,7 @@ function IO() //{{{
// also expands relative paths // also expands relative paths
getFile: function (path, noCheckPWD) getFile: function (path, noCheckPWD)
{ {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); let file = service.getFile();
if (/file:\/\//.test(path)) if (/file:\/\//.test(path))
{ {
@@ -563,7 +520,7 @@ function IO() //{{{
break; break;
} }
let file = directoryService.get("TmpD", Ci.nsIFile); let file = service["directory"].get("TmpD", Ci.nsIFile);
file.append(tmpName); file.append(tmpName);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600); file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
@@ -589,8 +546,7 @@ function IO() //{{{
while (entries.hasMoreElements()) while (entries.hasMoreElements())
{ {
let entry = entries.getNext(); let entry = entries.getNext();
entry.QueryInterface(Ci.nsIFile); array.push(entry.QueryInterface(Ci.nsIFile));
array.push(entry);
} }
if (sort) if (sort)
return array.sort(function (a, b) b.isDirectory() - a.isDirectory() || String.localeCompare(a.path, b.path)); return array.sort(function (a, b) b.isDirectory() - a.isDirectory() || String.localeCompare(a.path, b.path));
@@ -670,7 +626,7 @@ function IO() //{{{
} }
else else
{ {
let dirs = environmentService.get("PATH").split(WINDOWS ? ";" : ":"); let dirs = service["environment"].get("PATH").split(WINDOWS ? ";" : ":");
// Windows tries the cwd first TODO: desirable? // Windows tries the cwd first TODO: desirable?
if (WINDOWS) if (WINDOWS)
dirs = [io.getCurrentDirectory().path].concat(dirs); dirs = [io.getCurrentDirectory().path].concat(dirs);
@@ -688,7 +644,7 @@ lookup:
// automatically try to add the executable path extensions on windows // automatically try to add the executable path extensions on windows
if (WINDOWS) if (WINDOWS)
{ {
let extensions = environmentService.get("PATHEXT").split(";"); let extensions = service["environment"].get("PATHEXT").split(";");
for (let [,extension] in Iterator(extensions)) for (let [,extension] in Iterator(extensions))
{ {
file = joinPaths(dir, program + extension); file = joinPaths(dir, program + extension);
@@ -707,7 +663,7 @@ lookup:
return -1; return -1;
} }
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); let process = service.getProcess();
process.init(file); process.init(file);
process.run(blocking, args, args.length); process.run(blocking, args, args.length);
@@ -821,7 +777,7 @@ lookup:
liberator.echomsg("sourcing " + filename.quote(), 2); liberator.echomsg("sourcing " + filename.quote(), 2);
let str = ioManager.readFile(file); let str = ioManager.readFile(file);
let uri = ioService.newFileURI(file); let uri = service["io"].newFileURI(file);
// handle pure javascript files specially // handle pure javascript files specially
if (/\.js$/.test(filename)) 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: // vim: set fdm=marker sw=4 ts=4 et:

View File

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

View File

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

View File

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

View File

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

View File

@@ -117,7 +117,7 @@ Option.prototype = {
scope = this.scope; scope = this.scope;
} }
var aValue; let aValue;
if (liberator.has("tabs") && (scope & options.OPTION_SCOPE_LOCAL)) if (liberator.has("tabs") && (scope & options.OPTION_SCOPE_LOCAL))
aValue = tabs.options[this.name]; aValue = tabs.options[this.name];
@@ -306,7 +306,6 @@ function Options() //{{{
const SAVED = "liberator.saved."; const SAVED = "liberator.saved.";
const prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
const optionHash = {}; const optionHash = {};
const prefContexts = []; const prefContexts = [];
@@ -320,10 +319,7 @@ function Options() //{{{
} }
storage.newMap("options", false); storage.newMap("options", false);
storage.addObserver("options", optionObserver); storage.addObserver("options", optionObserver, window);
liberator.registerObserver("shutdown", function () {
storage.removeObserver("options", optionObserver);
});
function storePreference(name, value) function storePreference(name, value)
{ {
@@ -334,27 +330,27 @@ function Options() //{{{
prefContexts[prefContexts.length - 1][name] = val; prefContexts[prefContexts.length - 1][name] = val;
} }
var type = prefService.getPrefType(name); let type = service["pref"].getPrefType(name);
switch (typeof value) switch (typeof value)
{ {
case "string": case "string":
if (type == prefService.PREF_INVALID || type == prefService.PREF_STRING) if (type == service["pref"].PREF_INVALID || type == service["pref"].PREF_STRING)
prefService.setCharPref(name, value); service["pref"].setCharPref(name, value);
else if (type == prefService.PREF_INT) else if (type == service["pref"].PREF_INT)
liberator.echoerr("E521: Number required after =: " + name + "=" + value); liberator.echoerr("E521: Number required after =: " + name + "=" + value);
else else
liberator.echoerr("E474: Invalid argument: " + name + "=" + value); liberator.echoerr("E474: Invalid argument: " + name + "=" + value);
break; break;
case "number": case "number":
if (type == prefService.PREF_INVALID || type == prefService.PREF_INT) if (type == service["pref"].PREF_INVALID || type == service["pref"].PREF_INT)
prefService.setIntPref(name, value); service["pref"].setIntPref(name, value);
else else
liberator.echoerr("E474: Invalid argument: " + name + "=" + value); liberator.echoerr("E474: Invalid argument: " + name + "=" + value);
break; break;
case "boolean": case "boolean":
if (type == prefService.PREF_INVALID || type == prefService.PREF_BOOL) if (type == service["pref"].PREF_INVALID || type == service["pref"].PREF_BOOL)
prefService.setBoolPref(name, value); service["pref"].setBoolPref(name, value);
else if (type == prefService.PREF_INT) else if (type == service["pref"].PREF_INT)
liberator.echoerr("E521: Number required after =: " + name + "=" + value); liberator.echoerr("E521: Number required after =: " + name + "=" + value);
else else
liberator.echoerr("E474: Invalid argument: " + name + "=" + value); 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) if (forcedDefault != null) // this argument sets defaults for non-user settable options (like extensions.history.comp_history)
defaultValue = forcedDefault; defaultValue = forcedDefault;
let branch = defaultBranch ? prefService.getDefaultBranch("") : prefService; let branch = defaultBranch ? service["pref"].getDefaultBranch("") : service["pref"];
let type = prefService.getPrefType(name); let type = service["pref"].getPrefType(name);
try try
{ {
switch (type) switch (type)
{ {
case prefService.PREF_STRING: case service["pref"].PREF_STRING:
let value = branch.getComplexValue(name, Ci.nsISupportsString).data; let value = branch.getComplexValue(name, Ci.nsISupportsString).data;
// try in case it's a localized string (will throw an exception if not) // 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)) /^chrome:\/\/.+\/locale\/.+\.properties/.test(value))
value = branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data; value = branch.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
return value; return value;
case prefService.PREF_INT: case service["pref"].PREF_INT:
return branch.getIntPref(name); return branch.getIntPref(name);
case prefService.PREF_BOOL: case service["pref"].PREF_BOOL:
return branch.getBoolPref(name); return branch.getBoolPref(name);
default: default:
return defaultValue; return defaultValue;
@@ -439,7 +435,7 @@ function Options() //{{{
if (!args) if (!args)
{ {
var str = let str =
<table> <table>
{ {
template.map(liberator.globalVariables, function ([i, value]) { template.map(liberator.globalVariables, function ([i, value]) {
@@ -460,20 +456,20 @@ function Options() //{{{
return; return;
} }
var matches; let matches;
// 1 - type, 2 - name, 3 - +-., 4 - expr // 1 - type, 2 - name, 3 - +-., 4 - expr
if (matches = args.match(/([$@&])?([\w:]+)\s*([-+.])?=\s*(.+)/)) if (matches = args.match(/([$@&])?([\w:]+)\s*([-+.])?=\s*(.+)/))
{ {
if (!matches[1]) if (!matches[1])
{ {
var reference = liberator.variableReference(matches[2]); let reference = liberator.variableReference(matches[2]);
if (!reference[0] && matches[3]) if (!reference[0] && matches[3])
{ {
liberator.echoerr("E121: Undefined variable: " + matches[2]); liberator.echoerr("E121: Undefined variable: " + matches[2]);
return; return;
} }
var expr = liberator.evalExpression(matches[4]); let expr = liberator.evalExpression(matches[4]);
if (expr === undefined) if (expr === undefined)
{ {
liberator.echoerr("E15: Invalid expression: " + matches[4]); liberator.echoerr("E15: Invalid expression: " + matches[4]);
@@ -506,14 +502,14 @@ function Options() //{{{
// 1 - name // 1 - name
else if (matches = args.match(/^\s*([\w:]+)\s*$/)) else if (matches = args.match(/^\s*([\w:]+)\s*$/))
{ {
var reference = liberator.variableReference(matches[1]); let reference = liberator.variableReference(matches[1]);
if (!reference[0]) if (!reference[0])
{ {
liberator.echoerr("E121: Undefined variable: " + matches[1]); liberator.echoerr("E121: Undefined variable: " + matches[1]);
return; return;
} }
var value = reference[0][reference[1]]; let value = reference[0][reference[1]];
let prefix = typeof value == "number" ? "#" : let prefix = typeof value == "number" ? "#" :
typeof value == "function" ? "*" : typeof value == "function" ? "*" :
" "; " ";
@@ -567,9 +563,9 @@ function Options() //{{{
{ {
if (bang) if (bang)
{ {
var onlyNonDefault = false; let onlyNonDefault = false;
var reset = false; let reset = false;
var invertBoolean = false; let invertBoolean = false;
if (args[0] == "") if (args[0] == "")
{ {
@@ -685,7 +681,6 @@ function Options() //{{{
completer: function (context, args, modifiers) completer: function (context, args, modifiers)
{ {
let filter = context.filter; let filter = context.filter;
var optionCompletions = [];
if (args.bang) // list completions for about:config entries if (args.bang) // list completions for about:config entries
{ {
@@ -758,15 +753,15 @@ function Options() //{{{
"Delete a variable", "Delete a variable",
function (args) function (args)
{ {
//var names = args.split(/ /); //let names = args.split(/ /);
//if (typeof names == "string") names = [names]; //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 i = 0, name = names[i]; i < length; name = names[++i])
for (let [,name] in args) for (let [,name] in args)
{ {
var name = args[i]; let name = args[i];
var reference = liberator.variableReference(name); let reference = liberator.variableReference(name);
if (!reference[0]) if (!reference[0])
{ {
if (!args.bang) if (!args.bang)
@@ -791,8 +786,7 @@ function Options() //{{{
{ {
completion.setFunctionCompleter(options.get, [function () ([o.name, o.description] for (o in 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], completion.setFunctionCompleter([options.getPref, options.safeSetPref, options.setPref, options.resetPref, options.invertPref],
[function () Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch) [function () service["pref"].getChildList("", { value: 0 })
.getChildList("", { value: 0 })
.map(function (pref) [pref, ""])]); .map(function (pref) [pref, ""])]);
}); });
@@ -894,12 +888,12 @@ function Options() //{{{
if (!filter) if (!filter)
filter = ""; filter = "";
var prefArray = prefService.getChildList("", { value: 0 }); let prefArray = service["pref"].getChildList("", { value: 0 });
prefArray.sort(); prefArray.sort();
let prefs = function () { let prefs = function () {
for each (let pref in prefArray) for each (let pref in prefArray)
{ {
let userValue = prefService.prefHasUserValue(pref); let userValue = service["pref"].prefHasUserValue(pref);
if (onlyNonDefault && !userValue || pref.indexOf(filter) == -1) if (onlyNonDefault && !userValue || pref.indexOf(filter) == -1)
continue; continue;
@@ -992,13 +986,13 @@ function Options() //{{{
resetPref: function (name) resetPref: function (name)
{ {
return prefService.clearUserPref(name); return service["pref"].clearUserPref(name);
}, },
// this works only for booleans // this works only for booleans
invertPref: function (name) 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)); this.setPref(name, !this.getPref(name));
else else
liberator.echoerr("E488: Trailing characters: " + name + "!"); 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 util = modules.util;
const sleep = liberator.sleep; const sleep = liberator.sleep;
const storage = modules.storage; const storage = modules.storage;
const consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService); const consoleService = service["console"];
const ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); const ios = service["io"];
const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService); const sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
const namespace = '@namespace html "' + XHTML + '";\n' + const namespace = '@namespace html "' + XHTML + '";\n' +
'@namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";\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) function copyTab(to, from)
{ {
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
if (!from) if (!from)
from = getBrowser().mTabContainer.selectedItem; from = getBrowser().mTabContainer.selectedItem;
let tabState = ss.getTabState(from); let tabState = service["sessionStore"].getTabState(from);
ss.setTabState(to, tabState); service["sessionStore"].setTabState(to, tabState);
} }
// hide tabs initially // hide tabs initially
@@ -741,9 +739,7 @@ function Tabs() //{{{
get closedTabs() get closedTabs()
{ {
const json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON); return service["json"].decode(service["sessionStore"].getClosedTabData(window));
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
return json.decode(ss.getClosedTabData(window));
}, },
list: function (filter) list: function (filter)
@@ -846,8 +842,7 @@ function Tabs() //{{{
{ {
if (bypassCache) if (bypassCache)
{ {
const nsIWebNavigation = Ci.nsIWebNavigation; const flags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
const flags = nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
getBrowser().getBrowserForTab(tab).reloadWithFlags(flags); getBrowser().getBrowserForTab(tab).reloadWithFlags(flags);
} }
else else
@@ -971,8 +966,7 @@ function Tabs() //{{{
tab = getBrowser().mTabContainer.selectedItem; tab = getBrowser().mTabContainer.selectedItem;
window.open(); window.open();
const wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator); let win = service["windowMediator"].getMostRecentWindow("navigator:browser");
let win = wm.getMostRecentWindow("navigator:browser");
copyTab(win.getBrowser().mCurrentTab, tab); copyTab(win.getBrowser().mCurrentTab, tab);
this.remove(tab, 1, false, 1); this.remove(tab, 1, false, 1);

View File

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

View File

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

View File

@@ -34,9 +34,21 @@ default xml namespace = XHTML;
const util = { //{{{ const util = { //{{{
/**
* Array utility methods.
* @singleton
*/
Array: { 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) assocToObj: function assocToObj(assoc)
{ {
let obj = {}; let obj = {};
@@ -44,9 +56,18 @@ const util = { //{{{
return obj; 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), flatten: function flatten(ary) Array.concat.apply([], ary),
/**
* Returns an Iterator for an array's values.
*
* @returns {Iterator(Object)}
*/
iterator: function iterator(ary) iterator: function iterator(ary)
{ {
let length = ary.length; let length = ary.length;
@@ -54,6 +75,11 @@ const util = { //{{{
yield ary[i]; yield ary[i];
}, },
/**
* Returns an Iterator for the arrays indices and values.
*
* @returns {Iterator([{number}, {Object}])}
*/
iterator2: function (ary) iterator2: function (ary)
{ {
let length = ary.length; let length = ary.length;
@@ -61,6 +87,14 @@ const util = { //{{{
yield [i, ary[i]]; 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) uniq: function uniq(ary, unsorted)
{ {
let ret = []; let ret = [];
@@ -83,60 +117,11 @@ const util = { //{{{
} }
}, },
// TODO: class could have better variable names/documentation /**
Timer: function Timer(minInterval, maxInterval, callback) * Returns a shallow copy of <b>obj</b>.
{ *
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); * @param {Object} obj
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();
};
},
cloneObject: function cloneObject(obj) cloneObject: function cloneObject(obj)
{ {
if (obj instanceof Array) if (obj instanceof Array)
@@ -147,13 +132,35 @@ const util = { //{{{
return newObj; 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) clip: function clip(str, length)
{ {
return str.length <= length ? str : str.substr(0, length - 3) + "..."; 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()), 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) computedStyle: function computedStyle(node)
{ {
while (node instanceof Text && node.parentNode) 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'] // and returns an array ['www.google.com/search?q=bla', 'www.osnews.com']
stringToURLArray: function stringToURLArray(str) 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) { return urls.map(function (url) {
try 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"]; 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) function Timer(minInterval, maxInterval, callback)
{ {
let timer = Components.classes["@mozilla.org/timer;1"] let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
.createInstance(Components.interfaces.nsITimer);
this.doneAt = 0; this.doneAt = 0;
this.latest = 0; this.latest = 0;
this.notify = function (aTimer) this.notify = function (aTimer)
@@ -75,7 +79,7 @@ function Timer(minInterval, maxInterval, callback)
{ {
timer.cancel(); timer.cancel();
this.doneAt = 0; this.doneAt = 0;
}; }
this.flush = function () this.flush = function ()
{ {
if (this.latest) if (this.latest)
@@ -83,43 +87,95 @@ function Timer(minInterval, maxInterval, callback)
}; };
} }
var prefService = Components.classes["@mozilla.org/preferences-service;1"] function getFile(name)
.getService(Components.interfaces.nsIPrefService) {
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."); .getBranch("extensions.liberator.datastore.");
var json = Components.classes["@mozilla.org/dom/json;1"] var json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
.createInstance(Components.interfaces.nsIJSON);
function getCharPref(name) function getCharPref(name)
{ {
try try
{ {
return prefService.getComplexValue(name, Components.interfaces.nsISupportsString).data; return prefService.getComplexValue(name, Ci.nsISupportsString).data;
} }
catch (e) {} catch (e) {}
} }
function setCharPref(name, value) function setCharPref(name, value)
{ {
var str = Components.classes['@mozilla.org/supports-string;1'] var str = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
.createInstance(Components.interfaces.nsISupportsString);
str.data = value; str.data = value;
return prefService.setComplexValue(name, Components.interfaces.nsISupportsString, str); return prefService.setComplexValue(name, Ci.nsISupportsString, str);
} }
function loadPref(name, store, type) function loadPref(name, store, type)
{ {
if (store) if (store)
var pref = getCharPref(name); var pref = getCharPref(name);
if (!pref && storage.infoPath)
var file = readFile(getFile(name));
if (pref || file)
var result = json.decode(pref || file);
if (pref) if (pref)
var result = json.decode(pref); {
prefService.clearUserPref(name);
savePref({ name: name, store: true, serial: pref })
}
if (result instanceof type) if (result instanceof type)
return result; return result;
} }
function savePref(obj) function savePref(obj)
{ {
if (obj.store) if (obj.store && storage.infoPath)
setCharPref(obj.name, obj.serial) writeFile(getFile(obj.name), obj.serial);
} }
var prototype = { var prototype = {
@@ -253,27 +309,41 @@ var storage = {
return this.newObject(key, ArrayStore, store, Array); return this.newObject(key, ArrayStore, store, Array);
}, },
addObserver: function addObserver(key, callback) addObserver: function addObserver(key, callback, ref)
{ {
this.removeDeadObservers();
if (!(key in observers)) if (!(key in observers))
observers[key] = []; observers[key] = [];
if (observers[key].indexOf(callback) == -1) if (observers[key].indexOf(callback) == -1)
observers[key].push(callback); observers[key].push({ ref: ref && Cu.getWeakReference(ref), callback: callback });
}, },
removeObserver: function (key, callback) removeObserver: function (key, callback)
{ {
this.removeDeadObservers();
if (!(key in observers)) if (!(key in observers))
return; 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) if (observers[key].length == 0)
delete obsevers[key]; 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) fireEvent: function fireEvent(key, event, arg)
{ {
for each (callback in observers[key]) this.removeDeadObservers();
callback(key, event, arg); // Safe, since we have our own Array object here.
for each (let observer in observers[key])
observer.callback(key, event, arg);
timers[key].tell(); timers[key].tell();
}, },

View File

@@ -20,7 +20,10 @@
* IMPORTANT: renamed Startup and Quit autocmd events to VimperatorEnter and * IMPORTANT: renamed Startup and Quit autocmd events to VimperatorEnter and
VimperatorLeave respectively VimperatorLeave respectively
* IMPORTANT: 'verbose' is now by default at 1, set to 0 to not show any status messages * 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 * :hardcopy now supports output redirection to a file on Unix and MacUnix
* add ";f" extended hint mode to focus a frame * add ";f" extended hint mode to focus a frame
* add "r", "l", and "b" to 'guioptions' to toggle the scrollbars. * add "r", "l", and "b" to 'guioptions' to toggle the scrollbars.

View File

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

View File

@@ -418,16 +418,13 @@ const config = { //{{{
{ {
setter: function (value) setter: function (value)
{ {
const ioService = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService2); service.io.offline = !value;
gPrefService.setBoolPref("browser.offline", service.io.offline);
ioService.offline = !value;
gPrefService.setBoolPref("browser.offline", ioService.offline);
return value; return value;
}, },
getter: function () 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"> "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{lang=en}"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="{lang=en}">
<head> <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}" /> <meta name="generator" content="AsciiDoc {asciidoc-version}" />
<link rel="stylesheet" href="xhtml11.css" type="text/css" /> <link rel="stylesheet" href="xhtml11.css" type="text/css" />
<script type="application/x-javascript;version=1.8" src="help.js"></script>
<title>{doctitle}</title> <title>{doctitle}</title>
</head> </head>
<body> <body>
@@ -73,10 +74,10 @@ HEADER=<div style="float: right; padding-left: 1px;"> <form action="https://www.
[tags] [tags]
tag=<span class="tag">|</span> tag=<span class="tag">|</span>
key=<div class="key">|</div> key=<div class="key">|</div>
option=<span class="option">|</span> option=<a class="option" href="#">|</a>
option2=<span class="option">'|'</span> option2=<a class="option" href="#">'|'</a>
command=<span class="command">|</span> command=<a class="command" href="#">|</a>
mapping=<span class="mapping">|</span> mapping=<a class="mapping" href="#">|</a>
argument=<span class="argument">|</span> argument=<span class="argument">|</span>
argument2=<span class="argument">&#123;|&#125;</span> argument2=<span class="argument">&#123;|&#125;</span>
argument3=<span class="argument">[|]</span> argument3=<span class="argument">[|]</span>

View File

@@ -68,7 +68,7 @@ ________________________________________________________________________________
||:tabopen[!] [arg1], [arg2], ...|| + ||:tabopen[!] [arg1], [arg2], ...|| +
||t|| ||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 in a new tab. When used with [!], the 'tabopen' value of the 'activate' option
is negated. 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'| |\'rtp'| |\'runtimepath'|
||'runtimepath' 'rtp'|| stringlist ||'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: + List of directories searched for runtime files: +
macros/ + macros/ +

View File

@@ -5,20 +5,20 @@ be documented here.
section:Initialization[initialization,startup] section:Initialization[initialization,startup]
At startup Vimperator sources a user RC file, containing Ex commands, and any At startup Vimperator can perform user initialization commands. When one of
JavaScript files found in the plugin directory. The RC file may be named the following is successfully located, it is executed, and no further
[a].vimperatorrc[a] or [a]\_vimperatorrc[a]. The search order is: locations are tried.
* Unix and Mac: [a]\~/.vimperatorrc[a] then [a]\~/_vimperatorrc[a] |$VIMPERATOR_INIT|
* Windows - [a]\~/_vimperatorrc[a] then [a]\~/.vimperatorrc[a] 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. 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 plugin directory can be in any of the directories in 'runtimepath'.
the default value of 'runtimepath' this would be:
* Unix and Mac - [a]\~/.vimperator/plugin[a]
* Windows - [a]\~/vimperator/plugin[a]
All directories in 'runtimepath' are searched for plugins and they are are all All directories in 'runtimepath' are searched for plugins and they are are all
loaded. 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 * Windows - if _%HOME%_ is set then this is used, otherwise _%USERPROFILE%_ or finally
_%HOMEDRIVE%%HOMEPATH%_. _%HOMEDRIVE%%HOMEPATH%_.
_$VIMPERATOR_HOME_ can be used to override the calculated _$HOME_ directory.
section:Saving{nbsp}settings[save-settings] section:Saving{nbsp}settings[save-settings]
|:mkv| |:mkvimperatorrc| |:mkv| |:mkvimperatorrc|

View File

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