);
commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
},
diff --git a/common/content/dactyl-overlay.js b/common/content/dactyl-overlay.js
index d7a00b41..32f23e9a 100644
--- a/common/content/dactyl-overlay.js
+++ b/common/content/dactyl-overlay.js
@@ -60,7 +60,6 @@
prefix.unshift("chrome://" + modules.Config.prototype.name.toLowerCase() + "/content/");
modules.Config.prototype.scripts.forEach(load);
-
})();
// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/content/dactyl.js b/common/content/dactyl.js
index fa6c91f1..f2912149 100644
--- a/common/content/dactyl.js
+++ b/common/content/dactyl.js
@@ -73,11 +73,11 @@ const Dactyl = Module("dactyl", {
},
destroy: function () {
- autocommands.trigger(config.name + "LeavePre", {});
+ autocommands.trigger("LeavePre", {});
storage.saveAll();
dactyl.triggerObserver("shutdown", null);
dactyl.dump("All dactyl modules destroyed\n");
- autocommands.trigger(config.name + "Leave", {});
+ autocommands.trigger("Leave", {});
},
/**
@@ -682,11 +682,12 @@ const Dactyl = Module("dactyl", {
return;
}
- dactyl.echomsg('Searching for "plugin/**/*.{js,vimp}" in "'
- + [dir.path.replace(/.plugin$/, "") for ([, dir] in Iterator(dirs))].join(",") + '"', 2);
+ dactyl.echomsg('Searching for "plugin/**/*.{js,vimp}" in '
+ + [dir.path.replace(/.plugin$/, "") for ([, dir] in Iterator(dirs))]
+ .join(",").quote(), 2);
dirs.forEach(function (dir) {
- dactyl.echomsg("Searching for \"" + (dir.path + "/**/*.{js,vimp}") + "\"", 3);
+ dactyl.echomsg("Searching for " + (dir.path + "/**/*.{js,vimp}").quote(), 3);
sourceDirectory(dir);
});
},
@@ -735,11 +736,6 @@ const Dactyl = Module("dactyl", {
* @returns {boolean}
*/
open: function (urls, params, force) {
- // convert the string to an array of converted URLs
- // -> see dactyl.stringToURLArray for more details
- //
- // This is strange. And counterintuitive. Is it really
- // necessary? --Kris
if (typeof urls == "string")
urls = dactyl.stringToURLArray(urls);
@@ -867,7 +863,7 @@ const Dactyl = Module("dactyl", {
urls = [str];
return urls.map(function (url) {
- if (/^\.?\//.test(url)) {
+ if (/^[.~]?\//.test(url)) {
try {
// Try to find a matching file.
let file = io.File(url);
@@ -1176,7 +1172,7 @@ const Dactyl = Module("dactyl", {
else
styles.removeSheet(true, "scrollbar");
options.safeSetPref("layout.scrollbar.side", opts.indexOf("l") >= 0 ? 3 : 2,
- "See 'guioptions' scrollbar flags.");
+ "See 'guioptions' scrollbar flags.");
},
validator: function (opts) (opts.indexOf("l") < 0 || opts.indexOf("r") < 0)
},
@@ -1271,7 +1267,7 @@ const Dactyl = Module("dactyl", {
{
setter: function (value) {
options.safeSetPref("accessibility.typeaheadfind.enablesound", !value,
- "See 'visualbell' option");
+ "See 'visualbell' option");
return value;
}
});
@@ -1444,7 +1440,7 @@ const Dactyl = Module("dactyl", {
else if (file.isReadable() && file.isFile())
AddonManager.getInstallForFile(file, callResult("install"), "application/x-xpinstall");
else if (file.isDirectory())
- dactyl.echomsg("Cannot install a directory: \"" + file.path + "\"", 0);
+ dactyl.echomsg("Cannot install a directory: " + file.path.quote(), 0);
else
dactyl.echoerr("E484: Can't open file " + file.path);
}, {
@@ -1552,7 +1548,7 @@ const Dactyl = Module("dactyl", {
}
else {
if (filter)
- dactyl.echoerr("Exxx: No extension matching \"" + filter + "\"");
+ dactyl.echoerr("Exxx: No extension matching " + filter.quote());
else
dactyl.echoerr("No extensions installed");
}
@@ -1953,7 +1949,7 @@ const Dactyl = Module("dactyl", {
});
dactyl.triggerObserver("enter", null);
- autocommands.trigger(config.name + "Enter", {});
+ autocommands.trigger("Enter", {});
}, 0);
statusline.update();
diff --git a/common/content/finder.js b/common/content/finder.js
index 9fd72cca..5f139efc 100644
--- a/common/content/finder.js
+++ b/common/content/finder.js
@@ -18,7 +18,7 @@ const RangeFinder = Module("rangefinder", {
let backwards = mode == modes.FIND_BACKWARD;
commandline.open(backwards ? "?" : "/", "", mode);
- if (this.rangeFind)
+ if (this.rangeFind && this.rangeFind.window.get() == window)
this.rangeFind.reset();
this.find("", backwards);
},
@@ -28,6 +28,7 @@ const RangeFinder = Module("rangefinder", {
this.rangeFind = null;
let highlighted = this.rangeFind && this.rangeFind.highlighted;
+ let selections = this.rangeFind && this.rangeFind.selections;
let matchCase = !(options["ignorecase"] || options["smartcase"] && !/[A-Z]/.test(str));
let linksOnly = options["linksearch"];
@@ -45,15 +46,19 @@ const RangeFinder = Module("rangefinder", {
return "";
});
- // It's possible, with :tabdetach, for the rangeFind to actually move
- // from one window to another, which breaks things.
- if (!this.rangeFind || this.rangeFind.window.get() != window ||
- linksOnly ^ !!this.rangeFind.elementPath ||
- matchCase ^ this.rangeFind.matchCase || backward ^ this.rangeFind.reverse) {
+ // It's possible, with :tabdetach for instance, for the rangeFind to
+ // actually move from one window to another, which breaks things.
+ if (!this.rangeFind
+ || this.rangeFind.window.get() != window
+ || linksOnly != !!this.rangeFind.elementPath
+ || matchCase != this.rangeFind.matchCase
+ || !!backward != this.rangeFind.reverse) {
+
if (this.rangeFind)
this.rangeFind.cancel();
this.rangeFind = RangeFind(matchCase, backward, linksOnly && options["hinttags"]);
this.rangeFind.highlighted = highlighted;
+ this.rangeFind.selections = selections;
}
return str;
},
@@ -71,15 +76,15 @@ const RangeFinder = Module("rangefinder", {
this.find(this.lastSearchPattern);
else if (!this.rangeFind.search(null, reverse))
dactyl.echoerr("E486: Pattern not found: " + this.lastSearchPattern);
- else if (this.rangeFind.wrapped) {
- // hack needed, because wrapping causes a "scroll" event which clears
- // our command line
+ else if (this.rangeFind.wrapped)
+ // hack needed, because wrapping causes a "scroll" event which
+ // clears our command line
this.setTimeout(function () {
let msg = this.rangeFind.backward ? "search hit TOP, continuing at BOTTOM"
: "search hit BOTTOM, continuing at TOP";
- commandline.echo(msg, commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES);
+ commandline.echo(msg, commandline.HL_WARNINGMSG,
+ commandline.APPEND_TO_MESSAGES | commandline.FORCE_SINGLELINE);
}, 0);
- }
else
commandline.echo((this.rangeFind.backward ? "?" : "/") + this.lastSearchPattern, null, commandline.FORCE_SINGLELINE);
@@ -197,6 +202,10 @@ const RangeFinder = Module("rangefinder", {
modes.addMode("FIND_BACKWARD", true);
},
options: function () {
+ options.safeSetPref("accessibility.typeaheadfind.autostart", false);
+ // The above should be sufficient, but: https://bugzilla.mozilla.org/show_bug.cgi?id=348187
+ options.safeSetPref("accessibility.typeaheadfind", false);
+
options.add(["hlsearch", "hls"],
"Highlight previous search pattern matches",
"boolean", "false", {
@@ -267,27 +276,31 @@ const RangeFind = Class("RangeFind", {
this.reset();
this.highlighted = null;
+ this.selections = [];
this.lastString = "";
},
+ get backward() this.finder.findBackwards,
+
+ get searchString() this.lastString,
+
get selectedRange() {
- let range = RangeFind.Range(tabs.localStore.focusedFrame || content);
- return (range.selection.rangeCount ? range.selection.getRangeAt(0) : this.ranges[0].range).cloneRange();
+ let selection = (tabs.localStore.focusedFrame || content).getSelection();
+ return (selection.rangeCount ? selection.getRangeAt(0) : this.ranges[0].range).cloneRange();
+ },
+ set selectedRange(range) {
+ this.range.selection.removeAllRanges();
+ this.range.selection.addRange(range);
+ this.range.selectionController.scrollSelectionIntoView(
+ this.range.selectionController.SELECTION_NORMAL, 0, false);
},
- reset: function () {
- this.startRange = this.selectedRange;
- this.startRange.collapse(!this.reverse);
- this.lastRange = this.selectedRange;
- this.range = this.findRange(this.startRange);
- this.ranges.first = this.range;
- this.ranges.forEach(function (range) range.save());
- this.forward = null;
- this.found = false;
+ cancel: function () {
+ this.purgeListeners();
+ this.range.deselect();
+ this.range.descroll();
},
- sameDocument: function (r1, r2) r1 && r2 && r1.endContainer.ownerDocument == r2.endContainer.ownerDocument,
-
compareRanges: function (r1, r2)
this.backward ? r1.compareBoundaryPoints(Range.END_TO_START, r2)
: -r1.compareBoundaryPoints(Range.START_TO_END, r2),
@@ -296,9 +309,7 @@ const RangeFind = Class("RangeFind", {
let doc = range.startContainer.ownerDocument;
let win = doc.defaultView;
let ranges = this.ranges.filter(function (r)
- r.window == win &&
- r.range.compareBoundaryPoints(Range.START_TO_END, range) >= 0 &&
- r.range.compareBoundaryPoints(Range.END_TO_START, range) <= 0);
+ r.window == win && RangeFind.contains(r.range, range));
if (this.backward)
return ranges[ranges.length - 1];
@@ -308,10 +319,8 @@ const RangeFind = Class("RangeFind", {
findSubRanges: function (range) {
let doc = range.startContainer.ownerDocument;
for (let elem in util.evaluateXPath(this.elementPath, doc)) {
- let r = doc.createRange();
- r.selectNode(elem);
- if (range.compareBoundaryPoints(Range.START_TO_END, r) >= 0 &&
- range.compareBoundaryPoints(Range.END_TO_START, r) <= 0)
+ let r = RangeFind.nodeRange(elem);
+ if (RangeFind.contains(range, r))
yield r;
}
},
@@ -322,7 +331,62 @@ const RangeFind = Class("RangeFind", {
this.lastRange.commonAncestorContainer).snapshotItem(0);
if(node) {
node.focus();
- this.search(null, false); // Rehighlight collapsed range
+ // Rehighlight collapsed selection
+ this.selectedRange = this.lastRange;
+ }
+ },
+
+ highlight: function (clear) {
+
+ if (!clear && (!this.lastString || this.lastString == this.highlighted))
+ return;
+ if (clear && !this.highlighted)
+ return;
+
+ if (!clear && this.highlighted)
+ this.highlight(true);
+
+ if (clear) {
+ this.selections.forEach(function (selection) {
+ selection.removeAllRanges();
+ });
+ this.selections = [];
+ this.highlighted = null;
+ }
+ else {
+ this.selections = [];
+ let string = this.lastString;
+ for (let r in this.iter(string)) {
+ let controller = this.range.selectionController;
+ for (let node=r.startContainer; node; node=node.parentNode)
+ if (node instanceof Ci.nsIDOMNSEditableElement) {
+ controller = node.editor.selectionController;
+ break;
+ }
+
+ let sel = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
+ sel.addRange(r);
+ if (this.selections.indexOf(sel) < 0)
+ this.selections.push(sel);
+ }
+ this.highlighted = this.lastString;
+ this.selectedRange = this.lastRange;
+ this.addListeners();
+ }
+ },
+
+ iter: function (word) {
+ let saved = ["range", "lastRange", "lastString"].map(function (s) [s, this[s]], this);
+ try {
+ this.range = this.ranges[0];
+ this.lastRange = null;
+ this.lastString = word;
+ var res;
+ while ((res = this.search(null, this.reverse, true)))
+ yield res;
+ }
+ finally {
+ saved.forEach(function ([k, v]) this[k] = v, this);
}
},
@@ -334,8 +398,7 @@ const RangeFind = Class("RangeFind", {
function pushRange(start, end) {
function push(r) {
- r = RangeFind.Range(r, frames.length);
- if (r)
+ if (r = RangeFind.Range(r, frames.length))
frames.push(r);
}
@@ -351,18 +414,19 @@ const RangeFind = Class("RangeFind", {
}
function rec(win) {
let doc = win.document;
- let pageRange = doc.createRange();
- pageRange.selectNode(doc.body || doc.documentElement.lastChild);
+ let pageRange = RangeFind.nodeRange(doc.body || doc.documentElement.lastChild);
backup = backup || pageRange;
let pageStart = RangeFind.endpoint(pageRange, true);
let pageEnd = RangeFind.endpoint(pageRange, false);
for (let frame in util.Array.itervalues(win.frames)) {
let range = doc.createRange();
- range.selectNode(frame.frameElement);
- pushRange(pageStart, RangeFind.endpoint(range, true));
- pageStart = RangeFind.endpoint(range, false);
- rec(frame);
+ if (util.computedStyle(frame.frameElement).visibility == "visible") {
+ range.selectNode(frame.frameElement);
+ pushRange(pageStart, RangeFind.endpoint(range, true));
+ pageStart = RangeFind.endpoint(range, false);
+ rec(frame);
+ }
}
pushRange(pageStart, pageEnd);
}
@@ -372,6 +436,17 @@ const RangeFind = Class("RangeFind", {
return frames;
},
+ reset: function () {
+ this.startRange = this.selectedRange;
+ this.startRange.collapse(!this.reverse);
+ this.lastRange = this.selectedRange;
+ this.range = this.findRange(this.startRange);
+ this.ranges.first = this.range;
+ this.ranges.forEach(function (range) range.save());
+ this.forward = null;
+ this.found = false;
+ },
+
// This doesn't work yet.
resetCaret: function () {
let equal = RangeFind.equal;
@@ -406,24 +481,6 @@ const RangeFind = Class("RangeFind", {
return null;
},
- get searchString() this.lastString,
- get backward() this.finder.findBackwards,
-
- iter: function (word) {
- let saved = ["range", "lastRange", "lastString"].map(this.closure(function (s) [s, this[s]]));
- try {
- this.range = this.ranges[0];
- this.lastRange = null;
- this.lastString = word;
- var res;
- while ((res = this.search(null, this.reverse, true)))
- yield res;
- }
- finally {
- saved.forEach(function ([k, v]) this[k] = v, this);
- }
- },
-
search: function (word, reverse, private_) {
if (!private_ && this.lastRange && !RangeFind.equal(this.selectedRange, this.lastRange))
this.reset();
@@ -450,110 +507,57 @@ const RangeFind = Class("RangeFind", {
else {
function indices() {
let idx = this.range.index;
- for (let i in this.backward ? util.range(idx + 1, 0, -1) : util.range(idx, this.ranges.length))
- yield i;
- if (private_)
- return;
- this.wrapped = true;
- this.lastRange = null;
- for (let i in this.backward ? util.range(this.ranges.length, idx, -1) : util.range(0, idx + 1))
+ if (this.backward)
+ var groups = [util.range(idx + 1, 0, -1), util.range(this.ranges.length, idx, -1)];
+ else
+ var groups = [util.range(idx, this.ranges.length), util.range(0, idx + 1)];
+
+ for (let i in groups[0])
yield i;
+
+ if (!private_) {
+ this.wrapped = true;
+ this.lastRange = null;
+ for (let i in groups[1])
+ yield i;
+ }
}
for (let i in indices.call(this)) {
+ if (!private_ && this.range.window != this.ranges[i].window && this.range.window != this.ranges[i].window.parent) {
+ this.range.descroll();
+ this.range.deselect();
+ }
this.range = this.ranges[i];
- let start = this.sameDocument(this.lastRange, this.range.range) && this.range.intersects(this.lastRange) ?
- RangeFind.endpoint(this.lastRange, !(again ^ this.backward)) :
- RangeFind.endpoint(this.range.range, !this.backward);;
+ let start = RangeFind.sameDocument(this.lastRange, this.range.range) && this.range.intersects(this.lastRange) ?
+ RangeFind.endpoint(this.lastRange, !(again ^ this.backward)) :
+ RangeFind.endpoint(this.range.range, !this.backward);;
+
if (this.backward && !again)
start = RangeFind.endpoint(this.startRange, false);
var range = this.finder.Find(word, this.range.range, start, this.range.range);
if (range)
break;
- if (!private_) {
- this.range.descroll();
- this.range.deselect();
- }
}
}
if (range)
this.lastRange = range.cloneRange();
- if (private_)
- return range;
-
- this.lastString = word;
- if (range == null) {
- this.cancel();
- this.found = false;
- return null;
+ if (!private_) {
+ this.lastString = word;
+ if (range == null) {
+ this.cancel();
+ this.found = false;
+ return null;
+ }
+ this.found = true;
}
- this.range.selection.removeAllRanges();
- this.range.selection.addRange(range);
- this.range.selectionController.scrollSelectionIntoView(
- this.range.selectionController.SELECTION_NORMAL, 0, false);
- this.found = true;
+ if (range && (!private_ || private_ < 0))
+ this.selectedRange = range;
return range;
},
- highlight: function (clear) {
-
- if (!clear && (!this.lastString || this.lastString == this.highlighted))
- return;
-
- if (!clear && this.highlighted)
- this.highlight(true);
-
- if (clear && !this.highlighted)
- return;
-
- let span = util.xmlToDom(, this.range.document);
-
- function highlight(range) {
- let startContainer = range.startContainer;
- let startOffset = range.startOffset;
- let node = startContainer.ownerDocument.importNode(span, true);
-
- let docfrag = range.extractContents();
- let before = startContainer.splitText(startOffset);
- let parent = before.parentNode;
- node.appendChild(docfrag);
- parent.insertBefore(node, before);
- range.selectNode(node);
- }
-
- function unhighlight(range) {
- let elem = range.startContainer;
- while (!(elem instanceof Element) && elem.parentNode)
- elem = elem.parentNode;
- if (elem.getAttributeNS(NS.uri, "highlight") != "Search")
- return;
-
- let docfrag = range.extractContents();
-
- let parent = elem.parentNode;
- parent.replaceChild(docfrag, elem);
- parent.normalize();
- }
-
- let action = clear ? unhighlight : highlight;
- let string = this[clear ? "highlighted" : "lastString"];
- for (let r in this.iter(string)) {
- action(r);
- this.lastRange = r;
- }
- if (clear) {
- this.highlighted = null;
- this.purgeListeners();
- }
- else {
- this.highlighted = this.lastString;
- this.addListeners();
- this.search(null, false); // Rehighlight collapsed range
- }
- },
-
addListeners: function () {
for (let range in values(this.ranges))
range.window.addEventListener("unload", this.closure.onUnload, true);
@@ -562,32 +566,23 @@ const RangeFind = Class("RangeFind", {
for (let range in values(this.ranges))
range.window.removeEventListener("unload", this.closure.onUnload, true);
},
-
onUnload: function (event) {
this.purgeListeners();
if (this.highlighted)
this.highlight(false);
this.stale = true;
- },
-
- cancel: function () {
- this.purgeListeners();
- this.range.deselect();
- this.range.descroll();
}
}, {
Range: Class("RangeFind.Range", {
init: function (range, index) {
- if (range instanceof Ci.nsIDOMWindow) { // Kludge
- this.document = range.document;
- return;
- }
-
this.index = index;
- this.document = range.startContainer.ownerDocument;
- this.window = this.document.defaultView;
this.range = range;
+ this.document = range.startContainer.ownerDocument;
+ this.window = this.document.defaultView;
+ this.docShell = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell);
if (this.selection == null)
return false;
@@ -617,14 +612,6 @@ const RangeFind = Class("RangeFind", {
this.selection.addRange(this.initialSelection);
},
- get docShell() {
- if (this._docShell)
- return this._docShell;
- for (let shell in iter(config.browser.docShell.getDocShellEnumerator(Ci.nsIDocShellTreeItem.typeAll, Ci.nsIDocShell.ENUMERATE_FORWARDS)))
- if (shell.QueryInterface(nsIWebNavigation).document == this.document)
- return this._docShell = shell;
- throw Error();
- },
get selectionController() this.docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsISelectionDisplay)
@@ -637,8 +624,9 @@ const RangeFind = Class("RangeFind", {
}}
}),
- selectNodePath: ["ancestor-or-self::" + s for ([i, s] in Iterator(
- ["a", "xhtml:a", "*[@onclick]"]))].join(" | "),
+ contains: function (range, r)
+ range.compareBoundaryPoints(Range.START_TO_END, r) >= 0 &&
+ range.compareBoundaryPoints(Range.END_TO_START, r) <= 0,
endpoint: function (range, before) {
range = range.cloneRange();
range.collapse(before);
@@ -650,7 +638,15 @@ const RangeFind = Class("RangeFind", {
}
catch (e) {}
return false;
- }
+ },
+ nodeRange: function (node) {
+ let range = node.ownerDocument.createRange();
+ range.selectNode(node);
+ return range;
+ },
+ sameDocument: function (r1, r2) r1 && r2 && r1.endContainer.ownerDocument == r2.endContainer.ownerDocument,
+ selectNodePath: ["a", "xhtml:a", "*[@onclick]"].map(
+ function (p) "ancestor-or-self::" + p).join(" | ")
});
// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/content/history.js b/common/content/history.js
index 33ecb7e2..262df4c3 100644
--- a/common/content/history.js
+++ b/common/content/history.js
@@ -104,7 +104,7 @@ const History = Module("history", {
return dactyl.open(items.map(function (i) i.url), dactyl.NEW_TAB);
if (filter.length > 0)
- dactyl.echoerr("E283: No history matching \"" + filter + "\"");
+ dactyl.echoerr("E283: No history matching " + filter.quote());
else
dactyl.echoerr("No history set");
return null;
diff --git a/common/content/io.js b/common/content/io.js
index ff958296..dfe16e5c 100755
--- a/common/content/io.js
+++ b/common/content/io.js
@@ -426,7 +426,7 @@ const IO = Module("io", {
let dir = File(newDir);
if (!dir.exists() || !dir.isDirectory()) {
- dactyl.echoerr("E344: Can't find directory \"" + dir.path + "\" in path");
+ dactyl.echoerr("E344: Can't find directory " + dir.path.quote());
return null;
}
@@ -564,14 +564,14 @@ lookup:
let dirs = File.getPathsFromPathList(options["runtimepath"]);
let found = false;
- dactyl.echomsg("Searching for \"" + paths.join(" ") + "\" in \"" + options["runtimepath"] + "\"", 2);
+ dactyl.echomsg("Searching for " + paths.join(" ").quote() + " in " + options["runtimepath"].quote(), 2);
outer:
for (let [, dir] in Iterator(dirs)) {
for (let [, path] in Iterator(paths)) {
let file = File.joinPaths(dir, path);
- dactyl.echomsg("Searching for \"" + file.path + "\"", 3);
+ dactyl.echomsg("Searching for " + file.path.quote(), 3);
if (file.exists() && file.isFile() && file.isReadable()) {
io.source(file.path, false);
@@ -584,7 +584,7 @@ lookup:
}
if (!found)
- dactyl.echomsg("not found in 'runtimepath': \"" + paths.join(" ") + "\"", 1);
+ dactyl.echomsg("not found in 'runtimepath': " + paths.join(" ").quote(), 1);
return found;
},
@@ -609,9 +609,9 @@ lookup:
if (!file.exists() || !file.isReadable() || file.isDirectory()) {
if (!silent) {
if (file.exists() && file.isDirectory())
- dactyl.echomsg("Cannot source a directory: \"" + filename + "\"", 0);
+ dactyl.echomsg("Cannot source a directory: " + filename.quote(), 0);
else
- dactyl.echomsg("could not source: \"" + filename + "\"", 1);
+ dactyl.echomsg("could not source: " + filename.quote(), 1);
dactyl.echoerr("E484: Can't open file " + filename);
}
@@ -619,7 +619,7 @@ lookup:
return;
}
- dactyl.echomsg("sourcing \"" + filename + "\"", 2);
+ dactyl.echomsg("sourcing " + filename.quote(), 2);
let str = file.read();
let uri = services.get("io").newFileURI(file);
@@ -705,7 +705,7 @@ lookup:
if (this._scriptNames.indexOf(file.path) == -1)
this._scriptNames.push(file.path);
- dactyl.echomsg("finished sourcing \"" + filename + "\"", 2);
+ dactyl.echomsg("finished sourcing " + filename.quote(), 2);
dactyl.log("Sourced: " + filename, 3);
}
@@ -880,7 +880,7 @@ lookup:
let file = File(filename);
dactyl.assert(!file.exists() || args.bang,
- "E189: \"" + filename + "\" exists (add ! to override)");
+ "E189: " + filename.quote() + " exists (add ! to override)");
// TODO: Use a set/specifiable list here:
let lines = [cmd.serial().map(commands.commandToString) for (cmd in commands) if (cmd.serial)];
@@ -903,7 +903,7 @@ lookup:
file.write(lines.join("\n"));
}
catch (e) {
- dactyl.echoerr("E190: Cannot open \"" + filename + "\" for writing");
+ dactyl.echoerr("E190: Cannot open " + filename.quote() + " for writing");
dactyl.log("Could not write to " + file.path + ": " + e.message); // XXX
}
}, {
diff --git a/common/content/javascript.js b/common/content/javascript.js
index bd057bc2..686929ba 100644
--- a/common/content/javascript.js
+++ b/common/content/javascript.js
@@ -49,10 +49,8 @@ const JavaScript = Module("javascript", {
for (; obj; obj = !toplevel && obj.__proto__) {
services.get("debugger").wrapValue(obj).getProperties(ret, {});
for (let prop in values(ret.value)) {
- let name = '|' + prop.name.stringValue;
- if (name in seen)
+ if (set.add(seen, prop.name.stringValue))
continue;
- seen[name] = 1;
if (toplevel || obj !== orig)
yield [prop.name.stringValue, top.getProperty(prop.name.stringValue).value.getWrappedValue()]
}
@@ -61,7 +59,7 @@ const JavaScript = Module("javascript", {
// This only lists ENUMERABLE properties.
try {
for (let k in orig)
- if (k in orig && !('|' + k in seen)
+ if (k in orig && !(set.has(seen, k))
&& Object.hasOwnProperty(orig, k) == toplevel)
yield [k, this.getKey(orig, k)]
}
@@ -298,14 +296,18 @@ const JavaScript = Module("javascript", {
continue;
if (dot > stop || dot <= prev)
break;
- let s = this._str.substring(prev, dot);
+ let s = this._str.substring(prev, dot);
if (prev != statement)
s = JavaScript.EVAL_TMP + "." + s;
cacheKey = this._str.substring(statement, dot);
if (this._checkFunction(prev, dot, cacheKey))
return [];
+ if (prev != statement && obj == null) {
+ this.context.message = "Error: " + cacheKey.quote() + " is " + String(obj);
+ return [];
+ }
prev = dot + 1;
obj = this.eval(s, cacheKey, obj);
@@ -338,7 +340,7 @@ const JavaScript = Module("javascript", {
context.anchored = anchored;
context.filter = key;
context.itemCache = context.parent.itemCache;
- context.key = name;
+ context.key = name + last;
if (last != null)
context.quote = [last, function (text) util.escapeString(text.substr(offset), ""), last];
@@ -435,7 +437,7 @@ const JavaScript = Module("javascript", {
}
this.context.getCache("eval", Object);
- this.context.getCache("evalContext", function () ({ __proto__: userContext }));
+ this.context.getCache("evalContext", function () ({ __proto__: userContext }));;
// Okay, have parse stack. Figure out what we're completing.
diff --git a/common/content/options.js b/common/content/options.js
index 43174ac2..c7cda5c8 100644
--- a/common/content/options.js
+++ b/common/content/options.js
@@ -792,10 +792,11 @@ const Options = Module("options", {
*/
// FIXME: Well it used to. I'm looking at you mst! --djk
safeSetPref: function (name, value, message) {
- let val = this._loadPreference(name, null, false);
- let def = this._loadPreference(name, null, true);
- let lib = this._loadPreference(Options.SAVED + name);
- if (lib == null && val != def || val != lib) {
+ let curval = this._loadPreference(name, null, false);
+ let defval = this._loadPreference(name, null, true);
+ let saved = this._loadPreference(Options.SAVED + name);
+
+ if (saved == null && curval != defval || curval != saved) {
let msg = "Warning: setting preference " + name + ", but it's changed from its default value.";
if (message)
msg += " " + message;
@@ -952,14 +953,6 @@ const Options = Module("options", {
SAVED: "extensions.dactyl.saved.",
OLD_SAVED: "dactyl.saved."
}, {
- commandline: function () {
- // TODO: maybe reset in .destroy()?
- // TODO: move to buffer.js
- // we have our own typeahead find implementation
- // See: https://bugzilla.mozilla.org/show_bug.cgi?id=348187
- options.safeSetPref("accessibility.typeaheadfind.autostart", false);
- options.safeSetPref("accessibility.typeaheadfind", false); // actually the above setting should do it, but has no effect in Firefox
- },
commands: function () {
function setAction(args, modifiers) {
let bang = args.bang;
diff --git a/common/content/quickmarks.js b/common/content/quickmarks.js
index 9000bd23..fc44eb79 100644
--- a/common/content/quickmarks.js
+++ b/common/content/quickmarks.js
@@ -89,7 +89,7 @@ const QuickMarks = Module("quickmarks", {
if (filter.length > 0) {
marks = marks.filter(function (qmark) filter.indexOf(qmark) >= 0);
- dactyl.assert(marks.length >= 0, "E283: No QuickMarks matching \"" + filter + "\"");
+ dactyl.assert(marks.length >= 0, "E283: No QuickMarks matching " + filter.quote());
}
let items = [[mark, this._qmarks.get(mark)] for ([k, mark] in Iterator(marks))];
@@ -138,7 +138,7 @@ const QuickMarks = Module("quickmarks", {
args = args.string;
// ignore invalid qmark characters unless there are no valid qmark chars
- dactyl.assert(!args || /[a-zA-Z0-9]/.test(args), "E283: No QuickMarks matching \"" + args + "\"");
+ dactyl.assert(!args || /[a-zA-Z0-9]/.test(args), "E283: No QuickMarks matching " + args.quote());
let filter = args.replace(/[^a-zA-Z0-9]/g, "");
quickmarks.list(filter);
diff --git a/common/content/sanitizer.js b/common/content/sanitizer.js
index c061bc25..68b5ed69 100644
--- a/common/content/sanitizer.js
+++ b/common/content/sanitizer.js
@@ -7,7 +7,7 @@
// TODO:
// - fix Sanitize autocommand
// - add warning for TIMESPAN_EVERYTHING?
-// - respect privacy.clearOnShutdown et al or recommend PentadactylLeave autocommand?
+// - respect privacy.clearOnShutdown et al or recommend Leave autocommand?
// - add support for :set sanitizeitems=all like 'eventignore'?
// - integrate with the Clear Private Data dialog?
diff --git a/common/content/services.js b/common/content/services.js
index f95f29a2..33b6acab 100644
--- a/common/content/services.js
+++ b/common/content/services.js
@@ -22,7 +22,7 @@ const Services = Module("services", {
this.add("browserSearch", "@mozilla.org/browser/search-service;1", Ci.nsIBrowserSearchService);
this.add("cache", "@mozilla.org/network/cache-service;1", Ci.nsICacheService);
this.add("console", "@mozilla.org/consoleservice;1", Ci.nsIConsoleService);
- this.add("dactyl:", "@mozilla.org/network/protocol;1?name=dactyl");
+ this.add("dactyl:", "@mozilla.org/network/protocol;1?name=dactyl");
this.add("debugger", "@mozilla.org/js/jsd/debugger-service;1", Ci.jsdIDebuggerService);
this.add("directory", "@mozilla.org/file/directory_service;1", Ci.nsIProperties);
this.add("downloadManager", "@mozilla.org/download-manager;1", Ci.nsIDownloadManager);
diff --git a/common/content/statusline.js b/common/content/statusline.js
index c43ea4be..b40374ce 100755
--- a/common/content/statusline.js
+++ b/common/content/statusline.js
@@ -188,10 +188,10 @@ const StatusLine = Module("statusline", {
// update the ordinal which is used for numbered tabs
if (options.get("guioptions").has("n", "N"))
- for (let [i, tab] in util.Array.iteritems(config.browser.mTabs))
+ for (let [i, tab] in Iterator(tabs.visibleTabs))
tab.setAttribute("ordinal", i + 1);
- this.widgets.tabcount.value = "[" + (tabs.index() + 1) + "/" + tabs.count + "]";
+ this.widgets.tabcount.value = "[" + (tabs.index(null, true) + 1) + "/" + tabs.visibleTabs.length + "]";
}
},
diff --git a/common/content/tabs.js b/common/content/tabs.js
index dbabc928..a05a2979 100644
--- a/common/content/tabs.js
+++ b/common/content/tabs.js
@@ -43,6 +43,8 @@ const Tabs = Module("tabs", {
setTimeout(function () { dactyl.focusContent(true); }, 10); // just make sure, that no widget has focus
},
+ get allTabs() Array.slice(config.tabbrowser.tabContainer.childNodes),
+
/**
* @property {Object} The previously accessed tab or null if no tab
* other than the current one has been accessed.
@@ -59,6 +61,21 @@ const Tabs = Module("tabs", {
yield [i, browsers[i]];
},
+ /**
+ * @property {number} The number of tabs in the current window.
+ */
+ get count() config.tabbrowser.mTabs.length,
+
+ /**
+ * @property {Object} The local options store for the current tab.
+ */
+ get options() {
+ let store = this.localStore;
+ if (!("options" in store))
+ store.options = {};
+ return store.options;
+ },
+
/**
* @property {boolean} Whether the tab numbering XBL binding has been
* applied.
@@ -75,20 +92,7 @@ const Tabs = Module("tabs", {
".tabbrowser-tab[busy] > .tab-icon > .tab-icon-image { list-style-image: url('chrome://global/skin/icons/loading_16.png') !important; }");
},
- /**
- * @property {number} The number of tabs in the current window.
- */
- get count() config.tabbrowser.mTabs.length,
-
- /**
- * @property {Object} The local options store for the current tab.
- */
- get options() {
- let store = this.localStore;
- if (!("options" in store))
- store.options = {};
- return store.options;
- },
+ get visibleTabs() config.tabbrowser.visibleTabs || this.allTabs.filter(function (tab) !tab.hidden),
/**
* Returns the local state store for the tab at the specified
@@ -123,37 +127,33 @@ const Tabs = Module("tabs", {
get closedTabs() services.get("json").decode(services.get("sessionStore").getClosedTabData(window)),
/**
- * Returns the index of tab or the index of the currently
- * selected tab if tab is not specified. This is a 0-based
- * index.
+ * Clones the specified tab and append it to the tab list.
*
- * @param {Object} tab A tab from the current tab list.
- * @returns {number}
+ * @param {Object} tab The tab to clone.
+ * @param {boolean} activate Whether to select the newly cloned tab.
*/
- index: function (tab) {
- if (tab)
- return Array.indexOf(config.tabbrowser.mTabs, tab);
- else
- return config.tabbrowser.mTabContainer.selectedIndex;
+ cloneTab: function (tab, activate) {
+ let newTab = config.tabbrowser.addTab();
+ Tabs.copyTab(newTab, tab);
+
+ if (activate)
+ config.tabbrowser.mTabContainer.selectedItem = newTab;
+
+ return newTab;
},
- // TODO: implement filter
/**
- * Returns an array of all tabs in the tab list.
+ * Detaches the specified tab and open it in a new window. If no
+ * tab is specified the currently selected tab is detached.
*
- * @returns {Object[]}
+ * @param {Object} tab The tab to detach.
*/
- // FIXME: why not return the tab element?
- // : unused? Remove me.
- get: function () {
- let buffers = [];
- for (let [i, browser] in this.browsers) {
- let title = browser.contentTitle || "(Untitled)";
- let uri = browser.currentURI.spec;
- let number = i + 1;
- buffers.push([number, title, uri]);
- }
- return buffers;
+ detachTab: function (tab) {
+ if (!tab)
+ tab = config.tabbrowser.mTabContainer.selectedItem;
+
+ services.get("windowWatcher")
+ .openWindow(window, window.getBrowserURL(), null, "chrome,dialog=no,all", tab);
},
/**
@@ -171,6 +171,26 @@ const Tabs = Module("tabs", {
return -1;
},
+ /**
+ * If TabView exists, returns the Panorama window. If the Panorama
+ * is has not yet initialized, this function will not return until
+ * it has.
+ *
+ * @returns {Window}
+ */
+ getGroups: function () {
+ if ("_groups" in this)
+ return this._groups;
+ if (window.TabView && TabView._initFrame)
+ TabView._initFrame();
+ let iframe = document.getElementById("tab-view");
+ this._groups = this._groups = iframe ? iframe.contentWindow : null;
+ if (this._groups)
+ while (!this._groups.TabItems)
+ dactyl.threadYield(false, true);
+ return this._groups;
+ },
+
/**
* Returns the tab at the specified index or the currently
* selected tab if index is not specified. This is a 0-based
@@ -180,12 +200,72 @@ const Tabs = Module("tabs", {
* @returns {Object}
*/
getTab: function (index) {
- if (index != undefined)
+ if (index != null)
return config.tabbrowser.mTabs[index];
else
return config.tabbrowser.mCurrentTab;
},
+ /**
+ * Returns the index of tab or the index of the currently
+ * selected tab if tab is not specified. This is a 0-based
+ * index.
+ *
+ * @param {} tab A tab from the current tab list.
+ * @param {boolean} visible Whether to consider only visible tabs.
+ * @returns {number}
+ */
+ index: function (tab, visible) {
+ let tabs = this[visible ? "visibleTabs" : "allTabs"];
+ return tabs.indexOf(tab || config.tabbrowser.mCurrentTab);
+ },
+
+ /**
+ * @param spec can either be:
+ * - an absolute integer
+ * - "" for the current tab
+ * - "+1" for the next tab
+ * - "-3" for the tab, which is 3 positions left of the current
+ * - "$" for the last tab
+ */
+ indexFromSpec: function (spec, wrap) {
+ if (spec instanceof Node)
+ return this.allTabs.indexOf(spec);
+
+ let tabs = this.visibleTabs;
+ let position = this.index(null, true);
+
+ if (spec == null || spec === "")
+ return position;
+
+ if (typeof spec === "number")
+ position = spec;
+ else if (spec === "$")
+ position = tabs.length - 1;
+ else if (/^[+-]\d+$/.test(spec))
+ position += parseInt(spec, 10);
+ else if (/^\d+$/.test(spec))
+ position = parseInt(spec, 10);
+ else
+ return -1;
+
+ if (position >= tabs.length)
+ position = wrap ? position % tabs.length : tabs.length - 1;
+ else if (position < 0)
+ position = wrap ? (position % tabs.length) + tabs.length : 0;
+
+ return this.allTabs.indexOf(tabs[position]);
+ },
+
+ /**
+ * Removes all tabs from the tab list except the specified tab.
+ *
+ * @param {Object} tab The tab to keep.
+ */
+ keepOnly: function (tab) {
+ config.tabbrowser.removeAllTabsBut(tab);
+ },
+
/**
* Lists all tabs matching filter.
*
@@ -206,7 +286,7 @@ const Tabs = Module("tabs", {
* list.
*/
move: function (tab, spec, wrap) {
- let index = Tabs.indexFromSpec(spec, wrap);
+ let index = tabs.indexFromSpec(spec, wrap);
config.tabbrowser.moveTabTo(tab, index);
},
@@ -223,96 +303,31 @@ const Tabs = Module("tabs", {
*/
// FIXME: what is quitOnLastTab {1,2} all about then, eh? --djk
remove: function (tab, count, focusLeftTab, quitOnLastTab) {
- let removeOrBlankTab = {
- Firefox: function (tab) {
- if (config.tabbrowser.mTabs.length > 1)
- config.tabbrowser.removeTab(tab);
- else {
- if (buffer.URL != "about:blank" ||
- window.getWebNavigation().sessionHistory.count > 0) {
- dactyl.open("about:blank", dactyl.NEW_BACKGROUND_TAB);
- config.tabbrowser.removeTab(tab);
- }
- else
- dactyl.beep();
- }
- },
- Thunderbird: function (tab) {
- if (config.tabbrowser.mTabs.length > 1)
- config.tabbrowser.removeTab(tab);
- else
- dactyl.beep();
- },
- Songbird: function (tab) {
- if (config.tabbrowser.mTabs.length > 1)
- config.tabbrowser.removeTab(tab);
- else {
- if (buffer.URL != "about:blank" || window.getWebNavigation().sessionHistory.count > 0) {
- dactyl.open("about:blank", dactyl.NEW_BACKGROUND_TAB);
- config.tabbrowser.removeTab(tab);
- }
- else
- dactyl.beep();
- }
- }
- }[config.hostApplication] || function () {};
+ count = Math.max(count, 1);
- if (typeof count != "number" || count < 1)
- count = 1;
-
- if (quitOnLastTab >= 1 && config.tabbrowser.mTabs.length <= count) {
+ if (quitOnLastTab >= 1 && this.count <= count) {
if (dactyl.windows.length > 1)
window.close();
else
dactyl.quit(quitOnLastTab == 2);
-
return;
}
- let index = this.index(tab);
- if (focusLeftTab) {
- let lastRemovedTab = 0;
- for (let i = index; i > index - count && i >= 0; i--) {
- removeOrBlankTab(this.getTab(i));
- lastRemovedTab = i > 0 ? i : 1;
- }
- config.tabbrowser.mTabContainer.selectedIndex = lastRemovedTab - 1;
- }
- else {
- let i = index + count - 1;
- if (i >= this.count)
- i = this.count - 1;
+ let tabs = this.visibleTabs
+ if (tabs.indexOf(tab) < 0)
+ tabs = this.allTabs;
+ let index = tabs.indexOf(tab);
- for (; i >= index; i--)
- removeOrBlankTab(this.getTab(i));
- config.tabbrowser.mTabContainer.selectedIndex = index;
- }
- },
+ let next = index + (focusLeftTab ? -count : count);
+ if (!(next in tabs))
+ next = index + (focusLeftTab ? 1 : -1);
+ if (next in tabs)
+ config.tabbrowser.mTabContainer.selectedItem = tabs[next];
- /**
- * Removes all tabs from the tab list except the specified tab.
- *
- * @param {Object} tab The tab to keep.
- */
- keepOnly: function (tab) {
- config.tabbrowser.removeAllTabsBut(tab);
- },
-
- /**
- * Selects the tab at the position specified by spec.
- *
- * @param {string} spec See {@link Tabs.indexFromSpec}
- * @param {boolean} wrap Whether an out of bounds spec causes
- * the selection position to wrap around the start/end of the tab
- * list.
- */
- select: function (spec, wrap) {
- let index = Tabs.indexFromSpec(spec, wrap);
- // FIXME:
- if (index == -1)
- dactyl.beep();
+ if (focusLeftTab)
+ tabs.slice(Math.max(0, index+1 - count), index+1).forEach(config.removeTab);
else
- config.tabbrowser.mTabContainer.selectedIndex = index;
+ tabs.slice(index, index + count).forEach(config.removeTab);
},
/**
@@ -353,6 +368,40 @@ const Tabs = Module("tabs", {
config.tabbrowser.reloadAllTabs();
},
+ /**
+ * Selects the tab at the position specified by spec.
+ *
+ * @param {string} spec See {@link Tabs.indexFromSpec}
+ * @param {boolean} wrap Whether an out of bounds spec causes
+ * the selection position to wrap around the start/end of the tab
+ * list.
+ */
+ select: function (spec, wrap) {
+ let index = tabs.indexFromSpec(spec, wrap);
+ if (index == -1)
+ dactyl.beep();
+ else
+ config.tabbrowser.mTabContainer.selectedIndex = index;
+ },
+
+ /**
+ * Selects the alternate tab.
+ */
+ selectAlternateTab: function () {
+ dactyl.assert(tabs.alternate != null && tabs.getTab() != tabs.alternate,
+ "E23: No alternate page");
+
+ // NOTE: this currently relies on v.tabs.index() returning the
+ // currently selected tab index when passed null
+ let index = tabs.index(tabs.alternate);
+
+ // TODO: since a tab close is more like a bdelete for us we
+ // should probably reopen the closed tab when a 'deleted'
+ // alternate is selected
+ dactyl.assert(index >= 0, "E86: Buffer does not exist"); // TODO: This should read "Buffer N does not exist"
+ tabs.select(index);
+ },
+
/**
* Stops loading the specified tab.
*
@@ -398,7 +447,7 @@ const Tabs = Module("tabs", {
}
else {
buffer = this._lastBufferSwitchArgs;
- if (allowNonUnique === undefined || allowNonUnique == null) // XXX
+ if (allowNonUnique == null) // XXX
allowNonUnique = this._lastBufferSwitchSpecial;
}
@@ -407,14 +456,12 @@ const Tabs = Module("tabs", {
return;
}
- if (!count || count < 1)
- count = 1;
- if (typeof reverse != "boolean")
- reverse = false;
+ count = Math.max(1, count || 1);
+ reverse = Boolean(reverse);
let matches = buffer.match(/^(\d+):?/);
if (matches) {
- tabs.select(parseInt(matches[1], 10) - 1, false); // make it zero-based
+ tabs.select(this.allTabs[parseInt(matches[1], 10) - 1], false);
return;
}
@@ -424,8 +471,9 @@ const Tabs = Module("tabs", {
let nbrowsers = config.tabbrowser.browsers.length;
for (let [i, ] in tabs.browsers) {
let index = (i + first) % nbrowsers;
- let url = config.tabbrowser.getBrowserAtIndex(index).contentDocument.location.href;
- let title = config.tabbrowser.getBrowserAtIndex(index).contentDocument.title.toLowerCase();
+ let browser = config.tabbrowser.getBrowserAtIndex(index);
+ let url = browser.contentDocument.location.href;
+ let title = browser.contentDocument.title.toLowerCase();
if (url == buffer) {
tabs.select(index, false);
return;
@@ -434,71 +482,21 @@ const Tabs = Module("tabs", {
if (url.indexOf(buffer) >= 0 || title.indexOf(lowerBuffer) >= 0)
matches.push(index);
}
+
if (matches.length == 0)
dactyl.echoerr("E94: No matching buffer for " + buffer);
else if (matches.length > 1 && !allowNonUnique)
dactyl.echoerr("E93: More than one match for " + buffer);
else {
- if (reverse) {
+ let index = (count - 1) % matches.length;
+ if (reverse)
index = matches.length - count;
- while (index < 0)
- index += matches.length;
- }
- else
- index = (count - 1) % matches.length;
- tabs.select(matches[index], false);
+ index = Array.indexOf(config.tabbrowser.browsers, matches[index]);
+ tabs.select(index, false);
}
},
- /**
- * Clones the specified tab and append it to the tab list.
- *
- * @param {Object} tab The tab to clone.
- * @param {boolean} activate Whether to select the newly cloned tab.
- */
- cloneTab: function (tab, activate) {
- let newTab = config.tabbrowser.addTab();
- Tabs.copyTab(newTab, tab);
-
- if (activate)
- config.tabbrowser.mTabContainer.selectedItem = newTab;
-
- return newTab;
- },
-
- /**
- * Detaches the specified tab and open it in a new window. If no
- * tab is specified the currently selected tab is detached.
- *
- * @param {Object} tab The tab to detach.
- */
- detachTab: function (tab) {
- if (!tab)
- tab = config.tabbrowser.mTabContainer.selectedItem;
-
- services.get("windowWatcher")
- .openWindow(window, window.getBrowserURL(), null, "chrome,dialog=no,all", tab);
- },
-
- /**
- * Selects the alternate tab.
- */
- selectAlternateTab: function () {
- dactyl.assert(tabs.alternate != null && tabs.getTab() != tabs.alternate,
- "E23: No alternate page");
-
- // NOTE: this currently relies on v.tabs.index() returning the
- // currently selected tab index when passed null
- let index = tabs.index(tabs.alternate);
-
- // TODO: since a tab close is more like a bdelete for us we
- // should probably reopen the closed tab when a 'deleted'
- // alternate is selected
- dactyl.assert(index >= 0, "E86: Buffer does not exist"); // TODO: This should read "Buffer N does not exist"
- tabs.select(index);
- },
-
// NOTE: when restarting a session FF selects the first tab and then the
// tab that was selected when the session was created. As a result the
// alternate after a restart is often incorrectly tab 1 when there
@@ -520,41 +518,6 @@ const Tabs = Module("tabs", {
let tabState = services.get("sessionStore").getTabState(from);
services.get("sessionStore").setTabState(to, tabState);
- },
-
- /**
- * @param spec can either be:
- * - an absolute integer
- * - "" for the current tab
- * - "+1" for the next tab
- * - "-3" for the tab, which is 3 positions left of the current
- * - "$" for the last tab
- */
- indexFromSpec: function (spec, wrap) {
- let position = config.tabbrowser.mTabContainer.selectedIndex;
- let length = config.tabbrowser.mTabs.length;
- let last = length - 1;
-
- if (spec === undefined || spec === "")
- return position;
-
- if (typeof spec === "number")
- position = spec;
- else if (spec === "$")
- position = last;
- else if (/^[+-]\d+$/.test(spec))
- position += parseInt(spec, 10);
- else if (/^\d+$/.test(spec))
- position = parseInt(spec, 10);
- else
- return -1;
-
- if (position > last)
- position = wrap ? position % length : last;
- else if (position < 0)
- position = wrap ? (position % length) + length : 0;
-
- return position;
}
}, {
commands: function () {
@@ -1037,7 +1000,7 @@ const Tabs = Module("tabs", {
let pref = "browser.tabStrip.autoHide";
if (options.getPref(pref) == null) // Try for FF 3.0 & 3.1
pref = "browser.tabs.autoHide";
- options.safeSetPref(pref, value == 1);
+ options.safeSetPref(pref, value == 1, "See 'showtabline' option.");
tabStrip.collapsed = false;
}
@@ -1098,8 +1061,10 @@ const Tabs = Module("tabs", {
restriction = 2;
}
- options.safeSetPref("browser.link.open_newwindow", open, "See 'popups' option.");
- options.safeSetPref("browser.link.open_newwindow.restriction", restriction, "See 'popups' option.");
+ options.safeSetPref("browser.link.open_newwindow", open,
+ "See 'popups' option.");
+ options.safeSetPref("browser.link.open_newwindow.restriction", restriction,
+ "See 'popups' option.");
return values;
},
completer: function (context) [
diff --git a/common/content/util.js b/common/content/util.js
index 8061534b..f72c6dbc 100644
--- a/common/content/util.js
+++ b/common/content/util.js
@@ -452,7 +452,8 @@ const Util = Module("util", {
let result = doc.evaluate(expression, elem,
function lookupNamespaceURI(prefix) {
return {
- xhtml: "http://www.w3.org/1999/xhtml",
+ xul: XUL.uri,
+ xhtml: XHTML.uri,
xhtml2: "http://www.w3.org/2002/06/xhtml2",
dactyl: NS.uri
}[prefix] || null;
diff --git a/common/locale/en-US/pattern.xml b/common/locale/en-US/pattern.xml
index 403df7de..ace1c205 100644
--- a/common/locale/en-US/pattern.xml
+++ b/common/locale/en-US/pattern.xml
@@ -25,14 +25,20 @@
Search forward for the first occurrence of pattern.
- If \c appears anywhere in the pattern the whole pattern is handled as though
- ignorecase is on. \C forces case-sensitive matching for the whole pattern.
-
-
- If \l appears in the pattern only the text of links is searched for a
- match as though linksearch is on. \L forces the entire page to be searched
- for a match.
+ The following escape sequences can be used to modify the
+ behavior of the search. When flags conflict, the last to
+ appear is the one that takes effect.
+
+
+
\c
Perform case insensitive search (default
+ if ignorecase is set).
+
\C
Perform case sensitive search
+
\l
Search only in links, as defined by
+ hinttags. (default if linksearch is
+ set).
+
\L
Do not search only in links.
+
@@ -54,7 +60,7 @@
nn
-
Find next. Repeat the last search 1 time (until count is supported).
+
Find next. Repeat the last search.
@@ -63,10 +69,7 @@
NN
-
- Find previous. Repeat the last search 1 time (until count is supported) in the
- opposite direction.
-
+
Find previous. Repeat the last search in the opposite direction.
diff --git a/muttator/content/config.js b/muttator/content/config.js
index 0f62c89e..b2ed159c 100644
--- a/muttator/content/config.js
+++ b/muttator/content/config.js
@@ -14,83 +14,53 @@ const Config = Module("config", ConfigBase, {
hostApplication: "Thunderbird", // TODO: can this be found out otherwise? gBrandBundle.getString("brandShortName");
// Yes, but it will be localized unlike all other strings. So, it's best left until we i18n dactyl. --djk
- get mainWindowId() this.isComposeWindow ? "msgcomposeWindow" : "messengerWindow",
+ autocommands: {
+ DOMLoad: "Triggered when a page's DOM content has fully loaded",
+ FolderLoad: "Triggered after switching folders in Thunderbird",
+ PageLoadPre: "Triggered after a page load is initiated",
+ PageLoad: "Triggered when a page gets (re)loaded/opened",
+ Enter: "Triggered after Thunderbird starts",
+ Leave: "Triggered before exiting Thunderbird",
+ LeavePre: "Triggered before exiting Thunderbird",
+ },
+
+ get browser() getBrowser(),
+
+ dialogs: {
+ about: ["About Thunderbird",
+ function () { window.openAboutDialog(); }],
+ addons: ["Manage Add-ons",
+ function () { window.openAddonsMgr(); }],
+ addressbook: ["Address book",
+ function () { window.toAddressBook(); }],
+ checkupdates: ["Check for updates",
+ function () { window.checkForUpdates(); }],
+ console: ["JavaScript console",
+ function () { window.toJavaScriptConsole(); }],
+ dominspector: ["DOM Inspector",
+ function () { window.inspectDOMDocument(content.document); }],
+ downloads: ["Manage Downloads",
+ function () { window.toOpenWindowByType('Download:Manager', 'chrome://mozapps/content/downloads/downloads.xul', 'chrome,dialog=no,resizable'); }],
+ preferences: ["Show Thunderbird preferences dialog",
+ function () { openOptionsDialog(); }],
+ printsetup: ["Setup the page size and orientation before printing",
+ function () { PrintUtils.showPageSetup(); }],
+ print: ["Show print dialog",
+ function () { PrintUtils.print(); }],
+ saveframe: ["Save frame to disk",
+ function () { window.saveFrameDocument(); }],
+ savepage: ["Save page to disk",
+ function () { window.saveDocument(window.content.document); }],
+ },
- /*** optional options, there are checked for existence and a fallback provided ***/
- features: ["hints", "mail", "marks", "addressbook", "tabs"],
defaults: {
guioptions: "frb",
showtabline: 1,
titlestring: "Muttator"
},
- guioptions: {
- m: ["MenuBar", ["mail-toolbar-menubar2"]],
- T: ["Toolbar" , ["mail-bar2"]],
- f: ["Folder list", ["folderPaneBox", "folderpane_splitter"]],
- F: ["Folder list header", ["folderPaneHeader"]]
- },
-
- get isComposeWindow() window.wintype == "msgcompose",
- get browserModes() [modes.MESSAGE],
- get mailModes() [modes.NORMAL],
- // focusContent() focuses this widget
- get mainWidget() this.isComposeWindow ? document.getElementById("content-frame") : GetThreadTree(),
- get visualbellWindow() document.getElementById(this.mainWindowId),
- styleableChrome: ["chrome://messenger/content/messenger.xul",
- "chrome://messenger/content/messengercompose/messengercompose.xul"],
-
- autocommands: [["DOMLoad", "Triggered when a page's DOM content has fully loaded"],
- ["FolderLoad", "Triggered after switching folders in Thunderbird"],
- ["PageLoadPre", "Triggered after a page load is initiated"],
- ["PageLoad", "Triggered when a page gets (re)loaded/opened"],
- ["MuttatorEnter", "Triggered after Thunderbird starts"],
- ["MuttatorLeave", "Triggered before exiting Thunderbird"],
- ["MuttatorLeavePre", "Triggered before exiting Thunderbird"]],
- dialogs: [
- ["about", "About Thunderbird",
- function () { window.openAboutDialog(); }],
- ["addons", "Manage Add-ons",
- function () { window.openAddonsMgr(); }],
- ["addressbook", "Address book",
- function () { window.toAddressBook(); }],
- ["checkupdates", "Check for updates",
- function () { window.checkForUpdates(); }],
- /*["cleardata", "Clear private data",
- function () { Cc[GLUE_CID].getService(Ci.nsIBrowserGlue).sanitize(window || null); }],*/
- ["console", "JavaScript console",
- function () { window.toJavaScriptConsole(); }],
- /*["customizetoolbar", "Customize the Toolbar",
- function () { BrowserCustomizeToolbar(); }],*/
- ["dominspector", "DOM Inspector",
- function () { window.inspectDOMDocument(content.document); }],
- ["downloads", "Manage Downloads",
- function () { window.toOpenWindowByType('Download:Manager', 'chrome://mozapps/content/downloads/downloads.xul', 'chrome,dialog=no,resizable'); }],
- /*["import", "Import Preferences, Bookmarks, History, etc. from other browsers",
- function () { BrowserImport(); }],
- ["openfile", "Open the file selector dialog",
- function () { BrowserOpenFileWindow(); }],
- ["pageinfo", "Show information about the current page",
- function () { BrowserPageInfo(); }],
- ["pagesource", "View page source",
- function () { BrowserViewSourceOfDocument(content.document); }],*/
- ["preferences", "Show Thunderbird preferences dialog",
- function () { openOptionsDialog(); }],
- /*["printpreview", "Preview the page before printing",
- function () { PrintUtils.printPreview(onEnterPrintPreview, onExitPrintPreview); }],*/
- ["printsetup", "Setup the page size and orientation before printing",
- function () { PrintUtils.showPageSetup(); }],
- ["print", "Show print dialog",
- function () { PrintUtils.print(); }],
- ["saveframe", "Save frame to disk",
- function () { window.saveFrameDocument(); }],
- ["savepage", "Save page to disk",
- function () { window.saveDocument(window.content.document); }],
- /*["searchengines", "Manage installed search engines",
- function () { openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
- ["selectionsource", "View selection source",
- function () { buffer.viewSelectionSource(); }]*/
- ],
+ /*** optional options, there are checked for existence and a fallback provided ***/
+ features: ["hints", "mail", "marks", "addressbook", "tabs"],
focusChange: function (win) {
// we switch to -- MESSAGE -- mode for Muttator, when the main HTML widget gets focus
@@ -102,23 +72,28 @@ const Config = Module("config", ConfigBase, {
}
},
- get browser() getBrowser(),
- tabbrowser: {
- __proto__: document.getElementById("tabmail"),
- get mTabContainer() this.tabContainer,
- get mTabs() this.tabContainer.childNodes,
- get mCurrentTab() this.tabContainer.selectedItem,
- get mStrip() this.tabStrip,
- get browsers() [browser for (browser in Iterator(this.mTabs))]
+ guioptions: {
+ m: ["MenuBar", ["mail-toolbar-menubar2"]],
+ T: ["Toolbar" , ["mail-bar2"]],
+ f: ["Folder list", ["folderPaneBox", "folderpane_splitter"]],
+ F: ["Folder list header", ["folderPaneHeader"]]
},
// they are sorted by relevance, not alphabetically
helpFiles: ["intro.html", "version.html"],
+ get isComposeWindow() window.wintype == "msgcompose",
+
+ get mainWidget() this.isComposeWindow ? document.getElementById("content-frame") : GetThreadTree(),
+
+ get mainWindowId() this.isComposeWindow ? "msgcomposeWindow" : "messengerWindow",
+
modes: [
["MESSAGE", { char: "m" }],
["COMPOSE"]
],
+ get browserModes() [modes.MESSAGE],
+ get mailModes() [modes.NORMAL],
// NOTE: as I don't use TB I have no idea how robust this is. --djk
get outputHeight() {
@@ -137,15 +112,35 @@ const Config = Module("config", ConfigBase, {
return document.getElementById("appcontent").boxObject.height;
},
+ removeTab: function (tab) {
+ if (config.tabbrowser.mTabs.length > 1)
+ config.tabbrowser.removeTab(tab);
+ else
+ dactyl.beep();
+ },
+
get scripts() this.isComposeWindow ? ["compose/compose.js"] : [
"addressbook.js",
"mail.js",
"tabs.js",
],
+ styleableChrome: ["chrome://messenger/content/messenger.xul",
+ "chrome://messenger/content/messengercompose/messengercompose.xul"],
+
+ tabbrowser: {
+ __proto__: document.getElementById("tabmail"),
+ get mTabContainer() this.tabContainer,
+ get mTabs() this.tabContainer.childNodes,
+ get mCurrentTab() this.tabContainer.selectedItem,
+ get mStrip() this.tabStrip,
+ get browsers() [browser for (browser in Iterator(this.mTabs))]
+ },
+
// to allow Vim to :set ft=mail automatically
tempFile: "mutt-ator-mail",
+ get visualbellWindow() document.getElementById(this.mainWindowId),
}, {
}, {
commands: function () {
diff --git a/pentadactyl/NEWS b/pentadactyl/NEWS
index 351c91f5..d0b1eb64 100755
--- a/pentadactyl/NEWS
+++ b/pentadactyl/NEWS
@@ -1,9 +1,11 @@
2009-XX-XX:
+ * Use only visible tabs for tab numbering, gt/gn/gN, etc.
+ * Group tabs in :buffer completions by panorama groups
* Replaced 'focuscontent' with 'strictfocus'
* Replaced previous incremental search implementation
* gf now toggles between source and content view.
'|' key binding has been removed.
- * :open now only opens files begining with / or ./
+ * :open now only opens files begining with /, ./, or ~/
* Page zoom information is now shown in the status bar
* Added ZO, ZI, ZM, and ZR as aliases for zO, zI, zM, and zR
* Add basic plugin authorship documentation
diff --git a/pentadactyl/content/config.js b/pentadactyl/content/config.js
index 2581e547..64bebd44 100644
--- a/pentadactyl/content/config.js
+++ b/pentadactyl/content/config.js
@@ -13,8 +13,26 @@ const Config = Module("config", ConfigBase, {
name: "Pentadactyl",
hostApplication: "Firefox",
- /*** optional options, there are checked for existence and a fallback provided ***/
- features: ["bookmarks", "hints", "history", "marks", "quickmarks", "sanitizer", "session", "tabs", "tabs_undo", "windows"],
+ get visualbellWindow() getBrowser().mPanelContainer,
+ styleableChrome: ["chrome://browser/content/browser.xul"],
+
+ autocommands: {
+ BookmarkAdd: "Triggered after a page is bookmarked",
+ ColorScheme: "Triggered after a color scheme has been loaded",
+ DOMLoad: "Triggered when a page's DOM content has fully loaded",
+ DownloadPost: "Triggered when a download has completed",
+ Fullscreen: "Triggered when the browser's fullscreen state changes",
+ LocationChange: "Triggered when changing tabs or when navigation to a new location",
+ PageLoadPre: "Triggered after a page load is initiated",
+ PageLoad: "Triggered when a page gets (re)loaded/opened",
+ PrivateMode: "Triggered when private mode is activated or deactivated",
+ Sanitize: "Triggered when a sanitizeable item is cleared",
+ ShellCmdPost: "Triggered after executing a shell command with :!cmd",
+ Enter: "Triggered after Firefox starts",
+ LeavePre: "Triggered before exiting Firefox, just before destroying each module",
+ Leave: "Triggered before exiting Firefox",
+ },
+
defaults: {
complete: "slf",
guioptions: "rb",
@@ -22,30 +40,6 @@ const Config = Module("config", ConfigBase, {
titlestring: "Pentadactyl"
},
- guioptions: {
- m: ["Menubar", ["toolbar-menubar"]],
- T: ["Toolbar", ["nav-bar"]],
- B: ["Bookmark bar", ["PersonalToolbar"]]
- },
-
- get visualbellWindow() getBrowser().mPanelContainer,
- styleableChrome: ["chrome://browser/content/browser.xul"],
-
- autocommands: [["BookmarkAdd", "Triggered after a page is bookmarked"],
- ["ColorScheme", "Triggered after a color scheme has been loaded"],
- ["DOMLoad", "Triggered when a page's DOM content has fully loaded"],
- ["DownloadPost", "Triggered when a download has completed"],
- ["Fullscreen", "Triggered when the browser's fullscreen state changes"],
- ["LocationChange", "Triggered when changing tabs or when navigation to a new location"],
- ["PageLoadPre", "Triggered after a page load is initiated"],
- ["PageLoad", "Triggered when a page gets (re)loaded/opened"],
- ["PrivateMode", "Triggered when private mode is activated or deactivated"],
- ["Sanitize", "Triggered when a sanitizeable item is cleared"],
- ["ShellCmdPost", "Triggered after executing a shell command with :!cmd"],
- ["PentadactylEnter", "Triggered after Firefox starts"],
- ["PentadactylLeavePre","Triggered before exiting Firefox, just before destroying each module"],
- ["PentadactylLeave", "Triggered before exiting Firefox"]],
-
dialogs: {
about: ["About Firefox",
function () { window.openDialog("chrome://browser/content/aboutDialog.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
@@ -99,10 +93,34 @@ const Config = Module("config", ConfigBase, {
function () { buffer.viewSelectionSource(); }]
},
+ features: [
+ "bookmarks", "hints", "history", "marks", "quickmarks", "sanitizer",
+ "session", "tabs", "tabs_undo", "windows"
+ ],
+
+ guioptions: {
+ m: ["Menubar", ["toolbar-menubar"]],
+ T: ["Toolbar", ["nav-bar"]],
+ B: ["Bookmark bar", ["PersonalToolbar"]]
+ },
+
hasTabbrowser: true,
ignoreKeys: {},
+ removeTab: function (tab) {
+ if (config.tabbrowser.mTabs.length > 1)
+ config.tabbrowser.removeTab(tab);
+ else {
+ if (buffer.URL != "about:blank" || window.getWebNavigation().sessionHistory.count > 0) {
+ dactyl.open("about:blank", dactyl.NEW_BACKGROUND_TAB);
+ config.tabbrowser.removeTab(tab);
+ }
+ else
+ dactyl.beep();
+ }
+ },
+
scripts: [
"browser.js",
"bookmarks.js",
@@ -114,7 +132,6 @@ const Config = Module("config", ConfigBase, {
get tempFile() {
let prefix = this.name.toLowerCase();
-
try {
prefix += "-" + window.content.document.location.hostname;
}
diff --git a/pentadactyl/content/dactyl.dtd b/pentadactyl/content/dactyl.dtd
index 88260bab..dff1ecf0 100644
--- a/pentadactyl/content/dactyl.dtd
+++ b/pentadactyl/content/dactyl.dtd
@@ -6,6 +6,8 @@
+
+
diff --git a/pentadactyl/locale/en-US/autocommands.xml b/pentadactyl/locale/en-US/autocommands.xml
index 637ce318..78539485 100644
--- a/pentadactyl/locale/en-US/autocommands.xml
+++ b/pentadactyl/locale/en-US/autocommands.xml
@@ -19,9 +19,9 @@
PrivateMode
Triggered when private mode is activated or deactivated
Sanitize
Triggered when privata data are sanitized
ShellCmdPost
Triggered after executing a shell command with :!cmd
-
&dactyl.appname;Enter
Triggered after &dactyl.host; starts
-
&dactyl.appname;LeavePre
Triggered before exiting &dactyl.host;, just before destroying each module
-
&dactyl.appname;Leave
Triggered before exiting &dactyl.host;
+
Enter
Triggered after &dactyl.host; starts
+
LeavePre
Triggered before exiting &dactyl.host;, just before destroying each module
+
Leave
Triggered before exiting &dactyl.host;
diff --git a/pentadactyl/locale/en-US/intro.xml b/pentadactyl/locale/en-US/intro.xml
index 07085326..da125455 100644
--- a/pentadactyl/locale/en-US/intro.xml
+++ b/pentadactyl/locale/en-US/intro.xml
@@ -14,49 +14,29 @@
&dactyl.appname; is a free browser add-on for &dactyl.host;,
which makes it look and behave like the
Vim
-text editor. It has similar key bindings, and you could call it a modal
-web browser, as key bindings differ according to which mode you are in.
+text editor.
- To provide the most authentic Vim experience, the &dactyl.host; menubar and toolbar are hidden.
+ To provide the most authentic Vim experience, the &dactyl.host;
+ menubar and toolbar are hidden.
+
+
+ If you really need them, type: :set guioptions+=mT to
+ get them back.
+
+
+
+ If you don't like &dactyl.appname; at all, you can uninstall it
+ by typing :extdelete &dactyl.appname; or disable it
+ with :extdisable &dactyl.appname;
+
+
+
+ If you like it but can't remember the shortcuts, then type
+ or :help to get this help window back.
+
-
If you really need them, type: :set guioptions+=mT to get them back.
-
- If you don't like &dactyl.appname; at all, you can uninstall it by typing
- :extdelete &dactyl.appname; or :extdisable &dactyl.appname; to disable it.
-
-
- If you like it but can't remember the shortcuts, then press
- or :help to get this help window back.
-
-
-author donaton sponsor
-
-
- &dactyl.appname; was initially written by
- Martin
- Stubenschrott but has found many other
- contributors
- in the meanwhile. If you appreciate the work on &dactyl.appname; and want to
- encourage us working on it more, you can send us greetings, patches, or
- donations (thanks a lot to
- these
- people
- who already did):
-
-
-
-
-
- If you prefer getting some nice products for your money, you can also support
- us by buying some cool
- merchandise like
- t-shirts or mugs. Of course, as we believe in free, open source software, only
- support us financially if you really like &dactyl.appname; and the money doesn't hurt
- — otherwise just use it, recommend it, and like it :)
-
-
Help topics
@@ -156,10 +136,11 @@ web browser, as key bindings differ according to which mode you are in.
-You can also jump directly to the help of a specific command with :help o
-or :help :set.
+ You can also jump directly to the help of a specific command via the :help command.
+:help :help
+
Features
@@ -188,15 +169,14 @@ or :help :set.
Contact
- Please send comments/bug reports/patches to the mailing list, where we will
- properly answer any questions. You can also join the
- #pentadactyl IRC channel
- on Freenode or check the
- Wiki for
-
- frequently asked questions (FAQ)
- . Make sure, you have read the TODO file first, as we are aware of many
- things which can be improved when we find time for it or receive patches.
+ Please send comments, questions, or patches to the
+ mailing list,
+ where we will do our best to answer any questions. You can also
+ check the
+ wiki for
+ FAQ.
+ Issue reports can be entered in the
+ issue tracker.
Show all options that differ from their default value.
-
-
-
-
- :sturm :drang
- :und
-
-
Show all options that differ from their default value.
-
-
-
-
diff --git a/pentadactyl/locale/en-US/tutorial.xml b/pentadactyl/locale/en-US/tutorial.xml
index 782d5316..ab522e10 100644
--- a/pentadactyl/locale/en-US/tutorial.xml
+++ b/pentadactyl/locale/en-US/tutorial.xml
@@ -122,20 +122,24 @@
Scrolling the browser window is done with simple keystrokes:
-
-
j/k –
+
+
j/k
+
scroll window down/up by one line, respectively
-
-
h/l –
+
+
h/l
+
scroll window left/right
-
-
/ –
+
+
/
+
scroll down/up by one page
-
-
/ –
+
+
/
+
scroll down/up by 1/2 page
-
-
+
+
Your standard buttons (///) will
@@ -149,31 +153,36 @@
scrolling.
-
-
/ –
+
+
/
+
move Back/Forward in the current window/tab's history, respectively
-
-
+
+
Move between tabs using these keystrokes which may also be familiar to tabbing
Vimmers.
-
-
gt/ –
+
+
gt/
+
go to the next tab
-
-
gT/ –
+
+
gT/
+
go to the previous tab
-
-
g0/g$ –
+
+
g0/g$
+
go to the first/last tab
-
-
d –
+
+
d
+
close the active tab (delete the buffer)
-
-
+
+
To open a web page in a new tab, use the :tabopen url. To open a URL in
@@ -186,8 +195,8 @@
:open my.webmail.comomy.webmail.com
-:tabopen vimperator.org
-tvimperator.org
+:tabopen google.com
+tgoogle.com
Some hints about surfing…
@@ -225,7 +234,7 @@
- To test it, try this link: &dactyl.appname; Homepage.
+ To test it, try this link: &dactyl.appname; Homepage.
Activate QuickHint mode with f or F to highlight all currently
visible links. Then start typing the text of the link. The link should be
uniquely identified soon, and &dactyl.appname; will open it. Once you're done,
@@ -250,7 +259,7 @@
-
Saving for posterity - pentadactylrc
+
Saving for posterity—pentadactylrc
Once you get &dactyl.appname; set up with your desired options, maps, and commands,
@@ -275,17 +284,24 @@
&dactyl.appname; supports all of Vim's classic methods of exiting.
-
-
:xall – command to quit and save the current browsing
- session for next time; the default.
-
-
:qall – command to quit without saving the session
-
-
ZZ – Normal mode mapping equivalent to :xall
-
-
ZQ – Normal mode mapping equivalent to :qall
-
-
+
+
:xall
+
+ command to quit and save the current browsing session for next time; the default.
+
+
:qall
+
+ command to quit without saving the session
+
+
ZZ
+
+ Normal mode mapping equivalent to :xall
+
+
ZQ
+
+ Normal mode mapping equivalent to :qall
+
+
Where did &dactyl.host; go?
@@ -296,24 +312,28 @@
make the best use of them.
-
-
:dialog –
+
+
:dialog
+
To access some of &dactyl.host;'s many dialog windows, you can use the
:dialog command. See :help :dialog.
-
-
:bmarks –
+
+
:bmarks
+
&dactyl.appname; provides a new interface to bookmarks, but they're still your
standard &dactyl.host; bookmarks under the hood. :bmark will add a new
bookmark, while :bmarks will list the bookmarks currently defined.
-
-
:history –
+
+
:history
+
It's exactly what it sounds like. This command will display a colorized,
scrollable and clickable list of the locations in &dactyl.appname;'s history.
-
-
:emenu –
+
+
:emenu
+
Access the &dactyl.host; menus through the &dactyl.appname; command line.
-
-
+
+
Feel free to explore at this point. If you use the :tabopen command,
diff --git a/xulmus/content/config.js b/xulmus/content/config.js
index 1a19a3a4..6eee5298 100644
--- a/xulmus/content/config.js
+++ b/xulmus/content/config.js
@@ -44,98 +44,74 @@ const Config = Module("config", ConfigBase, {
styleableChrome: ["chrome://gonzo/content/xul/mainplayer.xul"],
- autocommands: [["BookmarkAdd", "Triggered after a page is bookmarked"],
- ["ColorScheme", "Triggered after a color scheme has been loaded"],
- ["DOMLoad", "Triggered when a page's DOM content has fully loaded"],
- ["DownloadPost", "Triggered when a download has completed"],
- ["Fullscreen", "Triggered when the browser's fullscreen state changes"],
- ["LocationChange", "Triggered when changing tabs or when navigation to a new location"],
- ["PageLoadPre", "Triggered after a page load is initiated"],
- ["PageLoad", "Triggered when a page gets (re)loaded/opened"],
- ["ShellCmdPost", "Triggered after executing a shell command with :!cmd"],
- ["TrackChangePre", "Triggered before a playing track is changed"],
- ["TrackChange", "Triggered after a playing track has changed"],
- ["ViewChangePre", "Triggered before a sequencer view is changed"],
- ["ViewChange", "Triggered after a sequencer view is changed"],
- ["StreamStart", "Triggered after a stream has started"],
- ["StreamPause", "Triggered after a stream has paused"],
- ["StreamEnd", "Triggered after a stream has ended"],
- ["StreamStop", "Triggered after a stream has stopped"],
- ["XulmusEnter", "Triggered after Songbird starts"],
- ["XulmusLeavePre", "Triggered before exiting Songbird, just before destroying each module"],
- ["XulmusLeave", "Triggered before exiting Songbird"]],
+ autocommands: {
+ BookmarkAdd: "Triggered after a page is bookmarked",
+ ColorScheme: "Triggered after a color scheme has been loaded",
+ DOMLoad: "Triggered when a page's DOM content has fully loaded",
+ DownloadPost: "Triggered when a download has completed",
+ Fullscreen: "Triggered when the browser's fullscreen state changes",
+ LocationChange: "Triggered when changing tabs or when navigation to a new location",
+ PageLoadPre: "Triggered after a page load is initiated",
+ PageLoad: "Triggered when a page gets (re)loaded/opened",
+ ShellCmdPost: "Triggered after executing a shell command with :!cmd",
+ TrackChangePre: "Triggered before a playing track is changed",
+ TrackChange: "Triggered after a playing track has changed",
+ ViewChangePre: "Triggered before a sequencer view is changed",
+ ViewChange: "Triggered after a sequencer view is changed",
+ StreamStart: "Triggered after a stream has started",
+ StreamPause: "Triggered after a stream has paused",
+ StreamEnd: "Triggered after a stream has ended",
+ StreamStop: "Triggered after a stream has stopped",
+ Enter: "Triggered after Songbird starts",
+ LeavePre: "Triggered before exiting Songbird, just before destroying each module",
+ Leave: "Triggered before exiting Songbird",
+ },
// TODO: remove those which don't make sense, can't be provided.
- dialogs: [
- ["about", "About Songbird",
+ dialogs: {
+ about: ["About Songbird",
function () { window.openDialog("chrome://songbird/content/xul/about.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
- /*
- ["addbookmark", "Add bookmark for the current page",
- function () { PlacesCommandHook.bookmarkCurrentPage(true, PlacesUtils.bookmarksRootId); }],
- */
- ["addons", "Manage Add-ons",
+ addons: ["Manage Add-ons",
function () { SBOpenPreferences("paneAddons"); }],
- /*
- ["bookmarks", "List your bookmarks",
- function () { window.openDialog("chrome://browser/content/bookmarks/bookmarksPanel.xul", "Bookmarks", "dialog,centerscreen,width=600,height=600"); }],
- */
- ["checkupdates", "Check for updates",
+ checkupdates: ["Check for updates",
function () { window.checkForUpdates(); }],
- ["cleardata", "Clear private data",
+ cleardata: ["Clear private data",
function () { Sanitizer.showUI(); }],
- ["cookies", "List your cookies",
+ cookies: ["List your cookies",
function () { window.toOpenWindowByType("Browser:Cookies", "chrome://browser/content/preferences/cookies.xul", "chrome,dialog=no,resizable"); }],
- ["console", "JavaScript console",
+ console: ["JavaScript console",
function () { window.toJavaScriptConsole(); }],
- /*
- ["customizetoolbar", "Customize the Toolbar",
- function () { window.BrowserCustomizeToolbar(); }],
- */
- ["dominspector", "DOM Inspector",
+ dominspector: ["DOM Inspector",
function () { try { window.inspectDOMDocument(content.document); } catch (e) { dactyl.echoerr("DOM Inspector extension not installed"); } }],
- ["downloads", "Manage Downloads",
+ downloads: ["Manage Downloads",
function () { window.toOpenWindowByType("Download:Manager", "chrome://mozapps/content/downloads/downloads.xul", "chrome,dialog=no,resizable"); }],
- /*
- ["history", "List your history",
- function () { window.openDialog("chrome://browser/content/history/history-panel.xul", "History", "dialog,centerscreen,width=600,height=600"); }],
- ["import", "Import Preferences, Bookmarks, History, etc. from other browsers",
- function () { window.BrowserImport(); }],
- */
- ["jumpto", "Jump to a media item",
+ jumpto: ["Jump to a media item",
function () { onJumpToFileKey(); }],
- ["newsmartplaylist", "Open the file selector dialog",
+ newsmartplaylist: ["Open the file selector dialog",
function () { SBNewSmartPlaylist(); }],
- ["openfile", "Open the file selector dialog",
+ openfile: ["Open the file selector dialog",
function () { SBFileOpen(); }],
- /*
- ["pageinfo", "Show information about the current page",
- function () { window.BrowserPageInfo(); }],
- */
- ["pagesource", "View page source",
+ pagesource: ["View page source",
function () { window.BrowserViewSourceOfDocument(content.document); }],
- ["places", "Places Organizer: Manage your bookmarks and history",
+ places: ["Places Organizer: Manage your bookmarks and history",
function () { PlacesCommandHook.showPlacesOrganizer(ORGANIZER_ROOT_BOOKMARKS); }],
- ["preferences", "Show Songbird preferences dialog",
+ preferences: ["Show Songbird preferences dialog",
function () { window.openPreferences(); }],
- /*
- ["printpreview", "Preview the page before printing",
- function () { PrintUtils.printPreview(onEnterPrintPreview, onExitPrintPreview); }],
- */
- ["printsetup", "Setup the page size and orientation before printing",
+ printsetup: ["Setup the page size and orientation before printing",
function () { PrintUtils.showPageSetup(); }],
- ["print", "Show print dialog",
+ print: ["Show print dialog",
function () { PrintUtils.print(); }],
- ["saveframe", "Save frame to disk",
+ saveframe: ["Save frame to disk",
function () { window.saveFrameDocument(); }],
- ["savepage", "Save page to disk",
+ savepage: ["Save page to disk",
function () { window.saveDocument(window.content.document); }],
- ["searchengines", "Manage installed search engines",
+ searchengines: ["Manage installed search engines",
function () { window.openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
- ["selectionsource", "View selection source",
+ selectionsource: ["View selection source",
function () { buffer.viewSelectionSource(); }],
- ["subscribe", "Add a new subscription",
+ subscribe: ["Add a new subscription",
function () { SBSubscribe(); }]
- ],
+ },
focusChange: function () {
// Switch to -- PLAYER -- mode for Songbird Media Player.
@@ -153,14 +129,27 @@ const Config = Module("config", ConfigBase, {
modes: [["PLAYER", { char: "p" }]],
+ removeTab: function (tab) {
+ if (config.tabbrowser.mTabs.length > 1)
+ config.tabbrowser.removeTab(tab);
+ else {
+ if (buffer.URL != "about:blank" || window.getWebNavigation().sessionHistory.count > 0) {
+ dactyl.open("about:blank", dactyl.NEW_BACKGROUND_TAB);
+ config.tabbrowser.removeTab(tab);
+ }
+ else
+ dactyl.beep();
+ }
+ },
+
scripts: [
- "browser.js",
- "bookmarks.js",
- "history.js",
- "quickmarks.js",
- "tabs.js",
- "player.js",
- "library.js"
+ "browser",
+ "bookmarks",
+ "history",
+ "quickmarks",
+ "tabs",
+ "player",
+ "library"
],
// FIXME: tab arg and media tab exception?