1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-22 04:07:59 +01:00

Get rid of horrible coalesced event handlers in commandline.js.

--HG--
branch : key-processing
This commit is contained in:
Kris Maglione
2011-01-24 12:50:08 -05:00
parent 56777f59c3
commit 9786171520
10 changed files with 181 additions and 206 deletions

View File

@@ -9,11 +9,16 @@
/** @scope modules */ /** @scope modules */
var CommandWidgets = Class("CommandWidgets", { var CommandWidgets = Class("CommandWidgets", {
init: function () { depends: ["statusline"],
let _status = "dactyl-statusline-field-";
init: function init() {
let s = "dactyl-statusline-field-";
XML.ignoreWhitespace = true; XML.ignoreWhitespace = true;
util.overlayWindow(window, { util.overlayWindow(window, {
objects: {
eventTarget: commandline
},
append: <e4x xmlns={XUL} xmlns:dactyl={NS}> append: <e4x xmlns={XUL} xmlns:dactyl={NS}>
<window id={document.documentElement.id}> <window id={document.documentElement.id}>
<popupset> <popupset>
@@ -39,16 +44,15 @@ var CommandWidgets = Class("CommandWidgets", {
<vbox class="dactyl-container" id="dactyl-multiline-output-container" hidden="false" collapsed="true"> <vbox class="dactyl-container" id="dactyl-multiline-output-container" hidden="false" collapsed="true">
<iframe id="dactyl-multiline-output" src="dactyl://content/buffer.xhtml" <iframe id="dactyl-multiline-output" src="dactyl://content/buffer.xhtml"
flex="1" hidden="false" collapsed="false" flex="1" hidden="false" collapsed="false" contextmenu="dactyl-contextmenu"
contextmenu="dactyl-contextmenu" highlight="Events" events="multilineOutputEvents" />
onclick="dactyl.modules.commandline.onMultilineOutputEvent(event)"/>
</vbox> </vbox>
<vbox class="dactyl-container" hidden="false" collapsed="true"> <vbox class="dactyl-container" hidden="false" collapsed="true">
<iframe class="dactyl-completions" id="dactyl-completions-dactyl-commandline" src="dactyl://content/buffer.xhtml" <iframe class="dactyl-completions" id="dactyl-completions-dactyl-commandline" src="dactyl://content/buffer.xhtml"
contextmenu="dactyl-contextmenu" contextmenu="dactyl-contextmenu"
flex="1" hidden="false" collapsed="false" flex="1" hidden="false" collapsed="false"
onclick="dactyl.modules.commandline.onMultilineOutputEvent(event)"/> highlight="Events" events="multilineOutputEvents" />
</vbox> </vbox>
<stack orient="horizontal" align="stretch" class="dactyl-container" id="dactyl-container" highlight="CmdLine CmdCmdLine"> <stack orient="horizontal" align="stretch" class="dactyl-container" id="dactyl-container" highlight="CmdLine CmdCmdLine">
@@ -59,30 +63,31 @@ var CommandWidgets = Class("CommandWidgets", {
<hbox id="dactyl-commandline" hidden="false" class="dactyl-container" highlight="Normal CmdNormal" collapsed="true"> <hbox id="dactyl-commandline" hidden="false" class="dactyl-container" highlight="Normal CmdNormal" collapsed="true">
<label id="dactyl-commandline-prompt" class="dactyl-commandline-prompt plain" flex="0" crop="end" value="" collapsed="true"/> <label id="dactyl-commandline-prompt" class="dactyl-commandline-prompt plain" flex="0" crop="end" value="" collapsed="true"/>
<textbox id="dactyl-commandline-command" class="dactyl-commandline-command plain" flex="1" type="input" timeout="100" <textbox id="dactyl-commandline-command" class="dactyl-commandline-command plain" flex="1" type="input" timeout="100"
oninput="dactyl.modules.commandline.onEvent(event);" highlight="Events" />
onkeyup="dactyl.modules.commandline.onEvent(event);"
onfocus="dactyl.modules.commandline.onEvent(event);"
onblur="dactyl.modules.commandline.onEvent(event);"/>
</hbox> </hbox>
</stack> </stack>
<vbox class="dactyl-container" hidden="false" collapsed="false" highlight="CmdLine"> <vbox class="dactyl-container" hidden="false" collapsed="false" highlight="CmdLine">
<textbox id="dactyl-multiline-input" class="plain" flex="1" rows="1" hidden="false" collapsed="true" multiline="true" <textbox id="dactyl-multiline-input" class="plain" flex="1" rows="1" hidden="false" collapsed="true" multiline="true"
highlight="Normal" highlight="Normal Events" events="multilineInputEvents" />
onkeypress="dactyl.modules.commandline.onMultilineInputEvent(event);"
oninput="dactyl.modules.commandline.onMultilineInputEvent(event);"
onblur="dactyl.modules.commandline.onMultilineInputEvent(event);"/>
</vbox> </vbox>
</vbox> </vbox>
<stack id="dactyl-statusline-stack">
<hbox id={s + "commandline"} hidden="false" class="dactyl-container" highlight="Normal StatusNormal" collapsed="true">
<label id={s + "commandline-prompt"} class="dactyl-commandline-prompt plain" flex="0" crop="end" value="" collapsed="true"/>
<textbox id={s + "commandline-command"} class="dactyl-commandline-command plain" flex="1" type="text" timeout="100"
highlight="Events" />
</hbox>
</stack>
</e4x>.elements(), </e4x>.elements(),
before: <e4x xmlns={XUL} xmlns:dactyl={NS}> before: <e4x xmlns={XUL} xmlns:dactyl={NS}>
<toolbar id={statusline.statusBar.id}> <toolbar id={statusline.statusBar.id}>
<vbox id={"dactyl-completions-" + _status + "commandline-container"} class="dactyl-container" hidden="false" collapsed="true"> <vbox id={"dactyl-completions-" + s + "commandline-container"} class="dactyl-container" hidden="false" collapsed="true">
<iframe class="dactyl-completions" id={"dactyl-completions-" + _status + "commandline"} src="dactyl://content/buffer.xhtml" <iframe class="dactyl-completions" id={"dactyl-completions-" + s + "commandline"} src="dactyl://content/buffer.xhtml"
contextmenu="dactyl-contextmenu" contextmenu="dactyl-contextmenu" flex="1" hidden="false" collapsed="false"
flex="1" hidden="false" collapsed="false" highlight="Events" events="multilineOutputEvents" />
onclick="dactyl.modules.commandline.onMultilineOutputEvent(event)"/>
</vbox> </vbox>
</toolbar> </toolbar>
</e4x>.elements() </e4x>.elements()
@@ -171,7 +176,7 @@ var CommandWidgets = Class("CommandWidgets", {
html|html > xul|scrollbar { visibility: collapse !important; }", html|html > xul|scrollbar { visibility: collapse !important; }",
true); true);
}, },
addElement: function (obj) { addElement: function addElement(obj) {
const self = this; const self = this;
this.elements[obj.name] = obj; this.elements[obj.name] = obj;
@@ -185,13 +190,13 @@ var CommandWidgets = Class("CommandWidgets", {
if (!(obj.noValue || obj.getValue)) if (!(obj.noValue || obj.getValue))
Object.defineProperty(this, obj.name, Modes.boundProperty({ Object.defineProperty(this, obj.name, Modes.boundProperty({
get: function () { get: function get_widgetValue() {
let elem = self.getGroup(obj.name, obj.value)[obj.name]; let elem = self.getGroup(obj.name, obj.value)[obj.name];
if (obj.value != null) if (obj.value != null)
return [obj.value[0], obj.get ? obj.get.call(this, elem) : elem.value]; return [obj.value[0], obj.get ? obj.get.call(this, elem) : elem.value];
return null; return null;
}, },
set: function (val) { set: function set_widgetValue(val) {
if (val != null && !isArray(val)) if (val != null && !isArray(val))
val = [obj.defaultGroup || "", val]; val = [obj.defaultGroup || "", val];
obj.value = val; obj.value = val;
@@ -222,12 +227,12 @@ var CommandWidgets = Class("CommandWidgets", {
.map(function (g) g + " " + nodeSet.group + g).join(" ")); .map(function (g) g + " " + nodeSet.group + g).join(" "));
}); });
}, },
getGroup: function (name, value) { getGroup: function getgroup(name, value) {
if (!statusline.visible) if (!statusline.visible)
return this.commandbar; return this.commandbar;
return this.elements[name].getGroup.call(this, arguments.length > 1 ? value : this[name]); return this.elements[name].getGroup.call(this, arguments.length > 1 ? value : this[name]);
}, },
updateVisibility: function () { updateVisibility: function updateVisibility() {
for (let elem in values(this.elements)) for (let elem in values(this.elements))
if (elem.getGroup) { if (elem.getGroup) {
let value = elem.getValue ? elem.getValue.call(this) let value = elem.getValue ? elem.getValue.call(this)
@@ -260,10 +265,10 @@ var CommandWidgets = Class("CommandWidgets", {
commandbar: Class.memoize(function () ({ group: "Cmd" })), commandbar: Class.memoize(function () ({ group: "Cmd" })),
statusbar: Class.memoize(function () ({ group: "Status" })), statusbar: Class.memoize(function () ({ group: "Status" })),
_whenReady: function (name, id, processor) { _whenReady: function _whenReady(name, id, processor) {
Object.defineProperty(this, name, { Object.defineProperty(this, name, {
configurable: true, enumerable: true, configurable: true, enumerable: true,
get: function () { get: function get_whenReady() {
let elem = document.getElementById(id); let elem = document.getElementById(id);
while (elem.contentDocument.documentURI != elem.getAttribute("src") || while (elem.contentDocument.documentURI != elem.getAttribute("src") ||
["viewable", "complete"].indexOf(elem.contentDocument.readyState) < 0) ["viewable", "complete"].indexOf(elem.contentDocument.readyState) < 0)
@@ -295,7 +300,7 @@ var CommandWidgets = Class("CommandWidgets", {
multilineInput: Class.memoize(function () document.getElementById("dactyl-multiline-input")), multilineInput: Class.memoize(function () document.getElementById("dactyl-multiline-input")),
mowContainer: Class.memoize(function () document.getElementById("dactyl-multiline-output-container")) mowContainer: Class.memoize(function () document.getElementById("dactyl-multiline-output-container"))
}, { }, {
getEditor: function (elem) { getEditor: function getEditor(elem) {
elem.inputField.QueryInterface(Ci.nsIDOMNSEditableElement); elem.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
return elem; return elem;
} }
@@ -308,7 +313,7 @@ var CommandWidgets = Class("CommandWidgets", {
* this class when the chrome is ready. * this class when the chrome is ready.
*/ */
var CommandLine = Module("commandline", { var CommandLine = Module("commandline", {
init: function () { init: function init() {
const self = this; const self = this;
this._callbacks = {}; this._callbacks = {};
@@ -489,7 +494,7 @@ var CommandLine = Module("commandline", {
/** /**
* Ensure that the multiline input widget is the correct size. * Ensure that the multiline input widget is the correct size.
*/ */
_autosizeMultilineInputWidget: function () { _autosizeMultilineInputWidget: function _autosizeMultilineInputWidget() {
let lines = this.widgets.multilineInput.value.split("\n").length - 1; let lines = this.widgets.multilineInput.value.split("\n").length - 1;
this.widgets.multilineInput.setAttribute("rows", Math.max(lines, 1)); this.widgets.multilineInput.setAttribute("rows", Math.max(lines, 1));
@@ -538,13 +543,13 @@ var CommandLine = Module("commandline", {
// "change" // "change"
// "cancel" // "cancel"
// "complete" // "complete"
registerCallback: function (type, mode, func) { registerCallback: function registerCallback(type, mode, func) {
if (!(type in this._callbacks)) if (!(type in this._callbacks))
this._callbacks[type] = {}; this._callbacks[type] = {};
this._callbacks[type][mode] = func; this._callbacks[type][mode] = func;
}, },
triggerCallback: function (type, mode) { triggerCallback: function triggerCallback(type, mode) {
if (this._callbacks[type] && this._callbacks[type][mode]) if (this._callbacks[type] && this._callbacks[type][mode])
try { try {
this._callbacks[type][mode].apply(this, Array.slice(arguments, 2)); this._callbacks[type][mode].apply(this, Array.slice(arguments, 2));
@@ -554,14 +559,14 @@ var CommandLine = Module("commandline", {
} }
}, },
runSilently: function (func, self) { runSilently: function runSilently(func, self) {
this.withSavedValues(["_silent"], function () { this.withSavedValues(["_silent"], function () {
this._silent = true; this._silent = true;
func.call(self); func.call(self);
}); });
}, },
hideCompletions: function () { hideCompletions: function hideCompletions() {
for (let nodeSet in values([this.widgets.statusbar, this.widgets.commandbar])) for (let nodeSet in values([this.widgets.statusbar, this.widgets.commandbar]))
if (nodeSet.commandline._completionList) if (nodeSet.commandline._completionList)
nodeSet.commandline._completionList.hide(); nodeSet.commandline._completionList.hide();
@@ -575,10 +580,10 @@ var CommandLine = Module("commandline", {
messages: Modes.boundProperty(), messages: Modes.boundProperty(),
multilineInputVisible: Modes.boundProperty({ multilineInputVisible: Modes.boundProperty({
set: function (value) { this.widgets.multilineInput.collapsed = !value; } set: function set_miwVisible(value) { this.widgets.multilineInput.collapsed = !value; }
}), }),
multilineOutputVisible: Modes.boundProperty({ multilineOutputVisible: Modes.boundProperty({
set: function (value) { set: function set_mowVisible(value) {
this.widgets.mowContainer.collapsed = !value; this.widgets.mowContainer.collapsed = !value;
let elem = this.widgets.multilineOutput; let elem = this.widgets.multilineOutput;
if (!value && elem && elem.contentWindow == document.commandDispatcher.focusedWindow) if (!value && elem && elem.contentWindow == document.commandDispatcher.focusedWindow)
@@ -602,7 +607,7 @@ var CommandLine = Module("commandline", {
this.currentExtendedMode = extendedMode || null; this.currentExtendedMode = extendedMode || null;
modes.push(modes.COMMAND_LINE, this.currentExtendedMode, { modes.push(modes.COMMAND_LINE, this.currentExtendedMode, {
autocomplete: cmd.length, autocomplete: cmd.length,
onEvent: this.closure.onEvent, onKeyPress: this.closure.onKeyPress,
history: (extendedMode || {}).params.history, history: (extendedMode || {}).params.history,
leave: function (params) { leave: function (params) {
if (params.pop) if (params.pop)
@@ -671,7 +676,7 @@ var CommandLine = Module("commandline", {
get lastCommand() this._lastCommand || this.command, get lastCommand() this._lastCommand || this.command,
set lastCommand(val) { this._lastCommand = val }, set lastCommand(val) { this._lastCommand = val },
clear: function () { clear: function clear() {
if (this.widgets.message && this.widgets.message[1] === this._lastClearable) if (this.widgets.message && this.widgets.message[1] === this._lastClearable)
this.widgets.message = null; this.widgets.message = null;
if (modes.main != modes.COMMAND_LINE) if (modes.main != modes.COMMAND_LINE)
@@ -688,7 +693,7 @@ var CommandLine = Module("commandline", {
* *
* @param {XML} xml The output as an E4X XML object. * @param {XML} xml The output as an E4X XML object.
*/ */
commandOutput: function (xml) { commandOutput: function commandOutput(xml) {
XML.ignoreWhitespace = false; XML.ignoreWhitespace = false;
XML.prettyPrinting = false; XML.prettyPrinting = false;
if (this.command) if (this.command)
@@ -747,7 +752,7 @@ var CommandLine = Module("commandline", {
this._startHints = false; this._startHints = false;
if (modes.main != modes.OUTPUT_MULTILINE) { if (modes.main != modes.OUTPUT_MULTILINE) {
modes.push(modes.OUTPUT_MULTILINE, null, { modes.push(modes.OUTPUT_MULTILINE, null, {
onEvent: this.closure.onMultilineOutputEvent, onKeyPress: this.closure.onMOWKeyPress,
leave: this.closure(function leave(stack) { leave: this.closure(function leave(stack) {
if (stack.pop) if (stack.pop)
for (let message in values(this.messages)) for (let message in values(this.messages))
@@ -906,7 +911,7 @@ var CommandLine = Module("commandline", {
modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended, modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended,
update(Object.create(extra), { update(Object.create(extra), {
onEvent: extra.onEvent || this.closure.onEvent, onKeyPress: extra.onEvent || this.closure.onKeyPress,
leave: function leave(stack) { leave: function leave(stack) {
commandline.leave(stack); commandline.leave(stack);
leave.supercall(extra, stack); leave.supercall(extra, stack);
@@ -922,7 +927,7 @@ var CommandLine = Module("commandline", {
this.enter(); this.enter();
}, },
readHeredoc: function (end) { readHeredoc: function readHeredoc(end) {
let args; let args;
commandline.inputMultiline(end, commandline.inputMultiline(end,
function (res) { args = res; }); function (res) { args = res; });
@@ -946,7 +951,7 @@ var CommandLine = Module("commandline", {
if (cmd != false) if (cmd != false)
this._echoLine(cmd, this.HL_NORMAL); this._echoLine(cmd, this.HL_NORMAL);
// save the arguments, they are needed in the event handler onEvent // save the arguments, they are needed in the event handler onKeyPress
this._multilineEnd = "\n" + end + "\n"; this._multilineEnd = "\n" + end + "\n";
this._multilineCallback = callbackFunc; this._multilineCallback = callbackFunc;
@@ -976,53 +981,36 @@ var CommandLine = Module("commandline", {
return true; return true;
}, },
/** onKeyPress: function onKeyPress(event) {
* Handles all command-line events. All key events are passed here when let key = events.toString(event);
* COMMAND_LINE mode is active, as well as all input, keyup, focus, and if (this._completions)
* blur events sent to the command-line XUL element. this._completions.previewClear();
*
* @param {Event} event
* @private
*/
onEvent: function onEvent(event) {
const KILL = false, PASS = true;
try { return true; /* Pass event */
let command = this.command; },
if (event.type == "blur") { events: {
this.timeout(function () { blur: function onBlur(event) {
if (this.commandVisible && event.originalTarget == this.widgets.active.command.inputField) this.timeout(function () {
dactyl.focus(this.widgets.active.command.inputField); if (this.commandVisible && event.originalTarget == this.widgets.active.command.inputField)
}); dactyl.focus(this.widgets.active.command.inputField);
} });
else if (event.type == "focus") { },
if (!this.commandVisible && event.target == this.widgets.active.command.inputField) { focus: function onFocus(event) {
event.target.blur(); if (!this.commandVisible && event.target == this.widgets.active.command.inputField) {
dactyl.beep(); event.target.blur();
} dactyl.beep();
}
else if (event.type == "input") {
this.resetCompletions();
commandline.triggerCallback("change", this.currentExtendedMode, command);
}
else if (event.type == "keypress") {
let key = events.toString(event);
if (this._completions)
this._completions.previewClear();
return PASS;
}
else if (event.type == "keyup") {
let key = events.toString(event);
if (/^<(?:A-)?(?:S-)?Tab>$/.test(key))
this._tabTimer.flush();
} }
},
input: function onInput(event) {
this.resetCompletions();
this.triggerCallback("change", this.currentExtendedMode, this.command);
},
keyup: function onKeyUp(event) {
let key = events.toString(event);
if (/-?Tab>$/.test(key))
this._tabTimer.flush();
} }
catch (e) {
dactyl.reportError(e, true);
}
return PASS;
}, },
/** /**
@@ -1031,10 +1019,17 @@ var CommandLine = Module("commandline", {
* *
* @param {Event} event * @param {Event} event
*/ */
onMultilineInputEvent: function onMultilineInputEvent(event) { multilineInputEvents: {
const KILL = false, PASS = true; blur: function onBlur(event) {
if (modes.extended & modes.INPUT_MULTILINE)
if (event.type == "keypress") { this.timeout(function () {
dactyl.focus(this.widgets.multilineInput.inputField);
});
},
input: function onInput(event) {
this._autosizeMultilineInputWidget();
},
keypress: function onKeyPress(event) {
let key = events.toString(event); let key = events.toString(event);
if (events.isAcceptKey(key)) { if (events.isAcceptKey(key)) {
let text = "\n" + this.widgets.multilineInput.value.substr(0, this.widgets.multilineInput.selectionStart) + "\n"; let text = "\n" + this.widgets.multilineInput.value.substr(0, this.widgets.multilineInput.selectionStart) + "\n";
@@ -1050,78 +1045,52 @@ var CommandLine = Module("commandline", {
modes.pop(); modes.pop();
} }
} }
else if (event.type == "blur") {
if (modes.extended & modes.INPUT_MULTILINE)
this.timeout(function () { dactyl.focus(this.widgets.multilineInput.inputField); }, 0);
}
else if (event.type == "input")
this._autosizeMultilineInputWidget();
return PASS;
}, },
/** multilineOutputEvents: {
* Handle events when we are in multi-line output mode, these come from click: function onClick(event) {
* dactyl when modes.extended & modes.OUTPUT_MULTILINE and also from if (event.getPreventDefault())
* #dactyl-multiline-output in the XUL. return;
*
* @param {Event} event
*/
// FIXME: if 'more' is set and the MOW is not scrollable we should still
// allow a down motion after an up rather than closing
onMultilineOutputEvent: function onMultilineOutputEvent(event) {
try {
const KILL = false, PASS = true;
let win = this.widgets.multilineOutput.contentWindow;
let elem = win.document.documentElement;
let key = events.toString(event);
const openLink = function openLink(where) { const openLink = function openLink(where) {
event.preventDefault(); event.preventDefault();
dactyl.open(event.target.href, where); dactyl.open(event.target.href, where);
} }
// TODO: Wouldn't multiple handlers be cleaner? --djk if (event.target instanceof HTMLAnchorElement)
if (event.type == "click" && event.target instanceof HTMLAnchorElement) { switch (events.toString(event)) {
if (event.getPreventDefault())
return;
switch (key) {
case "<LeftMouse>": case "<LeftMouse>":
event.preventDefault();
openLink(dactyl.CURRENT_TAB); openLink(dactyl.CURRENT_TAB);
return KILL; break;
case "<MiddleMouse>": case "<MiddleMouse>":
case "<C-LeftMouse>": case "<C-LeftMouse>":
case "<C-M-LeftMouse>": case "<C-M-LeftMouse>":
openLink({ where: dactyl.NEW_TAB, background: true }); openLink({ where: dactyl.NEW_TAB, background: true });
return KILL; break;
case "<S-MiddleMouse>": case "<S-MiddleMouse>":
case "<C-S-LeftMouse>": case "<C-S-LeftMouse>":
case "<C-M-S-LeftMouse>": case "<C-M-S-LeftMouse>":
openLink({ where: dactyl.NEW_TAB, background: false }); openLink({ where: dactyl.NEW_TAB, background: false });
return KILL; break;
case "<S-LeftMouse>": case "<S-LeftMouse>":
openLink(dactyl.NEW_WINDOW); openLink(dactyl.NEW_WINDOW);
return KILL; break;
} }
return PASS; },
} unload: function onUnload(event) {
event.preventDefault();
if (event instanceof MouseEvent)
return KILL;
if (!options["more"] || !mow.isScrollable(1)) {
modes.pop();
events.feedkeys(key);
}
else
commandline.updateMorePrompt(false, true);
} }
catch (e) { },
util.reportError(e);
onMOWKeyPress: function onMOWKeyPress(event) {
const KILL = false, PASS = true;
if (options["more"] && mos.isScrollable(1))
commandline.updateMorePrompt(false, true);
else {
modes.pop();
events.feedkeys(events.toString(event));
return KILL;
} }
return PASS; return PASS;
}, },
@@ -1190,7 +1159,7 @@ var CommandLine = Module("commandline", {
this._history.reset(); this._history.reset();
}, },
withOutputToString: function (fn, self) { withOutputToString: function withOutputToString(fn, self) {
dactyl.registerObserver("echoLine", observe, true); dactyl.registerObserver("echoLine", observe, true);
dactyl.registerObserver("echoMultiline", observe, true); dactyl.registerObserver("echoMultiline", observe, true);
@@ -1213,7 +1182,7 @@ var CommandLine = Module("commandline", {
* @param {string} mode The mode for which we need history. * @param {string} mode The mode for which we need history.
*/ */
History: Class("History", { History: Class("History", {
init: function (inputField, mode) { init: function init(inputField, mode) {
this.mode = mode; this.mode = mode;
this.input = inputField; this.input = inputField;
this.reset(); this.reset();
@@ -1223,14 +1192,14 @@ var CommandLine = Module("commandline", {
/** /**
* Reset the history index to the first entry. * Reset the history index to the first entry.
*/ */
reset: function () { reset: function reset() {
this.index = null; this.index = null;
}, },
/** /**
* Save the last entry to the permanent store. All duplicate entries * Save the last entry to the permanent store. All duplicate entries
* are removed and the list is truncated, if necessary. * are removed and the list is truncated, if necessary.
*/ */
save: function () { save: function save() {
if (events.feedingKeys) if (events.feedingKeys)
return; return;
let str = this.input.value; let str = this.input.value;
@@ -1249,7 +1218,7 @@ var CommandLine = Module("commandline", {
* @property {function} Returns whether a data item should be * @property {function} Returns whether a data item should be
* considered private. * considered private.
*/ */
checkPrivate: function (str) { checkPrivate: function checkPrivate(str) {
// Not really the ideal place for this check. // Not really the ideal place for this check.
if (this.mode == "command") if (this.mode == "command")
return commands.hasPrivateData(str); return commands.hasPrivateData(str);
@@ -1260,7 +1229,7 @@ var CommandLine = Module("commandline", {
* *
* @param {string} val The new value. * @param {string} val The new value.
*/ */
replace: function (val) { replace: function replace(val) {
delete this.input.dactylKeyPress; delete this.input.dactylKeyPress;
this.input.value = val; this.input.value = val;
commandline.triggerCallback("change", commandline.currentExtendedMode, val, "history"); commandline.triggerCallback("change", commandline.currentExtendedMode, val, "history");
@@ -1273,7 +1242,7 @@ var CommandLine = Module("commandline", {
* @param {boolean} matchCurrent Search for matches starting * @param {boolean} matchCurrent Search for matches starting
* with the current input value. * with the current input value.
*/ */
select: function (backward, matchCurrent) { select: function select(backward, matchCurrent) {
// always reset the tab completion if we use up/down keys // always reset the tab completion if we use up/down keys
if (commandline._completions) if (commandline._completions)
commandline._completions.reset(); commandline._completions.reset();
@@ -1323,7 +1292,7 @@ var CommandLine = Module("commandline", {
* @param {Object} input * @param {Object} input
*/ */
Completions: Class("Completions", { Completions: Class("Completions", {
init: function (input) { init: function init(input) {
this.context = CompletionContext(input.QueryInterface(Ci.nsIDOMNSEditableElement).editor); this.context = CompletionContext(input.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
this.context.onUpdate = this.closure._reset; this.context.onUpdate = this.closure._reset;
this.editor = input.editor; this.editor = input.editor;
@@ -1385,7 +1354,7 @@ var CommandLine = Module("commandline", {
this.wildIndex = 0; this.wildIndex = 0;
}, },
haveType: function (type) haveType: function haveType(type)
this.wildmode.checkHas(this.wildtype, type == "first" ? "" : type), this.wildmode.checkHas(this.wildtype, type == "first" ? "" : type),
preview: function preview() { preview: function preview() {
@@ -1612,7 +1581,7 @@ var CommandLine = Module("commandline", {
return arg; return arg;
} }
}, { }, {
commands: function () { commands: function init_commands() {
[ [
{ {
name: "ec[ho]", name: "ec[ho]",
@@ -1673,7 +1642,7 @@ var CommandLine = Module("commandline", {
subCommand: 0 subCommand: 0
}); });
}, },
mappings: function () { mappings: function init_mappings() {
mappings.add([modes.COMMAND], mappings.add([modes.COMMAND],
[":"], "Enter command-line mode", [":"], "Enter command-line mode",
@@ -1705,11 +1674,15 @@ var CommandLine = Module("commandline", {
bind(["<Return>", "<C-j>", "<C-m>"], "Accept the current input", bind(["<Return>", "<C-j>", "<C-m>"], "Accept the current input",
function (args) { function (args) {
commandline._keepCommand = userContext.hidden_option_command_afterimage; commandline._keepCommand = userContext.hidden_option_command_afterimage;
let mode = commandline.currentExtendedMode;
let mode = commandline.currentExtendedMode;
let command = commandline.command;
commandline.currentExtendedMode = null; // Don't let modes.pop trigger "cancel" commandline.currentExtendedMode = null; // Don't let modes.pop trigger "cancel"
modes.pop(); modes.pop();
commandline.triggerCallback("submit", mode, commandline.command);
commandline.triggerCallback("submit", mode, command);
}); });
[ [
@@ -1822,7 +1795,7 @@ var CommandLine = Module("commandline", {
function () {}, function () {},
function () false, DROP); function () false, DROP);
}, },
options: function () { options: function init_options() {
options.add(["history", "hi"], options.add(["history", "hi"],
"Number of Ex commands and search patterns to store in the command-line history", "Number of Ex commands and search patterns to store in the command-line history",
"number", 500, "number", 500,
@@ -1846,7 +1819,7 @@ var CommandLine = Module("commandline", {
"Show the current mode in the command line", "Show the current mode in the command line",
"boolean", true); "boolean", true);
}, },
sanitizer: function () { sanitizer: function init_sanitizer() {
sanitizer.addItem("commandline", { sanitizer.addItem("commandline", {
description: "Command-line and search history", description: "Command-line and search history",
persistent: true, persistent: true,
@@ -1893,7 +1866,7 @@ var CommandLine = Module("commandline", {
* necessary. * necessary.
*/ */
var ItemList = Class("ItemList", { var ItemList = Class("ItemList", {
init: function (id) { init: function init(id) {
this._completionElements = []; this._completionElements = [];
var iframe = document.getElementById(id); var iframe = document.getElementById(id);
@@ -1917,9 +1890,9 @@ var ItemList = Class("ItemList", {
this._minHeight = 0; this._minHeight = 0;
}, },
_dom: function (xml, map) util.xmlToDom(xml instanceof XML ? xml : <>{xml}</>, this._doc, map), _dom: function _dom(xml, map) util.xmlToDom(xml instanceof XML ? xml : <>{xml}</>, this._doc, map),
_autoSize: function () { _autoSize: function _autoSize() {
if (this._container.collapsed) if (this._container.collapsed)
this._div.style.minWidth = document.getElementById("dactyl-commandline").scrollWidth + "px"; this._div.style.minWidth = document.getElementById("dactyl-commandline").scrollWidth + "px";
@@ -1938,9 +1911,9 @@ var ItemList = Class("ItemList", {
this.timeout(function () { this._container.height -= commandline.getSpaceNeeded(); }, 0); this.timeout(function () { this._container.height -= commandline.getSpaceNeeded(); }, 0);
}, },
_getCompletion: function (index) this._completionElements.snapshotItem(index - this._startIndex), _getCompletion: function _getCompletion(index) this._completionElements.snapshotItem(index - this._startIndex),
_init: function () { _init: function _init() {
this._div = this._dom( this._div = this._dom(
<div class="ex-command-output" highlight="Normal" style="white-space: nowrap"> <div class="ex-command-output" highlight="Normal" style="white-space: nowrap">
<div highlight="Completions" key="noCompletions"><span highlight="Title">No Completions</span></div> <div highlight="Completions" key="noCompletions"><span highlight="Title">No Completions</span></div>
@@ -1985,7 +1958,7 @@ var ItemList = Class("ItemList", {
* *
* @param {number} offset Start at this index and show options["maxitems"]. * @param {number} offset Start at this index and show options["maxitems"].
*/ */
_fill: function (offset) { _fill: function _fill(offset) {
XML.ignoreWhiteSpace = false; XML.ignoreWhiteSpace = false;
let diff = offset - this._startIndex; let diff = offset - this._startIndex;
if (this._items == null || offset == null || diff == 0 || offset < 0) if (this._items == null || offset == null || diff == 0 || offset < 0)
@@ -2068,7 +2041,7 @@ var ItemList = Class("ItemList", {
show: function show() { this._container.collapsed = false; }, show: function show() { this._container.collapsed = false; },
visible: function visible() !this._container.collapsed, visible: function visible() !this._container.collapsed,
reset: function (brief) { reset: function reset(brief) {
this._startIndex = this._endIndex = this._selIndex = -1; this._startIndex = this._endIndex = this._selIndex = -1;
this._div = null; this._div = null;
if (!brief) if (!brief)
@@ -2138,7 +2111,7 @@ var ItemList = Class("ItemList", {
// util.dump({ time: Date.now() - this.start }); // util.dump({ time: Date.now() - this.start });
}, },
onEvent: function onEvent(event) false onKeyPress: function onKeyPress(event) false
}, { }, {
WAITING_MESSAGE: "Generating results..." WAITING_MESSAGE: "Generating results..."
}); });

View File

@@ -24,9 +24,9 @@ var ProcessorStack = Class("ProcessorStack", {
input.preExecute = params.preExecute; input.preExecute = params.preExecute;
if (params.postExecute) if (params.postExecute)
input.postExecute = params.postExecute; input.postExecute = params.postExecute;
if (params.onEvent && input.hive === mappings.builtin) if (params.onKeyPress && input.hive === mappings.builtin)
input.fallthrough = function (event) { input.fallthrough = function (event) {
return params.onEvent(event) === false ? Events.KILL : Events.PASS; return params.onKeyPress(event) === false ? Events.KILL : Events.PASS;
}; };
} }
}, },

View File

@@ -327,7 +327,7 @@ var HintSession = Class("HintSession", {
* *
* @param {Event} event The event to handle. * @param {Event} event The event to handle.
*/ */
onEvent: function onEvent(event) { onKeyPress: function onKeyPress(event) {
const KILL = false, PASS = true; const KILL = false, PASS = true;
let key = events.toString(event); let key = events.toString(event);

View File

@@ -148,10 +148,10 @@ var Modes = Module("modes", {
// Fix me. // Fix me.
preExecute: function (map) { if (modes.main == modes.QUOTE && map.name !== "<C-v>") modes.pop() }, preExecute: function (map) { if (modes.main == modes.QUOTE && map.name !== "<C-v>") modes.pop() },
postExecute: function (map) { if (modes.main == modes.QUOTE && map.name === "<C-v>") modes.pop() }, postExecute: function (map) { if (modes.main == modes.QUOTE && map.name === "<C-v>") modes.pop() },
onEvent: function () { if (modes.main == modes.QUOTE) modes.pop() } onKeyPress: function () { if (modes.main == modes.QUOTE) modes.pop() }
}); });
this.addMode("IGNORE", { hidden: true }, { this.addMode("IGNORE", { hidden: true }, {
onEvent: function (event) Events.KILL, onKeyPress: function (event) Events.KILL,
bases: [] bases: []
}); });

View File

@@ -46,20 +46,13 @@ var StatusLine = Module("statusline", {
<!-- insertbefore="dactyl.statusBefore;" insertafter="dactyl.statusAfter;" --> <!-- insertbefore="dactyl.statusBefore;" insertafter="dactyl.statusAfter;" -->
<hbox key="container" hidden="false" align="center" flex="1"> <hbox key="container" hidden="false" align="center" flex="1">
<stack orient="horizontal" align="stretch" flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container"> <stack orient="horizontal" align="stretch" flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container">
<hbox highlight="CmdLine StatusCmdLine" class="dactyl-container"> <hbox highlight="CmdLine StatusCmdLine" class="dactyl-container" id="dactyl-statusline-stack">
<label key="mode" crop="end" class="plain" collapsed="true"/> <label key="mode" crop="end" class="plain" collapsed="true"/>
<stack flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container"> <stack flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container">
<textbox key="url" crop="end" flex="1" class="plain dactyl-status-field-url" readonly="true"/> <textbox key="url" crop="end" flex="1" class="plain dactyl-status-field-url" readonly="true"/>
<textbox key="message" crop="end" flex="1" highlight="Normal StatusNormal" class="plain" readonly="true"/> <textbox key="message" crop="end" flex="1" highlight="Normal StatusNormal" class="plain" readonly="true"/>
</stack> </stack>
</hbox> </hbox>
<hbox key="commandline" hidden="false" class="dactyl-container" highlight="Normal StatusNormal" collapsed="true">
<label key="commandline-prompt" class="dactyl-commandline-prompt plain" flex="0" crop="end" value="" collapsed="true"/>
<textbox key="commandline-command" class="dactyl-commandline-command plain" flex="1" type="text" timeout="100"
oninput={_commandline + ".onEvent(event);"} onkeyup={_commandline + ".onEvent(event);"}
onfocus={_commandline + ".onEvent(event);"} onblur={_commandline + ".onEvent(event);"}/>
</hbox>
</stack> </stack>
<label class="plain" key="inputbuffer" flex="0"/> <label class="plain" key="inputbuffer" flex="0"/>
<label class="plain" key="progress" flex="0"/> <label class="plain" key="progress" flex="0"/>

View File

@@ -233,23 +233,15 @@ var Addon = Class("Addon", {
} }
}); });
["cancelUninstall", "findUpdates", "getResourceURI", "hasResource", iter.forEach(properties(config.addon), function (prop) {
"isCompatibleWith", "uninstall"].forEach(function (prop) { let desc = Object.getOwnPropertyDescriptor(config.addon, prop);
Addon.prototype[prop] = function proxy() this.addon[prop].apply(this.addon, arguments); if (callable(desc.value))
}); Addon.prototype[prop] = function proxy() this.addon[prop].apply(this.addon, arguments);
else
["aboutURL", "appDisabled", "applyBackgroundUpdates", "blocklistState", Object.defineProperty(Addon.prototype, prop, {
"contributors", "creator", "description", "developers", "homepageURL", get: function get_proxy() this.addon[prop],
"iconURL", "id", "install", "installDate", "isActive", "isCompatible", set: function set_proxy(val) this.addon[prop] = val
"isPlatformCompatible", "name", "operationsRequiringRestart", });
"optionsURL", "pendingOperations", "pendingUpgrade", "permissions",
"providesUpdatesSecurely", "releaseNotesURI", "scope", "screenshots",
"size", "sourceURI", "translators", "type", "updateDate",
"userDisabled", "version"].forEach(function (prop) {
Object.defineProperty(Addon.prototype, prop, {
get: function get_proxy() this.addon[prop],
set: function set_proxy(val) this.addon[prop] = val
});
}); });
var AddonList = Class("AddonList", { var AddonList = Class("AddonList", {

View File

@@ -188,10 +188,17 @@ var Highlights = Module("Highlight", {
* @param {Node} node * @param {Node} node
* @param {string} group * @param {string} group
*/ */
highlightNode: function (node, group) { highlightNode: function (node, group, applyBindings) {
node.setAttributeNS(NS.uri, "highlight", group); node.setAttributeNS(NS.uri, "highlight", group);
for each (let h in group.split(" "))
this.loaded[h] = true; let groups = group.split(" ");
for each (let group in groups)
this.loaded[group] = true;
if (applyBindings)
for each (let group in groups)
if (group in template.bindings)
template.bindings[group](node, applyBindings);
}, },
/** /**

View File

@@ -270,9 +270,11 @@ var Overlay = Module("Overlay", {
modules.events.addSessionListener(window, "unload", function onUnload() { modules.events.addSessionListener(window, "unload", function onUnload() {
window.removeEventListener("unload", onUnload.wrapped, false); window.removeEventListener("unload", onUnload.wrapped, false);
for (let [, mod] in iter(modules)) for (let prop in properties(modules)) {
if (mod instanceof ModuleBase && "destroy" in mod) let desc = Object.getOwnPropertyDescriptor(modules, prop);
util.trapErrors(mod.destroy, mod); if (desc.value instanceof ModuleBase && "destroy" in desc.value)
util.trapErrors(desc.value.destroy, desc.value);
}
}, false); }, false);
} }
})); }));

View File

@@ -131,6 +131,16 @@ var Template = Module("Template", {
update: function update() { update: function update() {
this.collapsed = !this.commandAllowed; this.collapsed = !this.commandAllowed;
} }
}),
Events: Class("Events", Binding, {
init: function init(node, params) {
init.supercall(this, node);
let obj = params.eventTarget;
for (let [event, handler] in Iterator(obj[this.getAttribute("events") || "events"]))
node.addEventListener(event, obj.closure(handler), false);
}
}) })
}, },

View File

@@ -1602,19 +1602,17 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
case "element": case "element":
let domnode = doc.createElementNS(node.namespace(), node.localName()); let domnode = doc.createElementNS(node.namespace(), node.localName());
for each (let attr in node.@*::*)
if (attr.name() != "highlight")
domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr));
for each (let child in node.*::*) for each (let child in node.*::*)
domnode.appendChild(xmlToDom(child, doc, nodes)); domnode.appendChild(xmlToDom(child, doc, nodes));
if (nodes && node.@key) if (nodes && node.@key)
nodes[node.@key] = domnode; nodes[node.@key] = domnode;
for each (let attr in node.@*::*) if (node.@highlight)
if (attr.name() != "highlight") highlight.highlightNode(domnode, String(node.@highlight), nodes || true);
domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr));
else {
highlight.highlightNode(domnode, String(attr));
if (attr in template.bindings)
template.bindings[attr](domnode, nodes);
}
return domnode; return domnode;
default: default:
return null; return null;