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

Fix some major mode changing bugs. Closes issue #55.

--HG--
branch : mode-refactoring
This commit is contained in:
Kris Maglione
2010-10-06 10:34:28 -04:00
parent dd3d79ea73
commit 41335adaae
8 changed files with 274 additions and 242 deletions

View File

@@ -76,11 +76,11 @@ const Events = Module("events", {
this._activeMenubar = false;
this.addSessionListener(window, "DOMMenuBarActive", this.closure.onDOMMenuBarActive, true);
this.addSessionListener(window, "DOMMenuBarInactive", this.closure.onDOMMenuBarInactive, true);
this.addSessionListener(window, "focus", this.wrapListener(this.closure.onFocus), true);
this.addSessionListener(window, "keydown", this.wrapListener(this.closure.onKeyUpOrDown), true);
this.addSessionListener(window, "keypress", this.wrapListener(this.closure.onKeyPress), true);
this.addSessionListener(window, "keyup", this.wrapListener(this.closure.onKeyUpOrDown), true);
this.addSessionListener(window, "mousedown", this.wrapListener(this.closure.onMouseDown), true);
this.addSessionListener(window, "focus", this.wrapListener(this.onFocus), true);
this.addSessionListener(window, "keydown", this.wrapListener(this.onKeyUpOrDown), true);
this.addSessionListener(window, "keypress", this.wrapListener(this.onKeyPress), true);
this.addSessionListener(window, "keyup", this.wrapListener(this.onKeyUpOrDown), true);
this.addSessionListener(window, "mousedown", this.wrapListener(this.onMouseDown), true);
this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true);
this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true);
this.addSessionListener(window, "resize", this.closure.onResize, true);
@@ -90,7 +90,8 @@ const Events = Module("events", {
destroy: function () {
util.dump("Removing all event listeners");
for (let args in values(this.sessionListeners))
args[0].removeEventListener.apply(args[0], args.slice(1));
if (args[0].get())
args[0].get().removeEventListener.apply(args[0].get(), args.slice(1));
},
/**
@@ -105,7 +106,8 @@ const Events = Module("events", {
*/
addSessionListener: function (target, event, callback, capture) {
let args = Array.slice(arguments, 0);
target.addEventListener.apply(args[0], args.slice(1));
args[0].addEventListener.apply(args[0], args.slice(1));
args[0] = Cu.getWeakReference(args[0]);
this.sessionListeners.push(args);
},
@@ -113,6 +115,7 @@ const Events = Module("events", {
* Wraps an event listener to ensure that errors are reported.
*/
wrapListener: function wrapListener(method, self) {
self = self || this;
return function (event) {
try {
method.apply(self, arguments);
@@ -625,69 +628,17 @@ const Events = Module("events", {
* The global escape key handler. This is called in ALL modes.
*/
onEscape: function () {
if (modes.passNextKey)
return;
if (modes.passAllKeys) {
modes.passAllKeys = false;
return;
}
switch (dactyl.mode) {
case modes.NORMAL:
// clear any selection made
let selection = window.content.getSelection();
try { // a simple if (selection) does not seem to work
selection.collapseToStart();
}
catch (e) {}
modes.reset();
break;
case modes.VISUAL:
if (modes.extended & modes.TEXTAREA)
dactyl.mode = modes.TEXTAREA;
else if (modes.extended & modes.CARET)
dactyl.mode = modes.CARET;
break;
case modes.CARET:
// setting this option will trigger an observer which will
// take care of all other details like setting the NORMAL
// mode
options.setPref("accessibility.browsewithcaret", false);
break;
case modes.TEXTAREA:
// TODO: different behaviour for text areas and other input
// fields seems unnecessarily complicated. If the user
// likes Vi-mode then they probably like it for all input
// fields, if not they can enter it explicitly for only
// text areas. The mode name TEXTAREA is confusing and
// would be better replaced with something indicating that
// it's a Vi editing mode. Extended modes really need to be
// displayed too. --djk
function isInputField() {
let elem = dactyl.focus;
return elem instanceof HTMLInputElement && set.has(Events.editableInputs, elem.type)
|| elem instanceof HTMLIsIndexElement;
}
if (options["insertmode"] || isInputField())
dactyl.mode = modes.INSERT;
else
modes.reset();
break;
case modes.COMMAND_LINE:
case modes.INSERT:
if ((modes.extended & modes.TEXTAREA))
dactyl.mode = modes.TEXTAREA;
else
modes.reset();
case modes.PASS_THROUGH:
case modes.QUOTE:
case modes.TEXTAREA:
case modes.VISUAL:
modes.pop();
break;
default: // HINTS, CUSTOM or COMMAND_LINE
default:
modes.reset();
break;
}
@@ -752,12 +703,15 @@ const Events = Module("events", {
}
if (elem instanceof HTMLTextAreaElement || (elem && util.computedStyle(elem).MozUserModify == "read-write")) {
if (modes.main === modes.VISUAL && elem.selectionEnd == elem.selectionStart)
modes.pop();
if (options["insertmode"])
modes.set(modes.INSERT);
else if (elem.selectionEnd - elem.selectionStart > 0)
modes.set(modes.VISUAL, modes.TEXTAREA);
else
modes.main = modes.TEXTAREA;
else {
modes.set(modes.TEXTAREA);
if (elem.selectionEnd - elem.selectionStart > 0)
modes.push(modes.VISUAL);
}
if (hasHTMLDocument(win))
buffer.lastInputField = elem;
return;
@@ -772,7 +726,7 @@ const Events = Module("events", {
if (elem == null && urlbar && urlbar.inputField == this._lastFocus)
util.threadYield(true);
if (dactyl.mode & (modes.EMBED | modes.INSERT | modes.TEXTAREA | modes.VISUAL))
if (modes.getMode(modes.main).ownsFocus)
modes.reset();
}
finally {
@@ -784,7 +738,7 @@ const Events = Module("events", {
// the commandline has focus
// TODO: ...help me...please...
onKeyPress: function (event) {
function isEscapeKey(key) key == "<Esc>" || key == "<C-[>";
function isEscape(key) key == "<Esc>" || key == "<C-[>";
function killEvent() {
event.preventDefault();
@@ -802,7 +756,7 @@ const Events = Module("events", {
dactyl.echomsg("Recorded macro '" + this._currentMacro + "'");
return killEvent();
}
else if (!mappings.hasMap(dactyl.mode, this._input.buffer + key))
else if (!mappings.hasMap(mode, this._input.buffer + key))
this._macros.set(this._currentMacro, {
keys: this._macros.get(this._currentMacro, {}).keys + key,
timeRecorded: Date.now()
@@ -832,6 +786,7 @@ const Events = Module("events", {
try {
let stop = false;
let mode = modes.main;
let win = document.commandDispatcher.focusedWindow;
if (win && win.document && "designMode" in win.document && win.document.designMode == "on" && !config.isComposeWindow)
@@ -839,20 +794,19 @@ const Events = Module("events", {
// menus have their own command handlers
if (modes.extended & modes.MENU)
stop = true;
else if (modes.main == modes.PASS_THROUGH)
// let flow continue to handle these keys to cancel escape-all-keys mode
stop = !isEscape(key) && key != "<C-v>"
// handle Escape-one-key mode (Ctrl-v)
else if (modes.passNextKey && !modes.passAllKeys) {
modes.passNextKey = false;
stop = true;
else if (modes.main == modes.QUOTE) {
stop = modes.getStack(1).main !== modes.PASS_THROUGH || isEscape(key);
// We need to preserve QUOTE mode until the escape
// handler to escape the <Esc> key
if (!stop || !isEscape(key))
modes.pop();
mode = modes.getStack(1).main;
}
// handle Escape-all-keys mode (Ctrl-q)
else if (modes.passAllKeys) {
if (modes.passNextKey)
modes.passNextKey = false; // and then let flow continue
else if (isEscapeKey(key) || key == "<C-v>")
; // let flow continue to handle these keys to cancel escape-all-keys mode
else
stop = true;
}
if (stop) {
this._input.buffer = "";
@@ -862,7 +816,7 @@ const Events = Module("events", {
stop = true; // set to false if we should NOT consume this event but let the host app handle it
// just forward event without checking any mappings when the MOW is open
if (dactyl.mode == modes.COMMAND_LINE && (modes.extended & modes.OUTPUT_MULTILINE)) {
if (mode == modes.COMMAND_LINE && (modes.extended & modes.OUTPUT_MULTILINE)) {
commandline.onMultilineOutputEvent(event);
return killEvent();
}
@@ -871,16 +825,16 @@ const Events = Module("events", {
// they are without beeping also fixes key navigation in combo
// boxes, submitting forms, etc.
// FIXME: breaks iabbr for now --mst
if (key in config.ignoreKeys && (config.ignoreKeys[key] & dactyl.mode)) {
if (key in config.ignoreKeys && (config.ignoreKeys[key] & mode)) {
this._input.buffer = "";
return null;
}
// TODO: handle middle click in content area
if (!isEscapeKey(key)) {
if (!isEscape(key)) {
// custom mode...
if (dactyl.mode == modes.CUSTOM) {
if (mode == modes.CUSTOM) {
plugins.onEvent(event);
return killEvent();
}
@@ -910,15 +864,17 @@ const Events = Module("events", {
// whatever reason). if that happens to be correct, well..
// XXX: why not just do that as well for HINTS mode actually?
if (dactyl.mode == modes.CUSTOM)
if (mode == modes.CUSTOM)
return null;
let mainMode = modes.getMode(mode);
let inputStr = this._input.buffer + key;
let countStr = inputStr.match(/^[1-9][0-9]*|/)[0];
let candidateCommand = inputStr.substr(countStr.length);
let map = mappings[event.noremap ? "getDefault" : "get"](dactyl.mode, candidateCommand);
let map = mappings[event.noremap ? "getDefault" : "get"](mode, candidateCommand);
let candidates = mappings.getCandidates(dactyl.mode, candidateCommand);
let candidates = mappings.getCandidates(mode, candidateCommand);
if (candidates.length == 0 && !map) {
map = this._input.pendingMap;
this._input.pendingMap = null;
@@ -929,7 +885,7 @@ const Events = Module("events", {
// counts must be at the start of a complete mapping (10j -> go 10 lines down)
if (countStr && !candidateCommand) {
// no count for insert mode mappings
if (!modes.mainMode.count || modes.mainMode.input)
if (!mainMode.count || mainMode.input)
stop = false;
else
this._input.buffer = inputStr;
@@ -938,7 +894,7 @@ const Events = Module("events", {
this._input.buffer = "";
let map = this._input.pendingArgMap;
this._input.pendingArgMap = null;
if (!isEscapeKey(key)) {
if (!isEscape(key)) {
if (modes.isReplaying && !this.waitForPageLoad())
return null;
map.execute(null, this._input.count, key);
@@ -957,7 +913,7 @@ const Events = Module("events", {
this._input.pendingArgMap = map;
}
else if (this._input.pendingMotionMap) {
if (!isEscapeKey(key))
if (!isEscape(key))
this._input.pendingMotionMap.execute(candidateCommand, this._input.count, null);
this._input.pendingMotionMap = null;
}
@@ -974,14 +930,14 @@ const Events = Module("events", {
stop = false;
}
}
else if (mappings.getCandidates(dactyl.mode, candidateCommand).length > 0 && !event.skipmap) {
else if (mappings.getCandidates(mode, candidateCommand).length > 0 && !event.skipmap) {
this._input.pendingMap = map;
this._input.buffer += key;
}
else { // if the key is neither a mapping nor the start of one
// the mode checking is necessary so that things like g<esc> do not beep
if (this._input.buffer != "" && !event.skipmap &&
(dactyl.mode & (modes.INSERT | modes.COMMAND_LINE | modes.TEXTAREA)))
(mode & (modes.INSERT | modes.COMMAND_LINE | modes.TEXTAREA)))
events.feedkeys(this._input.buffer, { noremap: true, skipmap: true });
this._input.buffer = "";
@@ -989,17 +945,17 @@ const Events = Module("events", {
this._input.pendingMotionMap = null;
this._input.pendingMap = null;
if (!isEscapeKey(key)) {
if (!isEscape(key)) {
// allow key to be passed to the host app if we can't handle it
stop = (dactyl.mode == modes.TEXTAREA);
stop = (mode == modes.TEXTAREA);
if (dactyl.mode == modes.COMMAND_LINE) {
if (mode == modes.COMMAND_LINE) {
if (!(modes.extended & modes.INPUT_MULTILINE))
dactyl.trapErrors(function () {
commandline.onEvent(event); // reroute event in command line mode
});
}
else if (!modes.mainMode.input)
else if (!mainMode.input)
dactyl.beep();
}
}
@@ -1019,9 +975,8 @@ const Events = Module("events", {
// this is need for sites like msn.com which focus the input field on keydown
onKeyUpOrDown: function (event) {
if (modes.passNextKey ^ modes.passAllKeys || Events.isInputElemFocused())
return;
event.stopPropagation();
if (!Events.isInputElemFocused() && !modes.passThrough)
event.stopPropagation();
},
onMouseDown: function (event) {
@@ -1052,20 +1007,18 @@ const Events = Module("events", {
},
onSelectionChange: function (event) {
let couldCopy = false;
let controller = document.commandDispatcher.getControllerForCommand("cmd_copy");
if (controller && controller.isCommandEnabled("cmd_copy"))
couldCopy = true;
let couldCopy = controller && controller.isCommandEnabled("cmd_copy");
if (dactyl.mode != modes.VISUAL) {
if (couldCopy) {
if ((dactyl.mode == modes.TEXTAREA ||
(modes.extended & modes.TEXTAREA))
&& !options["insertmode"])
modes.set(modes.VISUAL, modes.TEXTAREA);
else if (dactyl.mode == modes.CARET)
modes.set(modes.VISUAL, modes.CARET);
}
if (dactyl.mode === modes.VISUAL) {
if (!couldCopy)
modes.pop(); // Really not ideal.
}
else if (couldCopy) {
if (modes.main == modes.TEXTAREA && !options["insertmode"])
modes.push(modes.VISUAL);
else if (dactyl.mode == modes.CARET)
modes.push(modes.VISUAL);
}
// XXX: disabled, as i think automatically starting visual caret mode does more harm than help
// else
@@ -1144,11 +1097,11 @@ const Events = Module("events", {
mappings.add(modes.all,
["<C-z>"], "Temporarily ignore all " + config.appName + " key bindings",
function () { modes.passAllKeys = true; });
function () { modes.push(modes.PASS_THROUGH); });
mappings.add(modes.all,
["<C-v>"], "Pass through next key",
function () { modes.passNextKey = true; });
function () { modes.push(modes.QUOTE); });
mappings.add(modes.all,
["<Nop>"], "Do nothing",