1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-01-06 06:34:13 +01:00

Fix tab number updates in FF36. Closes issue 300.

This commit is contained in:
Kris Maglione
2011-01-26 16:22:29 -05:00
parent a6fe97b787
commit 218562e21b
48 changed files with 498 additions and 8666 deletions

View File

@@ -65,7 +65,7 @@ var Browser = Module("browser", {
mappings: function () {
mappings.add([modes.NORMAL],
["y"], "Yank current location to the clipboard",
["y", "<yank-location>"], "Yank current location to the clipboard",
function () { dactyl.clipboardWrite(buffer.uri.spec, true); });
// opening websites

View File

@@ -1651,7 +1651,7 @@ var Buffer = Module("buffer", {
mappings: function () {
var myModes = config.browserModes;
mappings.add(myModes, ["."],
mappings.add(myModes, [".", "<repeat-key>"],
"Repeat the last key event",
function (args) {
if (mappings.repeat) {
@@ -1670,31 +1670,31 @@ var Buffer = Module("buffer", {
function () { ex.stop(); });
// scrolling
mappings.add(myModes, ["j", "<Down>", "<C-e>"],
mappings.add(myModes, ["j", "<Down>", "<C-e>", "<scroll-down-line>"],
"Scroll document down",
function (args) { buffer.scrollVertical("lines", Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["k", "<Up>", "<C-y>"],
mappings.add(myModes, ["k", "<Up>", "<C-y>", "<scroll-up-line>"],
"Scroll document up",
function (args) { buffer.scrollVertical("lines", -Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, dactyl.has("mail") ? ["h"] : ["h", "<Left>"],
mappings.add(myModes, dactyl.has("mail") ? ["h", "<scroll-left-column>"] : ["h", "<Left>", "<scroll-left-column>"],
"Scroll document to the left",
function (args) { buffer.scrollHorizontal("columns", -Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, dactyl.has("mail") ? ["l"] : ["l", "<Right>"],
mappings.add(myModes, dactyl.has("mail") ? ["l", "<scroll-right-column>"] : ["l", "<Right>", "<scroll-right-column>"],
"Scroll document to the right",
function (args) { buffer.scrollHorizontal("columns", Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["0", "^"],
mappings.add(myModes, ["0", "^", "<scroll-begin>"],
"Scroll to the absolute left of the document",
function () { buffer.scrollToPercent(0, null); });
mappings.add(myModes, ["$"],
mappings.add(myModes, ["$", "<scroll-end>"],
"Scroll to the absolute right of the document",
function () { buffer.scrollToPercent(100, null); });
@@ -1708,7 +1708,7 @@ var Buffer = Module("buffer", {
function (args) { buffer.scrollToPercent(null, args.count != null ? args.count : 100); },
{ count: true });
mappings.add(myModes, ["%"],
mappings.add(myModes, ["%", "<scroll-percent>"],
"Scroll to {count} percent of the document",
function (args) {
dactyl.assert(args.count > 0 && args.count <= 100);
@@ -1716,59 +1716,59 @@ var Buffer = Module("buffer", {
},
{ count: true });
mappings.add(myModes, ["<C-d>"],
mappings.add(myModes, ["<C-d>", "<scroll-down>"],
"Scroll window downwards in the buffer",
function (args) { buffer._scrollByScrollSize(args.count, true); },
{ count: true });
mappings.add(myModes, ["<C-u>"],
mappings.add(myModes, ["<C-u>", "<scroll-up>"],
"Scroll window upwards in the buffer",
function (args) { buffer._scrollByScrollSize(args.count, false); },
{ count: true });
mappings.add(myModes, ["<C-b>", "<PageUp>", "<S-Space>"],
mappings.add(myModes, ["<C-b>", "<PageUp>", "<S-Space>", "<scroll-page-up>"],
"Scroll up a full page",
function (args) { buffer.scrollVertical("pages", -Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["<C-f>", "<PageDown>", "<Space>"],
mappings.add(myModes, ["<C-f>", "<PageDown>", "<Space>", "<scroll-page-down>"],
"Scroll down a full page",
function (args) { buffer.scrollVertical("pages", Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["]f"],
mappings.add(myModes, ["]f", "<previous-frame>"],
"Focus next frame",
function (args) { buffer.shiftFrameFocus(Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["[f"],
mappings.add(myModes, ["[f", "<next-frame>"],
"Focus previous frame",
function (args) { buffer.shiftFrameFocus(-Math.max(args.count, 1)); },
{ count: true });
mappings.add(myModes, ["]]"],
mappings.add(myModes, ["]]", "<next-page>"],
"Follow the link labeled 'next' or '>' if it exists",
function (args) {
buffer.findLink("next", options["nextpattern"], (args.count || 1) - 1, true);
},
{ count: true });
mappings.add(myModes, ["[["],
mappings.add(myModes, ["[[", "<previous-page>"],
"Follow the link labeled 'prev', 'previous' or '<' if it exists",
function (args) {
buffer.findLink("previous", options["previouspattern"], (args.count || 1) - 1, true);
},
{ count: true });
mappings.add(myModes, ["gf"],
mappings.add(myModes, ["gf", "<view-source>"],
"Toggle between rendered and source view",
function () { buffer.viewSource(null, false); });
mappings.add(myModes, ["gF"],
mappings.add(myModes, ["gF", "<view-source-externally>"],
"View source with an external editor",
function () { buffer.viewSource(null, true); });
mappings.add(myModes, ["gi"],
mappings.add(myModes, ["gi", "<focus-input>"],
"Focus last used input field",
function (args) {
let elem = buffer.lastInputField;
@@ -1808,7 +1808,7 @@ var Buffer = Module("buffer", {
dactyl.open(url, { from: "paste", where: dactyl.NEW_TAB, background: true });
});
mappings.add(myModes, ["p", "<MiddleMouse>"],
mappings.add(myModes, ["p", "<MiddleMouse>", "<open-clipboard-url>"],
"Open (put) a URL based on the current clipboard contents in the current buffer",
function () {
let url = dactyl.clipboardRead();
@@ -1816,7 +1816,7 @@ var Buffer = Module("buffer", {
dactyl.open(url);
});
mappings.add(myModes, ["P"],
mappings.add(myModes, ["P", "<tab-open-clipboard-url>"],
"Open (put) a URL based on the current clipboard contents in a new buffer",
function () {
let url = dactyl.clipboardRead();
@@ -1825,16 +1825,16 @@ var Buffer = Module("buffer", {
});
// reloading
mappings.add(myModes, ["r"],
mappings.add(myModes, ["r", "<reload>"],
"Reload the current web page",
function () { tabs.reload(tabs.getTab(), false); });
mappings.add(myModes, ["R"],
mappings.add(myModes, ["R", "<full-reload>"],
"Reload while skipping the cache",
function () { tabs.reload(tabs.getTab(), true); });
// yanking
mappings.add(myModes, ["Y"],
mappings.add(myModes, ["Y", "<yank-word>"],
"Copy selected text or current word",
function () {
let sel = buffer.getCurrentWord();
@@ -1843,62 +1843,62 @@ var Buffer = Module("buffer", {
});
// zooming
mappings.add(myModes, ["zi", "+"],
mappings.add(myModes, ["zi", "+", "<text-zoom-in>"],
"Enlarge text zoom of current web page",
function (args) { buffer.zoomIn(Math.max(args.count, 1), false); },
{ count: true });
mappings.add(myModes, ["zm"],
mappings.add(myModes, ["zm", "<text-zoom-more>"],
"Enlarge text zoom of current web page by a larger amount",
function (args) { buffer.zoomIn(Math.max(args.count, 1) * 3, false); },
{ count: true });
mappings.add(myModes, ["zo", "-"],
mappings.add(myModes, ["zo", "-", "<text-zoom-out>"],
"Reduce text zoom of current web page",
function (args) { buffer.zoomOut(Math.max(args.count, 1), false); },
{ count: true });
mappings.add(myModes, ["zr"],
mappings.add(myModes, ["zr", "<text-zoom-reduce>"],
"Reduce text zoom of current web page by a larger amount",
function (args) { buffer.zoomOut(Math.max(args.count, 1) * 3, false); },
{ count: true });
mappings.add(myModes, ["zz"],
mappings.add(myModes, ["zz", "<text-zoom>"],
"Set text zoom value of current web page",
function (args) { buffer.setZoom(args.count > 1 ? args.count : 100, false); },
{ count: true });
mappings.add(myModes, ["ZI", "zI"],
mappings.add(myModes, ["ZI", "zI", "<full-zoom-in>"],
"Enlarge full zoom of current web page",
function (args) { buffer.zoomIn(Math.max(args.count, 1), true); },
{ count: true });
mappings.add(myModes, ["ZM", "zM"],
mappings.add(myModes, ["ZM", "zM", "<full-zoom-more>"],
"Enlarge full zoom of current web page by a larger amount",
function (args) { buffer.zoomIn(Math.max(args.count, 1) * 3, true); },
{ count: true });
mappings.add(myModes, ["ZO", "zO"],
mappings.add(myModes, ["ZO", "zO", "<full-zoom-out>"],
"Reduce full zoom of current web page",
function (args) { buffer.zoomOut(Math.max(args.count, 1), true); },
{ count: true });
mappings.add(myModes, ["ZR", "zR"],
mappings.add(myModes, ["ZR", "zR", "<full-zoom-reduce>"],
"Reduce full zoom of current web page by a larger amount",
function (args) { buffer.zoomOut(Math.max(args.count, 1) * 3, true); },
{ count: true });
mappings.add(myModes, ["zZ"],
mappings.add(myModes, ["zZ", "<full-zoom>"],
"Set full zoom value of current web page",
function (args) { buffer.setZoom(args.count > 1 ? args.count : 100, true); },
{ count: true });
// page info
mappings.add(myModes, ["<C-g>"],
mappings.add(myModes, ["<C-g>", "<page-info>"],
"Print the current file name",
function () { buffer.showPageInfo(false); });
mappings.add(myModes, ["g<C-g>"],
mappings.add(myModes, ["g<C-g>", "<more-page-info>"],
"Print file information",
function () { buffer.showPageInfo(true); });
},

View File

@@ -148,12 +148,6 @@ var CommandWidgets = Class("CommandWidgets", {
return this.commandbar;
}
});
let fontSize = util.computedStyle(document.documentElement).fontSize;
styles.system.add("font-size", "dactyl://content/buffer.xhtml",
"body { font-size: " + fontSize + "; } \
html|html > xul|scrollbar { visibility: collapse !important; }",
true);
},
addElement: function addElement(obj) {
const self = this;
@@ -301,18 +295,10 @@ var CommandMode = Class("CommandMode", {
this.keepCommand = userContext.hidden_option_command_afterimage;
if (this.historyKey)
this.history = CommandLine.History(commandline.widgets.active.command.inputField, this.historyKey);
this.history = CommandLine.History(commandline.widgets.active.command.inputField, this.historyKey, this);
if (this.complete)
this.completions = CommandLine.Completions(commandline.widgets.active.command.inputField);
this.autocompleteTimer = Timer(200, 500, function autocompleteTell(tabPressed) {
if (!events.feedingKeys && this.completions && options["autocomplete"].length) {
this.completions.complete(true, false);
if (this.completions)
this.completions.itemList.visible = true;
}
}, this);
this.completions = CommandLine.Completions(commandline.widgets.active.command.inputField, this);
},
open: function (command) {
@@ -335,17 +321,14 @@ var CommandMode = Class("CommandMode", {
commandline.commandSession = this;
if (this.command || stack.pop && commandline.command) {
this.onChange(commandline.command);
this.autocompleteTimer.flush(true);
if (this.completions)
this.completions.autocompleteTimer.flush(true);
}
},
leave: function (stack) {
this.autocompleteTimer.reset();
if (this.completions) {
this.completions.previewClear();
this.completions.tabTimer.reset();
}
if (this.completions)
this.completions.cleanup();
if (this.history)
this.history.save();
@@ -368,9 +351,9 @@ var CommandMode = Class("CommandMode", {
if (this.completions) {
this.resetCompletions();
this.autocompleteTimer.tell(false);
this.completions.autocompleteTimer.tell(false);
if (!this.completions.itemList.visible)
this.autocompleteTimer.flush();
this.completions.autocompleteTimer.flush();
}
this.onChange(commandline.command);
},
@@ -614,8 +597,10 @@ var CommandLine = Module("commandline", {
if (this.widgets.message && this.widgets.message[1] === this._lastClearable)
this.widgets.message = null;
if (modes.main != modes.COMMAND_LINE)
if (!this.commandSession) {
this.widgets.command = null;
this.hideCompletions();
}
if (modes.main == modes.OUTPUT_MULTILINE && !mow.isScrollable(1))
modes.pop();
@@ -866,10 +851,11 @@ var CommandLine = Module("commandline", {
* @param {string} mode The mode for which we need history.
*/
History: Class("History", {
init: function init(inputField, mode) {
init: function init(inputField, mode, session) {
this.mode = mode;
this.input = inputField;
this.reset();
this.session = session;
},
get store() commandline._store.get(this.mode, []),
set store(ary) { commandline._store.set(this.mode, ary); },
@@ -915,8 +901,9 @@ var CommandLine = Module("commandline", {
*/
replace: function replace(val) {
delete this.input.dactylKeyPress;
if (this.completions)
this.completions.previewClear();
this.input.value = val;
commandline.commandSession.onChange(val, "history");
},
/**
@@ -928,8 +915,8 @@ var CommandLine = Module("commandline", {
*/
select: function select(backward, matchCurrent) {
// always reset the tab completion if we use up/down keys
if (commandline._completions)
commandline._completions.reset();
if (this.session.completions)
this.session.completions.reset();
let diff = backward ? -1 : 1;
@@ -976,22 +963,36 @@ var CommandLine = Module("commandline", {
* @param {Object} input
*/
Completions: Class("Completions", {
init: function init(input) {
init: function init(input, session) {
this.context = CompletionContext(input.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
this.context.onUpdate = this.closure._reset;
this.editor = input.editor;
this.input = input;
this.session = session;
this.selected = null;
this.wildmode = options.get("wildmode");
this.wildtypes = this.wildmode.value;
this.itemList = commandline.completionList;
this.itemList.setItems(this.context);
this.autocompleteTimer = Timer(200, 500, function autocompleteTell(tabPressed) {
if (!events.feedingKeys && options["autocomplete"].length) {
this.complete(true, false);
this.itemList.visible = true;
}
}, this);
this.tabTimer = Timer(0, 0, function tabTell(event) {
this.tab(event.shiftKey, event.altKey && options["altwildmode"]);
}, this);
},
cleanup: function () {
this.previewClear();
this.tabTimer.reset();
this.autocompleteTimer.reset();
this.itemList.visible = false;
},
UP: {},
DOWN: {},
PAGE_UP: {},
@@ -1038,7 +1039,7 @@ var CommandLine = Module("commandline", {
complete: function complete(show, tabPressed) {
this.context.reset();
this.context.tabPressed = tabPressed;
commandline.commandSession.complete(this.context);
this.session.complete(this.context);
this.context.updateAsync = true;
this.reset(show, tabPressed);
this.wildIndex = 0;
@@ -1204,7 +1205,7 @@ var CommandLine = Module("commandline", {
tabs: [],
tab: function tab(reverse, wildmode) {
commandline.commandSession.autocompleteTimer.flush();
this.autocompleteTimer.flush();
if (this._caret != this.caret)
this.reset();

View File

@@ -110,10 +110,10 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
get menuItems() Dactyl.getMenuItems(),
// Global constants
CURRENT_TAB: [],
NEW_TAB: [],
NEW_BACKGROUND_TAB: [],
NEW_WINDOW: [],
CURRENT_TAB: "here",
NEW_TAB: "tab",
NEW_BACKGROUND_TAB: "background-tab",
NEW_WINDOW: "window",
forceNewTab: false,
forceNewWindow: false,
@@ -173,7 +173,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
let filters = args.map(function (arg) RegExp("\\b" + util.regexp.escape(arg) + "\\b", "i"));
if (filters.length)
results = results.filter(function (item) filters.every(function (re) re.test(item.name + item.description)));
results = results.filter(function (item) filters.every(function (re) re.test(item.name + " " + item.description)));
commandline.commandOutput(
template.usage(results, params.format));
@@ -380,15 +380,16 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
},
userEval: function (str, context, fileName, lineNumber) {
let ctxt;
if (jsmodules.__proto__ != window)
str = "with (window) { with (modules) { (this.eval || eval)(" + str.quote() + ") } }";
if (fileName == null)
if (io.sourcing && io.sourcing.file[0] !== "[")
({ file: fileName, line: lineNumber }) = io.sourcing;
({ file: fileName, line: lineNumber, context: ctxt }) = io.sourcing;
else try {
if (!context)
context = userContext;
context = userContext || ctxt;
context[EVAL_ERROR] = null;
context[EVAL_STRING] = str;
@@ -411,7 +412,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
}
if (!context)
context = _userContext;
context = _userContext || ctxt;
return Cu.evalInSandbox(str, context, "1.8", fileName, lineNumber);
},
@@ -560,9 +561,14 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
* @private
*/
initDocument: function initDocument(doc) {
if (doc.location.protocol === "dactyl:") {
dactyl.initHelp();
config.styleHelp();
try {
if (doc.location.protocol === "dactyl:") {
dactyl.initHelp();
config.styleHelp();
}
}
catch (e) {
util.reportError(e);
}
},
@@ -662,9 +668,9 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
let re = util.regexp(<![CDATA[
^ (?P<space> \s*)
(?P<char> [-*+]) \x20
(?P<char> [-*+]) \ //
(?P<content> .*\n
(?: \1\x20\x20.*\n | \s*\n)* )
(?: \1\ \ .*\n | \s*\n)* )
|
(?P<par>
(?: ^ [^\S\n]*
@@ -676,30 +682,55 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
(?: ^ [^\S\n]* \n) +
]]>, "gmy");
let betas = util.regexp(/\[(b\d)\]/, "g");
let beta = array(betas.iterate(NEWS))
.map(function (m) m[1]).uniq().slice(-1)[0];
default xml namespace = NS;
function rec(text, level) {
function rec(text, level, li) {
let res = <></>;
let list, space;
let list, space, i = 0;
for (let match in re.iterate(text)) {
if (match.char) {
if (!list)
res += list = <ul/>;
list.* += <li>{rec(match.content.replace(RegExp("^" + match.space, "gm"), ""), level + 1)}</li>;
let li = <li/>;
li.* += rec(match.content.replace(RegExp("^" + match.space, "gm"), ""), level + 1, li)
list.* += li;
}
else if (match.par) {
let [, par, tags] = /([^]*?)\s*((?:\[[^\]]+\])*)\n*$/.exec(match.par);
let t = tags;
tags = array(betas.iterate(tags)).map(function (m) m[1]);
let group = tags.length && !tags.some(function (t) t == beta) ? "HelpNewsOld" : "";
if (i === 0 && li) {
li.@highlight = group;
group = "";
}
list = null;
if (level == 0 && /^.*:\n$/.test(match.par))
res += <h2>{template.linkifyHelp(match.par.slice(0, -1), true)}</h2>;
if (level == 0 && /^.*:\n$/.test())
var elem = <h2>{template.linkifyHelp(par.slice(0, -1), true)}</h2>;
else {
let [, a, b] = /^(IMPORTANT:?)?([^]*)/.exec(match.par);
res += <p>{
let [, a, b] = /^(IMPORTANT:?)?([^]*)/.exec(par);
res += <p highlight={group + " HelpNews"}>{
!tags.length ? "" :
<hl key="HelpNewsTag">{tags.join(" ")}</hl>
}{
a ? <hl key="HelpWarning">{a}</hl> : ""
}{
template.linkifyHelp(b, true)
}</p>;
}
}
i++;
}
for each (let attr in res..@highlight) {
attr.parent().@NS::highlight = attr;
delete attr.parent().@highlight;
}
return res;
}
@@ -710,7 +741,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
'<?xml-stylesheet type="text/xsl" href="dactyl://content/help.xsl"?>\n' +
'<!DOCTYPE document SYSTEM "resource://dactyl-content/dactyl.dtd">\n' +
unescape(encodeURI( // UTF-8 handling hack.
<document xmlns={NS}
<document xmlns={NS} xmlns:dactyl={NS}
name="versions" title={config.appName + " Versions"}>
<h1 tag="versions news">{config.appName} Versions</h1>
<toc start="2"/>

View File

@@ -11,12 +11,14 @@
var ProcessorStack = Class("ProcessorStack", {
init: function (mode, hives, keyModes) {
this.main = mode.main;
this._actions = [];
this.actions = [];
this.buffer = "";
this.events = [];
this.processors = keyModes.map(function (m) hives.map(function (h) KeyProcessor(m, h)))
.flatten().array;
this.ownsBuffer = !this.processors.some(function (p) p.main.ownsBuffer);
for (let [i, input] in Iterator(this.processors)) {
let params = input.main.params;
@@ -31,9 +33,70 @@ var ProcessorStack = Class("ProcessorStack", {
}
},
notify: function () {
this.execute(Events.KILL, true);
},
execute: function execute(result, force) {
if (force && this.actions.length)
this.processors.length = 0;
if (this.ownsBuffer)
statusline.updateInputBuffer(this.processors.length ? this.buffer : "");
if (this.processors.length) {
result = Events.KILL;
if (this.actions.length && options["timeout"])
this.timer = services.Timer(this, options["timeoutlen"], services.Timer.TYPE_ONE_SHOT);
}
else if (this.actions.length) {
if (this._actions.length == 0) {
dactyl.beep();
events.feedingKeys = false;
}
for (var res = this.actions[0]; callable(res);)
res = res();
result = res === Events.PASS ? Events.PASS : Events.KILL;
}
else if (result !== Events.KILL && !this.actions.length &&
this.processors.some(function (p) !p.main.passUnknown)) {
result = Events.KILL;
dactyl.beep();
events.feedingKeys = false;
}
else if (result === undefined)
result = Events.PASS;
if (result !== Events.PASS)
Events.kill(this.events[this.events.length - 1]);
if (result === Events.PASS || result === Events.ABORT)
this.events.filter(function (e) e.getPreventDefault())
.forEach(function (event, i) {
let elem = event.originalTarget;
if (event.originalTarget) {
let doc = elem.ownerDocument || elem.document || elem;
let evt = events.create(doc, event.type, event);
events.dispatch(elem, evt, { skipmap: true, isMacro: true, isReplay: true });
}
else if (i > 0)
events.events.keypress.call(events, event);
});
if (force && this.processors.length === 0)
events.processor = null;
return this.processors.length == 0;
},
process: function process(event) {
function dbg() {}
if (this.timer)
this.timer.cancel();
let key = events.toString(event);
this.events.push(event);
@@ -70,9 +133,7 @@ var ProcessorStack = Class("ProcessorStack", {
dbg("ACTIONS: " + actions.length + " " + this.actions.length);
dbg("PROCESSORS:", processors);
if (!processors.some(function (p) p.main.ownsBuffer))
statusline.updateInputBuffer(processors.length ? this.buffer : "");
this._actions = actions;
this.actions = actions.concat(this.actions);
if (result === Events.KILL)
@@ -87,42 +148,7 @@ var ProcessorStack = Class("ProcessorStack", {
this.processors = processors;
if (processors.length)
result = Events.KILL;
else if (this.actions.length) {
if (actions.length == 0)
dactyl.beep();
if (modes.replaying && !events.waitForPageLoad())
result = Events.KILL;
else {
for (var res = this.actions[0]; callable(res);)
res = res();
result = res === Events.PASS ? Events.PASS : Events.KILL;
}
}
else if (result !== Events.KILL && !this.actions.length &&
processors.some(function (p) !p.main.passUnknown)) {
result = Events.KILL;
dactyl.beep();
}
else if (result === undefined)
result = Events.PASS;
if (result !== Events.PASS)
Events.kill(event);
if (result === Events.PASS || result === Events.ABORT)
this.events.filter(function (e) e.getPreventDefault())
.forEach(function (event, i) {
if (event.originalTarget) {
let evt = events.create(event.originalTarget.ownerDocument, event.type, event);
events.dispatch(event.originalTarget, evt, { skipmap: true, isMacro: true });
}
else if (i > 0)
events.events.keypress.call(events, event);
});
return this.processors.length == 0;
return this.execute(result, options["timeout"] && options["timeoutlen"] === 0)
}
});
@@ -491,6 +517,7 @@ var Events = Module("events", {
util.threadYield(1, true);
for (let [, evt_obj] in Iterator(events.fromString(keys))) {
let now = Date.now();
for (let type in values(["keydown", "keyup", "keypress"])) {
let evt = update({}, evt_obj, { type: type });
@@ -511,10 +538,6 @@ var Events = Module("events", {
if (!this.feedingKeys)
break;
// Stop feeding keys if page loading failed.
if (modes.replaying && !this.waitForPageLoad())
break;
}
}
catch (e) {
@@ -594,9 +617,14 @@ var Events = Module("events", {
* of x.
*
* @param {string} keys Messy form.
* @param {boolean} unknownOk Whether unknown keys are passed
* through rather than being converted to <lt>keyname>.
* @default false
* @returns {string} Canonical form.
*/
canonicalKeys: function (keys, unknownOk) {
if (arguments.length === 1)
unknownOk = true;
return events.fromString(keys, unknownOk).map(events.closure.toString).join("");
},
@@ -651,11 +679,17 @@ var Events = Module("events", {
* <S-@> where @ is a non-case-changeable, non-space character.
*
* @param {string} keys The string to parse.
* @param {boolean} unknownOk Whether unknown keys are passed
* through rather than being converted to <lt>keyname>.
* @default false
* @returns {Array[Object]}
*/
fromString: function (input, unknownOk) {
let out = [];
if (arguments.length === 1)
unknownOk = true;
let out = [];
let re = RegExp("<.*?>?>|[^<]|<(?!.*>)", "g");
let match;
while ((match = re.exec(input))) {
@@ -862,10 +896,7 @@ var Events = Module("events", {
isContentNode: function isContentNode(node) {
let win = (node.ownerDocument || node).defaultView || node;
for (; win; win = win.parent != win && win.parent)
if (win == content)
return true;
return false;
return XPCNativeWrapper(win).top == content;
},
/**
@@ -874,39 +905,24 @@ var Events = Module("events", {
*
* @returns {boolean}
*/
waitForPageLoad: function () {
waitForPageLoad: function (time) {
util.threadYield(true); // clear queue
if (buffer.loaded == 1)
if (buffer.loaded)
return true;
const maxWaitTime = 25;
dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE);
const maxWaitTime = (time || 25);
let start = Date.now();
let end = start + (maxWaitTime * 1000); // maximum time to wait - TODO: add option
let now;
while (now = Date.now(), now < end) {
util.threadYield();
let end = start + (maxWaitTime * 1000);
if (!events.feedingKeys)
return false;
if (buffer.loaded > 0) {
util.sleep(250);
break;
}
else
dactyl.echo("Waiting for page to load...", commandline.DISALLOW_MULTILINE);
}
util.waitFor(function () !events.feedingKeys || buffer.loaded || Date.now() > end);
commandline.clear();
// TODO: allow macros to be continued when page does not fully load with an option
if (!buffer.loaded)
dactyl.echoerr("Page did not load completely in " + maxWaitTime + " seconds. Macro stopped.");
// sometimes the input widget had focus when replaying a macro
// maybe this call should be moved somewhere else?
// dactyl.focusContent(true);
return buffer.loaded;
},
@@ -1000,7 +1016,8 @@ var Events = Module("events", {
*/
input: function onInput(event) {
delete event.originalTarget.dactylKeyPress;
if ("dactylKeyPress" in event.originalTarget)
delete event.originalTarget.dactylKeyPress;
},
// this keypress handler gets always called first, even if e.g.
@@ -1024,18 +1041,17 @@ var Events = Module("events", {
let duringFeed = this.duringFeed || [];
this.duringFeed = [];
try {
if (this.feedingEvent && [!(k in event) || event[k] === v for ([k, v] in Iterator(this.feedingEvent))].every(util.identity)) {
if (this.feedingEvent)
for (let [k, v] in Iterator(this.feedingEvent))
if (!(k in event))
event[k] = v;
this.feedingEvent = null;
}
this.feedingEvent = null;
let key = events.toString(event);
if (!key)
return null;
if (modes.recording && (!this._input || !mappings.user.hasMap(modes.main, this._input.buffer + key)))
if (modes.recording && !event.isReplay)
events._macroKeys.push(key);
// feedingKeys needs to be separate from interrupted so
@@ -1043,8 +1059,6 @@ var Events = Module("events", {
// interrupting whatever it's started and a real <C-c>
// interrupting our playback.
if (events.feedingKeys && !event.isMacro) {
if (!event.originalTarget)
util.dumpStack();
if (key == "<C-c>") {
events.feedingKeys = false;
if (modes.replaying) {
@@ -1177,10 +1191,6 @@ var Events = Module("events", {
// access to the real focus target
// Huh? --djk
onFocusChange: function onFocusChange(event) {
// command line has its own focus change handler
if (modes.main.input)
return;
function hasHTMLDocument(win) win && win.document && win.document instanceof HTMLDocument
let win = window.document.commandDispatcher.focusedWindow;
@@ -1202,7 +1212,7 @@ var Events = Module("events", {
}
if (Events.isInputElement(elem)) {
if (!(modes.main & (modes.INSERT | modes.TEXT_EDIT | modes.VISUAL)))
if (!modes.main.input)
modes.push(modes.INSERT);
if (hasHTMLDocument(win))
@@ -1216,7 +1226,7 @@ var Events = Module("events", {
if (modes.main == modes.VISUAL && elem.selectionEnd == elem.selectionStart)
modes.pop();
if (!(modes.main & (modes.INSERT | modes.TEXT_EDIT | modes.VISUAL)))
if (!modes.main.input)
if (options["insertmode"])
modes.push(modes.INSERT);
else {
@@ -1323,11 +1333,11 @@ var Events = Module("events", {
},
mappings: function () {
mappings.add(modes.all,
["<C-z>"], "Temporarily ignore all " + config.appName + " key bindings",
["<C-z>", "<pass-all-keys>"], "Temporarily ignore all " + config.appName + " key bindings",
function () { modes.push(modes.PASS_THROUGH); });
mappings.add(modes.all,
["<C-v>"], "Pass through next key",
["<C-v>", "<pass-next-key>"], "Pass through next key",
function () {
if (modes.main == modes.QUOTE)
return Events.PASS;
@@ -1340,7 +1350,7 @@ var Events = Module("events", {
// macros
mappings.add([modes.NORMAL, modes.TEXT_AREA, modes.PLAYER].filter(util.identity),
["q"], "Record a key sequence into a macro",
["q", "<record-macro>"], "Record a key sequence into a macro",
function ({ arg }) {
events._macroKeys.pop();
events[modes.recording ? "finishRecording" : "startRecording"](arg);
@@ -1348,13 +1358,33 @@ var Events = Module("events", {
{ get arg() !modes.recording });
mappings.add([modes.NORMAL, modes.TEXT_AREA, modes.PLAYER].filter(util.identity),
["@"], "Play a macro",
["@", "<play-macro>"], "Play a macro",
function ({ arg, count }) {
count = Math.max(count, 1);
while (count-- && events.playMacro(arg))
;
},
{ arg: true, count: true });
mappings.add([modes.COMMAND],
["<A-m>s", "<sleep>"], "Sleep for {count} milliseconds before continuing macro playback",
function ({ command, count }) {
let now = Date.now();
dactyl.assert(count, "Count required for " + command);
if (events.feedingKeys)
util.sleep(count);
},
{ count: true });
mappings.add([modes.COMMAND],
["<A-m>l", "<wait-for-page-load>"], "Wait for the current page to finish loading before continuing macro playback",
function ({ count }) {
if (events.feedingKeys && !events.waitForPageLoad(count)) {
util.interrupted = true;
throw Error("Interrupted");
}
},
{ count: true });
},
options: function () {
options.add(["passkeys", "pk"],
@@ -1375,9 +1405,18 @@ var Events = Module("events", {
return values;
}
});
options.add(["strictfocus", "sf"],
"Prevent scripts from focusing input elements without user intervention",
"boolean", true);
options.add(["timeout", "tmo"],
"Whether to execute a shorter key command after a timeout when a longer command exists",
"boolean", true);
options.add(["timeoutlen", "tmol"],
"Maximum time (milliseconds) to wait for a longer key command when a shorter one exists",
"number", 1000);
},
sanitizer: function () {
sanitizer.addItem("macros", {

View File

@@ -113,9 +113,17 @@ var Map = Class("Map", {
if (this.executing)
util.dumpStack("Attempt to execute mapping recursively: " + args.command);
dactyl.assert(!this.executing, "Attempt to execute mapping recursively: " + args.command);
this.executing = true;
let res = dactyl.trapErrors(repeat);
this.executing = false;
try {
this.executing = true;
var res = repeat();
}
catch (e) {
events.feedingKeys = false;
}
finally {
this.executing = false;
}
return res;
}
@@ -507,7 +515,7 @@ var Mappings = Module("mappings", {
description: "Accept a count before the requisite key press"
},
{
names: ["-description", "-d"],
names: ["-description", "-desc", "-d"],
description: "A description of this mapping",
default: "User-defined mapping",
type: CommandOption.STRING

View File

@@ -8,6 +8,12 @@
var MOW = Module("mow", {
init: function () {
let fontSize = util.computedStyle(document.documentElement).fontSize;
styles.system.add("font-size", "dactyl://content/buffer.xhtml",
"body { font-size: " + fontSize + "; } \
html|html > xul|scrollbar { visibility: collapse !important; }",
true);
XML.ignoreWhitespace = true;
util.overlayWindow(window, {
objects: {

View File

@@ -867,9 +867,11 @@ var Tabs = Module("tabs", {
},
events: function () {
let tabContainer = config.tabbrowser.mTabContainer;
["TabMove", "TabOpen", "TabClose"].forEach(function (event) {
events.addSessionListener(tabContainer, event, this.closure.updateTabCount, false);
}, this);
function callback() {
tabs.timeout(function () { this.updateTabCount(); });
}
for (let event in values(["TabMove", "TabOpen", "TabClose"]))
events.addSessionListener(tabContainer, event, callback, false);
events.addSessionListener(tabContainer, "TabSelect", this.closure._onTabSelect, false);
},
mappings: function () {