mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-22 00:47:59 +01:00
Fix some major mode changing bugs. Closes issue #55.
--HG-- branch : mode-refactoring
This commit is contained in:
@@ -1532,11 +1532,7 @@ const Buffer = Module("buffer", {
|
|||||||
|
|
||||||
mappings.add(myModes, ["i", "<Insert>"],
|
mappings.add(myModes, ["i", "<Insert>"],
|
||||||
"Start caret mode",
|
"Start caret mode",
|
||||||
function () {
|
function () { modes.push(modes.CARET); });
|
||||||
// setting this option notifies an observer which takes care of the
|
|
||||||
// mode setting
|
|
||||||
options.setPref("accessibility.browsewithcaret", true);
|
|
||||||
});
|
|
||||||
|
|
||||||
mappings.add(myModes, ["<C-c>"],
|
mappings.add(myModes, ["<C-c>"],
|
||||||
"Stop loading the current web page",
|
"Stop loading the current web page",
|
||||||
|
|||||||
@@ -441,7 +441,10 @@ const CommandLine = Module("commandline", {
|
|||||||
*/
|
*/
|
||||||
open: function open(prompt, cmd, extendedMode) {
|
open: function open(prompt, cmd, extendedMode) {
|
||||||
modes.push(modes.COMMAND_LINE, this.currentExtendedMode, {
|
modes.push(modes.COMMAND_LINE, this.currentExtendedMode, {
|
||||||
leave: commandline.closure.leave
|
leave: function (params) {
|
||||||
|
if (params.pop)
|
||||||
|
commandline.leave();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.currentExtendedMode = extendedMode || null;
|
this.currentExtendedMode = extendedMode || null;
|
||||||
@@ -689,13 +692,12 @@ const CommandLine = Module("commandline", {
|
|||||||
};
|
};
|
||||||
|
|
||||||
modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended, {
|
modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended, {
|
||||||
leave: function (newMode) {
|
enter: function (stack) { extra.enter && extra.enter(stack); },
|
||||||
commandline.leave(newMode);
|
leave: function (stack) {
|
||||||
|
commandline.leave(stack);
|
||||||
if (extra.leave)
|
if (extra.leave)
|
||||||
extra.leave(newMode);
|
extra.leave(stack);
|
||||||
},
|
}
|
||||||
restore: function (newMode) { extra.restore && extra.restore(newMode) },
|
|
||||||
save: function (newMode) { extra.save && extra.save(newMode) }
|
|
||||||
});
|
});
|
||||||
this.currentExtendedMode = modes.PROMPT;
|
this.currentExtendedMode = modes.PROMPT;
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ const Dactyl = Module("dactyl", {
|
|||||||
*
|
*
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
clipboardRead: function clipboardRead() {
|
clipboardRead: function clipboardRead(getClipboard) {
|
||||||
let str = null;
|
let str = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -171,7 +171,7 @@ const Dactyl = Module("dactyl", {
|
|||||||
|
|
||||||
transferable.addDataFlavor("text/unicode");
|
transferable.addDataFlavor("text/unicode");
|
||||||
|
|
||||||
if (clipboard.supportsSelectionClipboard())
|
if (!getClipboard && clipboard.supportsSelectionClipboard())
|
||||||
clipboard.getData(transferable, clipboard.kSelectionClipboard);
|
clipboard.getData(transferable, clipboard.kSelectionClipboard);
|
||||||
else
|
else
|
||||||
clipboard.getData(transferable, clipboard.kGlobalClipboard);
|
clipboard.getData(transferable, clipboard.kGlobalClipboard);
|
||||||
|
|||||||
@@ -16,30 +16,11 @@ const Editor = Module("editor", {
|
|||||||
//
|
//
|
||||||
this._lastFindChar = null;
|
this._lastFindChar = null;
|
||||||
this._lastFindCharFunc = null;
|
this._lastFindCharFunc = null;
|
||||||
|
|
||||||
// Hack?
|
|
||||||
dactyl.registerObserver("modeChange", function (oldMode, newMode, stack) {
|
|
||||||
switch (oldMode[0]) {
|
|
||||||
case modes.TEXTAREA:
|
|
||||||
case modes.INSERT:
|
|
||||||
editor.unselectText();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case modes.VISUAL:
|
|
||||||
if (newMode[0] == modes.CARET) {
|
|
||||||
try { // clear any selection made; a simple if (selection) does not work
|
|
||||||
let selection = window.content.getSelection();
|
|
||||||
selection.collapseToStart();
|
|
||||||
}
|
|
||||||
catch (e) {}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
editor.unselectText();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get isCaret() modes.getStack(1).main === modes.CARET,
|
||||||
|
get isTextArea() modes.getStack(1).main === modes.TEXTAREA,
|
||||||
|
|
||||||
line: function () {
|
line: function () {
|
||||||
let line = 1;
|
let line = 1;
|
||||||
let text = Editor.getEditor().value;
|
let text = Editor.getEditor().value;
|
||||||
@@ -60,12 +41,15 @@ const Editor = Module("editor", {
|
|||||||
return col;
|
return col;
|
||||||
},
|
},
|
||||||
|
|
||||||
unselectText: function () {
|
unselectText: function (toEnd) {
|
||||||
let elem = dactyl.focus;
|
let elem = dactyl.focus;
|
||||||
// A error occurs if the element has been removed when "elem.selectionStart" is executed.
|
// A error occurs if the element has been removed when "elem.selectionStart" is executed.
|
||||||
try {
|
try {
|
||||||
if (elem && elem.selectionEnd)
|
if (elem && elem.selectionEnd)
|
||||||
elem.selectionEnd = elem.selectionStart;
|
if (toEnd)
|
||||||
|
elem.selectionStart = elem.selectionEnd;
|
||||||
|
else
|
||||||
|
elem.selectionEnd = elem.selectionStart;
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
},
|
},
|
||||||
@@ -75,7 +59,7 @@ const Editor = Module("editor", {
|
|||||||
return text.substring(Editor.getEditor().selectionStart, Editor.getEditor().selectionEnd);
|
return text.substring(Editor.getEditor().selectionStart, Editor.getEditor().selectionEnd);
|
||||||
},
|
},
|
||||||
|
|
||||||
pasteClipboard: function () {
|
pasteClipboard: function (clipboard, toStart) {
|
||||||
if (dactyl.has("WINNT")) {
|
if (dactyl.has("WINNT")) {
|
||||||
this.executeCommand("cmd_paste");
|
this.executeCommand("cmd_paste");
|
||||||
return;
|
return;
|
||||||
@@ -85,7 +69,7 @@ const Editor = Module("editor", {
|
|||||||
let elem = dactyl.focus;
|
let elem = dactyl.focus;
|
||||||
|
|
||||||
if (elem.setSelectionRange) {
|
if (elem.setSelectionRange) {
|
||||||
let text = dactyl.clipboardRead();
|
let text = dactyl.clipboardRead(clipboard);
|
||||||
if (!text)
|
if (!text)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -101,7 +85,7 @@ const Editor = Module("editor", {
|
|||||||
let tempStr2 = text;
|
let tempStr2 = text;
|
||||||
let tempStr3 = elem.value.substring(rangeEnd);
|
let tempStr3 = elem.value.substring(rangeEnd);
|
||||||
elem.value = tempStr1 + tempStr2 + tempStr3;
|
elem.value = tempStr1 + tempStr2 + tempStr3;
|
||||||
elem.selectionStart = rangeStart + tempStr2.length;
|
elem.selectionStart = rangeStart + (toStart ? 0 : tempStr2.length);
|
||||||
elem.selectionEnd = elem.selectionStart;
|
elem.selectionEnd = elem.selectionStart;
|
||||||
|
|
||||||
elem.scrollTop = curTop;
|
elem.scrollTop = curTop;
|
||||||
@@ -153,7 +137,8 @@ const Editor = Module("editor", {
|
|||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
modes.set(modes.VISUAL, modes.TEXTAREA);
|
if (modes.main != modes.VISUAL)
|
||||||
|
modes.push(modes.VISUAL);
|
||||||
|
|
||||||
switch (motion) {
|
switch (motion) {
|
||||||
case "j":
|
case "j":
|
||||||
@@ -204,16 +189,16 @@ const Editor = Module("editor", {
|
|||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case "d":
|
case "d":
|
||||||
this.executeCommand("cmd_delete", 1);
|
this.executeCommand("cmd_delete", 1);
|
||||||
// need to reset the mode as the visual selection changes it
|
modes.pop(modes.TEXTAREA);
|
||||||
modes.main = modes.TEXTAREA;
|
|
||||||
break;
|
break;
|
||||||
case "c":
|
case "c":
|
||||||
this.executeCommand("cmd_delete", 1);
|
this.executeCommand("cmd_delete", 1);
|
||||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
modes.pop(modes.TEXTAREA);
|
||||||
|
modes.push(modes.INSERT);
|
||||||
break;
|
break;
|
||||||
case "y":
|
case "y":
|
||||||
this.executeCommand("cmd_copy", 1);
|
this.executeCommand("cmd_copy", 1);
|
||||||
this.unselectText();
|
modes.pop(modes.TEXTAREA);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -457,19 +442,37 @@ const Editor = Module("editor", {
|
|||||||
if (hasCount)
|
if (hasCount)
|
||||||
extraInfo.count = true;
|
extraInfo.count = true;
|
||||||
|
|
||||||
|
function caretExecute(arg, again) {
|
||||||
|
function fixSelection() {
|
||||||
|
sel.removeAllRanges();
|
||||||
|
sel.addRange(RangeFind.endpoint(
|
||||||
|
RangeFind.nodeRange(buffer.focusedFrame.document.documentElement),
|
||||||
|
true));
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = buffer.selectionController;
|
||||||
|
let sel = controller.getSelection(controller.SELECTION_NORMAL);
|
||||||
|
if (!sel.rangeCount) // Hack.
|
||||||
|
fixSelection();
|
||||||
|
|
||||||
|
try {
|
||||||
|
controller[caretModeMethod](caretModeArg, arg);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
dactyl.assert(again && e.result === Cr.NS_ERROR_FAILURE);
|
||||||
|
fixSelection();
|
||||||
|
caretExecute(arg, false);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
mappings.add([modes.CARET], keys, "",
|
mappings.add([modes.CARET], keys, "",
|
||||||
function (count) {
|
function (count) {
|
||||||
if (typeof count != "number" || count < 1)
|
if (typeof count != "number" || count < 1)
|
||||||
count = 1;
|
count = 1;
|
||||||
|
|
||||||
let controller = buffer.selectionController;
|
|
||||||
let sel = controller.getSelection(controller.SELECTION_NORMAL);
|
|
||||||
if (!sel.rangeCount) // Hack.
|
|
||||||
sel.addRange(RangeFind.endpoint(
|
|
||||||
RangeFind.nodeRange(buffer.focusedFrame.document.documentElement),
|
|
||||||
true));
|
|
||||||
while (count--)
|
while (count--)
|
||||||
controller[caretModeMethod](caretModeArg, false);
|
caretExecute(false, true);
|
||||||
},
|
},
|
||||||
extraInfo);
|
extraInfo);
|
||||||
|
|
||||||
@@ -479,15 +482,15 @@ const Editor = Module("editor", {
|
|||||||
count = 1;
|
count = 1;
|
||||||
|
|
||||||
let controller = buffer.selectionController;
|
let controller = buffer.selectionController;
|
||||||
while (count--) {
|
while (count-- && modes.main == modes.VISUAL) {
|
||||||
if (modes.extended & modes.TEXTAREA) {
|
if (editor.isTextArea) {
|
||||||
if (typeof visualTextareaCommand == "function")
|
if (typeof visualTextareaCommand == "function")
|
||||||
visualTextareaCommand();
|
visualTextareaCommand();
|
||||||
else
|
else
|
||||||
editor.executeCommand(visualTextareaCommand);
|
editor.executeCommand(visualTextareaCommand);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
controller[caretModeMethod](caretModeArg, true);
|
caretExecute(true, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
extraInfo);
|
extraInfo);
|
||||||
@@ -508,7 +511,7 @@ const Editor = Module("editor", {
|
|||||||
function (count) {
|
function (count) {
|
||||||
commands.forEach(function (cmd)
|
commands.forEach(function (cmd)
|
||||||
editor.executeCommand(cmd, 1));
|
editor.executeCommand(cmd, 1));
|
||||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
modes.push(modes.INSERT);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,7 +611,7 @@ const Editor = Module("editor", {
|
|||||||
|
|
||||||
mappings.add([modes.INSERT],
|
mappings.add([modes.INSERT],
|
||||||
["<C-t>"], "Edit text field in Vi mode",
|
["<C-t>"], "Edit text field in Vi mode",
|
||||||
function () { dactyl.mode = modes.TEXTAREA; });
|
function () { modes.push(modes.TEXTAREA); });
|
||||||
|
|
||||||
mappings.add([modes.INSERT],
|
mappings.add([modes.INSERT],
|
||||||
["<Space>", "<Return>"], "Expand insert mode abbreviation",
|
["<Space>", "<Return>"], "Expand insert mode abbreviation",
|
||||||
@@ -628,7 +631,7 @@ const Editor = Module("editor", {
|
|||||||
["u"], "Undo",
|
["u"], "Undo",
|
||||||
function (count) {
|
function (count) {
|
||||||
editor.executeCommand("cmd_undo", count);
|
editor.executeCommand("cmd_undo", count);
|
||||||
dactyl.mode = modes.TEXTAREA;
|
editor.unselectText();
|
||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
@@ -636,7 +639,7 @@ const Editor = Module("editor", {
|
|||||||
["<C-r>"], "Redo",
|
["<C-r>"], "Redo",
|
||||||
function (count) {
|
function (count) {
|
||||||
editor.executeCommand("cmd_redo", count);
|
editor.executeCommand("cmd_redo", count);
|
||||||
dactyl.mode = modes.TEXTAREA;
|
editor.unselectText();
|
||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
@@ -648,7 +651,7 @@ const Editor = Module("editor", {
|
|||||||
["o"], "Open line below current",
|
["o"], "Open line below current",
|
||||||
function (count) {
|
function (count) {
|
||||||
editor.executeCommand("cmd_endLine", 1);
|
editor.executeCommand("cmd_endLine", 1);
|
||||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
modes.push(modes.INSERT);
|
||||||
events.feedkeys("<Return>");
|
events.feedkeys("<Return>");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -656,7 +659,7 @@ const Editor = Module("editor", {
|
|||||||
["O"], "Open line above current",
|
["O"], "Open line above current",
|
||||||
function (count) {
|
function (count) {
|
||||||
editor.executeCommand("cmd_beginLine", 1);
|
editor.executeCommand("cmd_beginLine", 1);
|
||||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
modes.push(modes.INSERT);
|
||||||
events.feedkeys("<Return>");
|
events.feedkeys("<Return>");
|
||||||
editor.executeCommand("cmd_linePrevious", 1);
|
editor.executeCommand("cmd_linePrevious", 1);
|
||||||
});
|
});
|
||||||
@@ -674,7 +677,7 @@ const Editor = Module("editor", {
|
|||||||
// visual mode
|
// visual mode
|
||||||
mappings.add([modes.CARET, modes.TEXTAREA],
|
mappings.add([modes.CARET, modes.TEXTAREA],
|
||||||
["v"], "Start visual mode",
|
["v"], "Start visual mode",
|
||||||
function (count) { modes.set(modes.VISUAL, dactyl.mode); });
|
function (count) { modes.push(modes.VISUAL); });
|
||||||
|
|
||||||
mappings.add([modes.VISUAL],
|
mappings.add([modes.VISUAL],
|
||||||
["v"], "End visual mode",
|
["v"], "End visual mode",
|
||||||
@@ -683,7 +686,7 @@ const Editor = Module("editor", {
|
|||||||
mappings.add([modes.TEXTAREA],
|
mappings.add([modes.TEXTAREA],
|
||||||
["V"], "Start visual line mode",
|
["V"], "Start visual line mode",
|
||||||
function (count) {
|
function (count) {
|
||||||
modes.set(modes.VISUAL, modes.TEXTAREA | modes.LINE);
|
modes.push(modes.VISUAL, modes.LINE);
|
||||||
editor.executeCommand("cmd_beginLine", 1);
|
editor.executeCommand("cmd_beginLine", 1);
|
||||||
editor.executeCommand("cmd_selectLineNext", 1);
|
editor.executeCommand("cmd_selectLineNext", 1);
|
||||||
});
|
});
|
||||||
@@ -691,17 +694,17 @@ const Editor = Module("editor", {
|
|||||||
mappings.add([modes.VISUAL],
|
mappings.add([modes.VISUAL],
|
||||||
["c", "s"], "Change selected text",
|
["c", "s"], "Change selected text",
|
||||||
function (count) {
|
function (count) {
|
||||||
dactyl.assert(modes.extended & modes.TEXTAREA);
|
dactyl.assert(editor.isTextArea);
|
||||||
editor.executeCommand("cmd_cut");
|
editor.executeCommand("cmd_cut");
|
||||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
modes.replace(modes.VISUAL);
|
||||||
});
|
});
|
||||||
|
|
||||||
mappings.add([modes.VISUAL],
|
mappings.add([modes.VISUAL],
|
||||||
["d"], "Delete selected text",
|
["d"], "Delete selected text",
|
||||||
function (count) {
|
function (count) {
|
||||||
if (modes.extended & modes.TEXTAREA) {
|
if (editor.isTextArea) {
|
||||||
editor.executeCommand("cmd_cut");
|
editor.executeCommand("cmd_cut");
|
||||||
modes.set(modes.TEXTAREA);
|
modes.pop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dactyl.beep();
|
dactyl.beep();
|
||||||
@@ -710,9 +713,9 @@ const Editor = Module("editor", {
|
|||||||
mappings.add([modes.VISUAL],
|
mappings.add([modes.VISUAL],
|
||||||
["y"], "Yank selected text",
|
["y"], "Yank selected text",
|
||||||
function (count) {
|
function (count) {
|
||||||
if (modes.extended & modes.TEXTAREA) {
|
if (editor.isTextArea) {
|
||||||
editor.executeCommand("cmd_copy");
|
editor.executeCommand("cmd_copy");
|
||||||
modes.set(modes.TEXTAREA);
|
modes.pop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dactyl.clipboardWrite(buffer.getCurrentWord(), true);
|
dactyl.clipboardWrite(buffer.getCurrentWord(), true);
|
||||||
@@ -721,12 +724,12 @@ const Editor = Module("editor", {
|
|||||||
mappings.add([modes.VISUAL, modes.TEXTAREA],
|
mappings.add([modes.VISUAL, modes.TEXTAREA],
|
||||||
["p"], "Paste clipboard contents",
|
["p"], "Paste clipboard contents",
|
||||||
function (count) {
|
function (count) {
|
||||||
dactyl.assert(!(modes.extended & modes.CARET));
|
dactyl.assert(!editor.isCaret);
|
||||||
if (!count)
|
if (!count)
|
||||||
count = 1;
|
count = 1;
|
||||||
while (count--)
|
while (count--)
|
||||||
editor.executeCommand("cmd_paste");
|
editor.executeCommand("cmd_paste");
|
||||||
dactyl.mode = modes.TEXTAREA;
|
modes.pop(modes.TEXTAREA);
|
||||||
});
|
});
|
||||||
|
|
||||||
// finding characters
|
// finding characters
|
||||||
@@ -786,7 +789,7 @@ const Editor = Module("editor", {
|
|||||||
text.substring(pos + 1);
|
text.substring(pos + 1);
|
||||||
editor.moveToPosition(pos + 1, true, false);
|
editor.moveToPosition(pos + 1, true, false);
|
||||||
}
|
}
|
||||||
modes.set(modes.TEXTAREA);
|
modes.pop(modes.TEXTAREA);
|
||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -76,11 +76,11 @@ const Events = Module("events", {
|
|||||||
this._activeMenubar = false;
|
this._activeMenubar = false;
|
||||||
this.addSessionListener(window, "DOMMenuBarActive", this.closure.onDOMMenuBarActive, true);
|
this.addSessionListener(window, "DOMMenuBarActive", this.closure.onDOMMenuBarActive, true);
|
||||||
this.addSessionListener(window, "DOMMenuBarInactive", this.closure.onDOMMenuBarInactive, true);
|
this.addSessionListener(window, "DOMMenuBarInactive", this.closure.onDOMMenuBarInactive, true);
|
||||||
this.addSessionListener(window, "focus", this.wrapListener(this.closure.onFocus), true);
|
this.addSessionListener(window, "focus", this.wrapListener(this.onFocus), true);
|
||||||
this.addSessionListener(window, "keydown", this.wrapListener(this.closure.onKeyUpOrDown), true);
|
this.addSessionListener(window, "keydown", this.wrapListener(this.onKeyUpOrDown), true);
|
||||||
this.addSessionListener(window, "keypress", this.wrapListener(this.closure.onKeyPress), true);
|
this.addSessionListener(window, "keypress", this.wrapListener(this.onKeyPress), true);
|
||||||
this.addSessionListener(window, "keyup", this.wrapListener(this.closure.onKeyUpOrDown), true);
|
this.addSessionListener(window, "keyup", this.wrapListener(this.onKeyUpOrDown), true);
|
||||||
this.addSessionListener(window, "mousedown", this.wrapListener(this.closure.onMouseDown), true);
|
this.addSessionListener(window, "mousedown", this.wrapListener(this.onMouseDown), true);
|
||||||
this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true);
|
this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true);
|
||||||
this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true);
|
this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true);
|
||||||
this.addSessionListener(window, "resize", this.closure.onResize, true);
|
this.addSessionListener(window, "resize", this.closure.onResize, true);
|
||||||
@@ -90,7 +90,8 @@ const Events = Module("events", {
|
|||||||
destroy: function () {
|
destroy: function () {
|
||||||
util.dump("Removing all event listeners");
|
util.dump("Removing all event listeners");
|
||||||
for (let args in values(this.sessionListeners))
|
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) {
|
addSessionListener: function (target, event, callback, capture) {
|
||||||
let args = Array.slice(arguments, 0);
|
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);
|
this.sessionListeners.push(args);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -113,6 +115,7 @@ const Events = Module("events", {
|
|||||||
* Wraps an event listener to ensure that errors are reported.
|
* Wraps an event listener to ensure that errors are reported.
|
||||||
*/
|
*/
|
||||||
wrapListener: function wrapListener(method, self) {
|
wrapListener: function wrapListener(method, self) {
|
||||||
|
self = self || this;
|
||||||
return function (event) {
|
return function (event) {
|
||||||
try {
|
try {
|
||||||
method.apply(self, arguments);
|
method.apply(self, arguments);
|
||||||
@@ -625,69 +628,17 @@ const Events = Module("events", {
|
|||||||
* The global escape key handler. This is called in ALL modes.
|
* The global escape key handler. This is called in ALL modes.
|
||||||
*/
|
*/
|
||||||
onEscape: function () {
|
onEscape: function () {
|
||||||
if (modes.passNextKey)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (modes.passAllKeys) {
|
|
||||||
modes.passAllKeys = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (dactyl.mode) {
|
switch (dactyl.mode) {
|
||||||
case modes.NORMAL:
|
case modes.COMMAND_LINE:
|
||||||
// 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.INSERT:
|
case modes.INSERT:
|
||||||
if ((modes.extended & modes.TEXTAREA))
|
case modes.PASS_THROUGH:
|
||||||
dactyl.mode = modes.TEXTAREA;
|
case modes.QUOTE:
|
||||||
else
|
case modes.TEXTAREA:
|
||||||
modes.reset();
|
case modes.VISUAL:
|
||||||
|
modes.pop();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // HINTS, CUSTOM or COMMAND_LINE
|
default:
|
||||||
modes.reset();
|
modes.reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -752,12 +703,15 @@ const Events = Module("events", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (elem instanceof HTMLTextAreaElement || (elem && util.computedStyle(elem).MozUserModify == "read-write")) {
|
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"])
|
if (options["insertmode"])
|
||||||
modes.set(modes.INSERT);
|
modes.set(modes.INSERT);
|
||||||
else if (elem.selectionEnd - elem.selectionStart > 0)
|
else {
|
||||||
modes.set(modes.VISUAL, modes.TEXTAREA);
|
modes.set(modes.TEXTAREA);
|
||||||
else
|
if (elem.selectionEnd - elem.selectionStart > 0)
|
||||||
modes.main = modes.TEXTAREA;
|
modes.push(modes.VISUAL);
|
||||||
|
}
|
||||||
if (hasHTMLDocument(win))
|
if (hasHTMLDocument(win))
|
||||||
buffer.lastInputField = elem;
|
buffer.lastInputField = elem;
|
||||||
return;
|
return;
|
||||||
@@ -772,7 +726,7 @@ const Events = Module("events", {
|
|||||||
if (elem == null && urlbar && urlbar.inputField == this._lastFocus)
|
if (elem == null && urlbar && urlbar.inputField == this._lastFocus)
|
||||||
util.threadYield(true);
|
util.threadYield(true);
|
||||||
|
|
||||||
if (dactyl.mode & (modes.EMBED | modes.INSERT | modes.TEXTAREA | modes.VISUAL))
|
if (modes.getMode(modes.main).ownsFocus)
|
||||||
modes.reset();
|
modes.reset();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@@ -784,7 +738,7 @@ const Events = Module("events", {
|
|||||||
// the commandline has focus
|
// the commandline has focus
|
||||||
// TODO: ...help me...please...
|
// TODO: ...help me...please...
|
||||||
onKeyPress: function (event) {
|
onKeyPress: function (event) {
|
||||||
function isEscapeKey(key) key == "<Esc>" || key == "<C-[>";
|
function isEscape(key) key == "<Esc>" || key == "<C-[>";
|
||||||
|
|
||||||
function killEvent() {
|
function killEvent() {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -802,7 +756,7 @@ const Events = Module("events", {
|
|||||||
dactyl.echomsg("Recorded macro '" + this._currentMacro + "'");
|
dactyl.echomsg("Recorded macro '" + this._currentMacro + "'");
|
||||||
return killEvent();
|
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, {
|
this._macros.set(this._currentMacro, {
|
||||||
keys: this._macros.get(this._currentMacro, {}).keys + key,
|
keys: this._macros.get(this._currentMacro, {}).keys + key,
|
||||||
timeRecorded: Date.now()
|
timeRecorded: Date.now()
|
||||||
@@ -832,6 +786,7 @@ const Events = Module("events", {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
let stop = false;
|
let stop = false;
|
||||||
|
let mode = modes.main;
|
||||||
|
|
||||||
let win = document.commandDispatcher.focusedWindow;
|
let win = document.commandDispatcher.focusedWindow;
|
||||||
if (win && win.document && "designMode" in win.document && win.document.designMode == "on" && !config.isComposeWindow)
|
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
|
// menus have their own command handlers
|
||||||
if (modes.extended & modes.MENU)
|
if (modes.extended & modes.MENU)
|
||||||
stop = true;
|
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)
|
// handle Escape-one-key mode (Ctrl-v)
|
||||||
else if (modes.passNextKey && !modes.passAllKeys) {
|
else if (modes.main == modes.QUOTE) {
|
||||||
modes.passNextKey = false;
|
stop = modes.getStack(1).main !== modes.PASS_THROUGH || isEscape(key);
|
||||||
stop = true;
|
// 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)
|
// 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) {
|
if (stop) {
|
||||||
this._input.buffer = "";
|
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
|
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
|
// 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);
|
commandline.onMultilineOutputEvent(event);
|
||||||
return killEvent();
|
return killEvent();
|
||||||
}
|
}
|
||||||
@@ -871,16 +825,16 @@ const Events = Module("events", {
|
|||||||
// they are without beeping also fixes key navigation in combo
|
// they are without beeping also fixes key navigation in combo
|
||||||
// boxes, submitting forms, etc.
|
// boxes, submitting forms, etc.
|
||||||
// FIXME: breaks iabbr for now --mst
|
// 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 = "";
|
this._input.buffer = "";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle middle click in content area
|
// TODO: handle middle click in content area
|
||||||
|
|
||||||
if (!isEscapeKey(key)) {
|
if (!isEscape(key)) {
|
||||||
// custom mode...
|
// custom mode...
|
||||||
if (dactyl.mode == modes.CUSTOM) {
|
if (mode == modes.CUSTOM) {
|
||||||
plugins.onEvent(event);
|
plugins.onEvent(event);
|
||||||
return killEvent();
|
return killEvent();
|
||||||
}
|
}
|
||||||
@@ -910,15 +864,17 @@ const Events = Module("events", {
|
|||||||
// whatever reason). if that happens to be correct, well..
|
// whatever reason). if that happens to be correct, well..
|
||||||
// XXX: why not just do that as well for HINTS mode actually?
|
// XXX: why not just do that as well for HINTS mode actually?
|
||||||
|
|
||||||
if (dactyl.mode == modes.CUSTOM)
|
if (mode == modes.CUSTOM)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
let mainMode = modes.getMode(mode);
|
||||||
|
|
||||||
let inputStr = this._input.buffer + key;
|
let inputStr = this._input.buffer + key;
|
||||||
let countStr = inputStr.match(/^[1-9][0-9]*|/)[0];
|
let countStr = inputStr.match(/^[1-9][0-9]*|/)[0];
|
||||||
let candidateCommand = inputStr.substr(countStr.length);
|
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) {
|
if (candidates.length == 0 && !map) {
|
||||||
map = this._input.pendingMap;
|
map = this._input.pendingMap;
|
||||||
this._input.pendingMap = null;
|
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)
|
// counts must be at the start of a complete mapping (10j -> go 10 lines down)
|
||||||
if (countStr && !candidateCommand) {
|
if (countStr && !candidateCommand) {
|
||||||
// no count for insert mode mappings
|
// no count for insert mode mappings
|
||||||
if (!modes.mainMode.count || modes.mainMode.input)
|
if (!mainMode.count || mainMode.input)
|
||||||
stop = false;
|
stop = false;
|
||||||
else
|
else
|
||||||
this._input.buffer = inputStr;
|
this._input.buffer = inputStr;
|
||||||
@@ -938,7 +894,7 @@ const Events = Module("events", {
|
|||||||
this._input.buffer = "";
|
this._input.buffer = "";
|
||||||
let map = this._input.pendingArgMap;
|
let map = this._input.pendingArgMap;
|
||||||
this._input.pendingArgMap = null;
|
this._input.pendingArgMap = null;
|
||||||
if (!isEscapeKey(key)) {
|
if (!isEscape(key)) {
|
||||||
if (modes.isReplaying && !this.waitForPageLoad())
|
if (modes.isReplaying && !this.waitForPageLoad())
|
||||||
return null;
|
return null;
|
||||||
map.execute(null, this._input.count, key);
|
map.execute(null, this._input.count, key);
|
||||||
@@ -957,7 +913,7 @@ const Events = Module("events", {
|
|||||||
this._input.pendingArgMap = map;
|
this._input.pendingArgMap = map;
|
||||||
}
|
}
|
||||||
else if (this._input.pendingMotionMap) {
|
else if (this._input.pendingMotionMap) {
|
||||||
if (!isEscapeKey(key))
|
if (!isEscape(key))
|
||||||
this._input.pendingMotionMap.execute(candidateCommand, this._input.count, null);
|
this._input.pendingMotionMap.execute(candidateCommand, this._input.count, null);
|
||||||
this._input.pendingMotionMap = null;
|
this._input.pendingMotionMap = null;
|
||||||
}
|
}
|
||||||
@@ -974,14 +930,14 @@ const Events = Module("events", {
|
|||||||
stop = false;
|
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.pendingMap = map;
|
||||||
this._input.buffer += key;
|
this._input.buffer += key;
|
||||||
}
|
}
|
||||||
else { // if the key is neither a mapping nor the start of one
|
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
|
// the mode checking is necessary so that things like g<esc> do not beep
|
||||||
if (this._input.buffer != "" && !event.skipmap &&
|
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 });
|
events.feedkeys(this._input.buffer, { noremap: true, skipmap: true });
|
||||||
|
|
||||||
this._input.buffer = "";
|
this._input.buffer = "";
|
||||||
@@ -989,17 +945,17 @@ const Events = Module("events", {
|
|||||||
this._input.pendingMotionMap = null;
|
this._input.pendingMotionMap = null;
|
||||||
this._input.pendingMap = 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
|
// 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))
|
if (!(modes.extended & modes.INPUT_MULTILINE))
|
||||||
dactyl.trapErrors(function () {
|
dactyl.trapErrors(function () {
|
||||||
commandline.onEvent(event); // reroute event in command line mode
|
commandline.onEvent(event); // reroute event in command line mode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (!modes.mainMode.input)
|
else if (!mainMode.input)
|
||||||
dactyl.beep();
|
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
|
// this is need for sites like msn.com which focus the input field on keydown
|
||||||
onKeyUpOrDown: function (event) {
|
onKeyUpOrDown: function (event) {
|
||||||
if (modes.passNextKey ^ modes.passAllKeys || Events.isInputElemFocused())
|
if (!Events.isInputElemFocused() && !modes.passThrough)
|
||||||
return;
|
event.stopPropagation();
|
||||||
event.stopPropagation();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onMouseDown: function (event) {
|
onMouseDown: function (event) {
|
||||||
@@ -1052,20 +1007,18 @@ const Events = Module("events", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
onSelectionChange: function (event) {
|
onSelectionChange: function (event) {
|
||||||
let couldCopy = false;
|
|
||||||
let controller = document.commandDispatcher.getControllerForCommand("cmd_copy");
|
let controller = document.commandDispatcher.getControllerForCommand("cmd_copy");
|
||||||
if (controller && controller.isCommandEnabled("cmd_copy"))
|
let couldCopy = controller && controller.isCommandEnabled("cmd_copy");
|
||||||
couldCopy = true;
|
|
||||||
|
|
||||||
if (dactyl.mode != modes.VISUAL) {
|
if (dactyl.mode === modes.VISUAL) {
|
||||||
if (couldCopy) {
|
if (!couldCopy)
|
||||||
if ((dactyl.mode == modes.TEXTAREA ||
|
modes.pop(); // Really not ideal.
|
||||||
(modes.extended & modes.TEXTAREA))
|
}
|
||||||
&& !options["insertmode"])
|
else if (couldCopy) {
|
||||||
modes.set(modes.VISUAL, modes.TEXTAREA);
|
if (modes.main == modes.TEXTAREA && !options["insertmode"])
|
||||||
else if (dactyl.mode == modes.CARET)
|
modes.push(modes.VISUAL);
|
||||||
modes.set(modes.VISUAL, modes.CARET);
|
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
|
// XXX: disabled, as i think automatically starting visual caret mode does more harm than help
|
||||||
// else
|
// else
|
||||||
@@ -1144,11 +1097,11 @@ const Events = Module("events", {
|
|||||||
|
|
||||||
mappings.add(modes.all,
|
mappings.add(modes.all,
|
||||||
["<C-z>"], "Temporarily ignore all " + config.appName + " key bindings",
|
["<C-z>"], "Temporarily ignore all " + config.appName + " key bindings",
|
||||||
function () { modes.passAllKeys = true; });
|
function () { modes.push(modes.PASS_THROUGH); });
|
||||||
|
|
||||||
mappings.add(modes.all,
|
mappings.add(modes.all,
|
||||||
["<C-v>"], "Pass through next key",
|
["<C-v>"], "Pass through next key",
|
||||||
function () { modes.passNextKey = true; });
|
function () { modes.push(modes.QUOTE); });
|
||||||
|
|
||||||
mappings.add(modes.all,
|
mappings.add(modes.all,
|
||||||
["<Nop>"], "Do nothing",
|
["<Nop>"], "Do nothing",
|
||||||
|
|||||||
@@ -30,14 +30,42 @@ const Modes = Module("modes", {
|
|||||||
this.boundProperties = {};
|
this.boundProperties = {};
|
||||||
|
|
||||||
// main modes, only one should ever be active
|
// main modes, only one should ever be active
|
||||||
this.addMode("NORMAL", { char: "n", display: null });
|
this.addMode("NORMAL", { char: "n", display: function () null });
|
||||||
this.addMode("INSERT", { char: "i", input: true });
|
this.addMode("INSERT", { char: "i", input: true, ownsFocus: true });
|
||||||
this.addMode("VISUAL", { char: "v", display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : "") });
|
this.addMode("VISUAL", { char: "v", ownsFocus: true, display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : "") }, {
|
||||||
|
leave: function (stack, newMode) {
|
||||||
|
if (newMode.main == modes.CARET) {
|
||||||
|
let selection = window.content.getSelection();
|
||||||
|
if (selection && !selection.isCollapsed)
|
||||||
|
selection.collapseToStart();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
editor.unselectText();
|
||||||
|
}
|
||||||
|
});
|
||||||
this.addMode("COMMAND_LINE", { char: "c", input: true });
|
this.addMode("COMMAND_LINE", { char: "c", input: true });
|
||||||
this.addMode("CARET"); // text cursor is visible
|
this.addMode("CARET", {}, {
|
||||||
this.addMode("TEXTAREA", { char: "i" });
|
get pref() options.getPref("accessibility.browsewithcaret"),
|
||||||
this.addMode("EMBED", { input: true });
|
set pref(val) options.setPref("accessibility.browsewithcaret", val),
|
||||||
this.addMode("CUSTOM", { display: function () plugins.mode });
|
enter: function (stack) {
|
||||||
|
if (stack.pop && !this.pref)
|
||||||
|
modes.pop();
|
||||||
|
else if (!stack.pop && !this.pref)
|
||||||
|
this.pref = true;
|
||||||
|
},
|
||||||
|
leave: function (stack) {
|
||||||
|
if (!stack.push && this.pref)
|
||||||
|
this.pref = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.addMode("TEXTAREA", { char: "i", ownsFocus: true });
|
||||||
|
this.addMode("EMBED", { input: true, ownsFocus: true });
|
||||||
|
this.addMode("PASS_THROUGH");
|
||||||
|
this.addMode("QUOTE", {
|
||||||
|
display: function () modes.getStack(1).main == modes.PASS_THROUGH
|
||||||
|
? (modes.getStack(2).mainMode.display() || modes.getStack(2).mainMode.name) + " (next)"
|
||||||
|
: "PASS THROUGH (next)"
|
||||||
|
});
|
||||||
// this._extended modes, can include multiple modes, and even main modes
|
// this._extended modes, can include multiple modes, and even main modes
|
||||||
this.addMode("EX", true);
|
this.addMode("EX", true);
|
||||||
this.addMode("HINTS", true);
|
this.addMode("HINTS", true);
|
||||||
@@ -45,30 +73,31 @@ const Modes = Module("modes", {
|
|||||||
this.addMode("OUTPUT_MULTILINE", true);
|
this.addMode("OUTPUT_MULTILINE", true);
|
||||||
this.addMode("SEARCH_FORWARD", true);
|
this.addMode("SEARCH_FORWARD", true);
|
||||||
this.addMode("SEARCH_BACKWARD", true);
|
this.addMode("SEARCH_BACKWARD", true);
|
||||||
this.addMode("SEARCH_VIEW_FORWARD", true);
|
|
||||||
this.addMode("SEARCH_VIEW_BACKWARD", true);
|
|
||||||
this.addMode("MENU", true); // a popupmenu is active
|
this.addMode("MENU", true); // a popupmenu is active
|
||||||
this.addMode("LINE", true); // linewise visual mode
|
this.addMode("LINE", true); // linewise visual mode
|
||||||
this.addMode("PROMPT", true);
|
this.addMode("PROMPT", true);
|
||||||
|
|
||||||
this.push(this.NORMAL, 0, {
|
this.push(this.NORMAL, 0, {
|
||||||
restore: function (prev) {
|
enter: function (stack, prev) {
|
||||||
// disable caret mode when we want to switch to normal mode
|
|
||||||
if (options.getPref("accessibility.browsewithcaret"))
|
if (options.getPref("accessibility.browsewithcaret"))
|
||||||
options.setPref("accessibility.browsewithcaret", false);
|
options.setPref("accessibility.browsewithcaret", false);
|
||||||
|
|
||||||
statusline.updateUrl();
|
statusline.updateUrl();
|
||||||
dactyl.focusContent(true);
|
if (prev.mainMode.input || prev.mainMode.ownsFocus)
|
||||||
|
dactyl.focusContent(true);
|
||||||
|
if (prev.main === modes.NORMAL) {
|
||||||
|
dactyl.focusContent(true);
|
||||||
|
// clear any selection made
|
||||||
|
let selection = window.content.getSelection();
|
||||||
|
if (selection && !selection.isCollapsed)
|
||||||
|
selection.collapseToStart();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_getModeMessage: function () {
|
_getModeMessage: function () {
|
||||||
if (this._passNextKey && !this._passAllKeys)
|
|
||||||
return "-- PASS THROUGH (next) --";
|
|
||||||
else if (this._passAllKeys && !this._passNextKey)
|
|
||||||
return "-- PASS THROUGH --";
|
|
||||||
|
|
||||||
// when recording a macro
|
// when recording a macro
|
||||||
let macromode = "";
|
let macromode = "";
|
||||||
if (modes.isRecording)
|
if (modes.isRecording)
|
||||||
@@ -81,7 +110,8 @@ const Modes = Module("modes", {
|
|||||||
ext += " (menu)";
|
ext += " (menu)";
|
||||||
ext += " --" + macromode;
|
ext += " --" + macromode;
|
||||||
|
|
||||||
if (this._main in this._modeMap && typeof this._modeMap[this._main].display == "function")
|
let val = this._modeMap[this._main].display();
|
||||||
|
if (val)
|
||||||
return "-- " + this._modeMap[this._main].display() + ext;
|
return "-- " + this._modeMap[this._main].display() + ext;
|
||||||
return macromode;
|
return macromode;
|
||||||
},
|
},
|
||||||
@@ -98,27 +128,31 @@ const Modes = Module("modes", {
|
|||||||
|
|
||||||
get topOfStack() this._modeStack[this._modeStack.length - 1],
|
get topOfStack() this._modeStack[this._modeStack.length - 1],
|
||||||
|
|
||||||
addMode: function (name, extended, options) {
|
addMode: function (name, extended, options, params) {
|
||||||
let disp = name.replace("_", " ", "g");
|
let disp = name.replace("_", " ", "g");
|
||||||
this[name] = 1 << this._lastMode++;
|
this[name] = 1 << this._lastMode++;
|
||||||
|
|
||||||
if (typeof extended == "object") {
|
if (typeof extended == "object") {
|
||||||
|
params = options;
|
||||||
options = extended;
|
options = extended;
|
||||||
extended = false;
|
extended = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mode = util.extend({
|
let mode = util.extend({
|
||||||
extended: extended,
|
|
||||||
count: true,
|
count: true,
|
||||||
|
disp: disp,
|
||||||
|
extended: extended,
|
||||||
input: false,
|
input: false,
|
||||||
mask: this[name],
|
mask: this[name],
|
||||||
name: name,
|
name: name,
|
||||||
disp: disp
|
params: params || {}
|
||||||
}, options);
|
}, options);
|
||||||
if (mode.char) {
|
if (mode.char) {
|
||||||
this.modeChars[mode.char] = this.modeChars[mode.char] || [];
|
this.modeChars[mode.char] = this.modeChars[mode.char] || [];
|
||||||
this.modeChars[mode.char].push(mode);
|
this.modeChars[mode.char].push(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.display !== null)
|
if (mode.display == null)
|
||||||
mode.display = function () disp;
|
mode.display = function () disp;
|
||||||
this._modeMap[name] = mode;
|
this._modeMap[name] = mode;
|
||||||
this._modeMap[this[name]] = mode;
|
this._modeMap[this[name]] = mode;
|
||||||
@@ -129,6 +163,8 @@ const Modes = Module("modes", {
|
|||||||
|
|
||||||
getMode: function (name) this._modeMap[name],
|
getMode: function (name) this._modeMap[name],
|
||||||
|
|
||||||
|
getStack: function (idx) this._modeStack[this._modeStack.length - idx - 1] || this._modeStack[0],
|
||||||
|
|
||||||
getCharModes: function (chr) [m for (m in values(this._modeMap)) if (m.char == chr)],
|
getCharModes: function (chr) [m for (m in values(this._modeMap)) if (m.char == chr)],
|
||||||
|
|
||||||
matchModes: function (obj)
|
matchModes: function (obj)
|
||||||
@@ -158,7 +194,7 @@ const Modes = Module("modes", {
|
|||||||
// helper function to set both modes in one go
|
// helper function to set both modes in one go
|
||||||
// if silent == true, you also need to take care of the mode handling changes yourself
|
// if silent == true, you also need to take care of the mode handling changes yourself
|
||||||
set: function (mainMode, extendedMode, params, stack) {
|
set: function (mainMode, extendedMode, params, stack) {
|
||||||
params = params || {};
|
params = params || this.getMode(mainMode || this.main).params;
|
||||||
|
|
||||||
if (!stack && mainMode != null && this._modeStack.length > 1)
|
if (!stack && mainMode != null && this._modeStack.length > 1)
|
||||||
this.reset();
|
this.reset();
|
||||||
@@ -166,9 +202,8 @@ const Modes = Module("modes", {
|
|||||||
let push = mainMode != null && !(stack && stack.pop) &&
|
let push = mainMode != null && !(stack && stack.pop) &&
|
||||||
Modes.StackElem(mainMode, extendedMode || this.NONE, params, {});
|
Modes.StackElem(mainMode, extendedMode || this.NONE, params, {});
|
||||||
if (push && this.topOfStack) {
|
if (push && this.topOfStack) {
|
||||||
if (this.topOfStack.params.save)
|
if (this.topOfStack.params.leave)
|
||||||
this.topOfStack.params.save(push);
|
this.topOfStack.params.leave({ push: push }, push);
|
||||||
|
|
||||||
for (let [id, { obj, prop }] in Iterator(this.boundProperties)) {
|
for (let [id, { obj, prop }] in Iterator(this.boundProperties)) {
|
||||||
if (!obj.get())
|
if (!obj.get())
|
||||||
delete this.boundProperties(id);
|
delete this.boundProperties(id);
|
||||||
@@ -189,8 +224,12 @@ const Modes = Module("modes", {
|
|||||||
this._extended = this.NONE;
|
this._extended = this.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let prev = stack && stack.pop || this.topOfStack;
|
||||||
if (push)
|
if (push)
|
||||||
this._modeStack.push(push);
|
this._modeStack.push(push);
|
||||||
|
if (this.topOfStack.params.enter && prev)
|
||||||
|
this.topOfStack.params.enter(push ? { push: push } : stack || {},
|
||||||
|
prev);
|
||||||
|
|
||||||
dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack);
|
dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack);
|
||||||
|
|
||||||
@@ -202,22 +241,31 @@ const Modes = Module("modes", {
|
|||||||
this.set(mainMode, extendedMode, params, { push: this.topOfStack });
|
this.set(mainMode, extendedMode, params, { push: this.topOfStack });
|
||||||
},
|
},
|
||||||
|
|
||||||
pop: function () {
|
pop: function (mode) {
|
||||||
let a = this._modeStack.pop();
|
while (this._modeStack.length > 1 && this.main != mode) {
|
||||||
if (a.params.leave)
|
let a = this._modeStack.pop();
|
||||||
a.params.leave(this.topOfStack);
|
if (a.params.leave)
|
||||||
|
a.params.leave({ pop: a }, this.topOfStack);
|
||||||
|
|
||||||
this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params, { pop: a });
|
this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params, { pop: a });
|
||||||
if (this.topOfStack.params.restore)
|
|
||||||
this.topOfStack.params.restore(a);
|
|
||||||
|
|
||||||
for (let [k, { obj, prop, value }] in Iterator(this.topOfStack.saved))
|
for (let [k, { obj, prop, value }] in Iterator(this.topOfStack.saved))
|
||||||
obj[prop] = value;
|
obj[prop] = value;
|
||||||
|
|
||||||
|
if (mode == null)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
replace: function (mode, oldMode) {
|
||||||
|
// TODO: This should really be done in one step.
|
||||||
|
this.pop(oldMode);
|
||||||
|
this.push(mode);
|
||||||
},
|
},
|
||||||
|
|
||||||
reset: function () {
|
reset: function () {
|
||||||
if (this._modeStack.length == 1 && this.topOfStack.params.restore)
|
if (this._modeStack.length == 1 && this.topOfStack.params.enter)
|
||||||
this.topOfStack.params.restore(this.topOfStack);
|
this.topOfStack.params.enter({}, this.topOfStack);
|
||||||
while (this._modeStack.length > 1)
|
while (this._modeStack.length > 1)
|
||||||
this.pop();
|
this.pop();
|
||||||
},
|
},
|
||||||
@@ -229,12 +277,6 @@ const Modes = Module("modes", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get passNextKey() this._passNextKey,
|
|
||||||
set passNextKey(value) { this._passNextKey = value; this.show(); },
|
|
||||||
|
|
||||||
get passAllKeys() this._passAllKeys,
|
|
||||||
set passAllKeys(value) { this._passAllKeys = value; this.show(); },
|
|
||||||
|
|
||||||
get isRecording() this._isRecording,
|
get isRecording() this._isRecording,
|
||||||
set isRecording(value) { this._isRecording = value; this.show(); },
|
set isRecording(value) { this._isRecording = value; this.show(); },
|
||||||
|
|
||||||
@@ -247,7 +289,17 @@ const Modes = Module("modes", {
|
|||||||
get extended() this._extended,
|
get extended() this._extended,
|
||||||
set extended(value) { this.set(null, value); }
|
set extended(value) { this.set(null, value); }
|
||||||
}, {
|
}, {
|
||||||
StackElem: Struct("main", "extended", "params", "saved"),
|
StackElem: (function () {
|
||||||
|
let struct = Struct("main", "extended", "params", "saved");
|
||||||
|
struct.prototype.__defineGetter__("mainMode", function () modes.getMode(this.main));
|
||||||
|
struct.prototype.toString = function () !loaded.modes ? this.main : "[mode " +
|
||||||
|
modes.getMode(this.main).name +
|
||||||
|
(!this.extended ? "" :
|
||||||
|
"(" +
|
||||||
|
[modes.getMode(1<<i).name for (i in util.range(0, 32)) if (this.extended & (1<<i))].join("|") +
|
||||||
|
")") + "]";
|
||||||
|
return struct;
|
||||||
|
})(),
|
||||||
cacheId: 0,
|
cacheId: 0,
|
||||||
boundProperty: function boundProperty(desc) {
|
boundProperty: function boundProperty(desc) {
|
||||||
desc = desc || {};
|
desc = desc || {};
|
||||||
@@ -270,6 +322,15 @@ const Modes = Module("modes", {
|
|||||||
})
|
})
|
||||||
}, desc));
|
}, desc));
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
options: function () {
|
||||||
|
options.observePref("accessibility.browsewithcaret", function (value) {
|
||||||
|
if (!value && modes.topOfStack.main === modes.CARET)
|
||||||
|
modes.pop();
|
||||||
|
if (value && modes.main === modes.NORMAL)
|
||||||
|
modes.push(modes.CARET);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// vim: set fdm=marker sw=4 ts=4 et:
|
// vim: set fdm=marker sw=4 ts=4 et:
|
||||||
|
|||||||
@@ -646,13 +646,15 @@ const Options = Module("options", {
|
|||||||
|
|
||||||
observe: function (subject, topic, data) {
|
observe: function (subject, topic, data) {
|
||||||
if (topic == "nsPref:changed") {
|
if (topic == "nsPref:changed") {
|
||||||
// subject is the nsIPrefBranch we're observing (after appropriate QI)
|
let observers = this._observers[data];
|
||||||
// data is the name of the pref that's been changed (relative to subject)
|
if (observers) {
|
||||||
switch (data) {
|
let value = options.getPref(data, false);
|
||||||
case "accessibility.browsewithcaret":
|
this._observers[data] = observers.filter(function (callback) {
|
||||||
let value = options.getPref("accessibility.browsewithcaret", false);
|
if (!callback.get())
|
||||||
dactyl.mode = value ? modes.CARET : modes.NORMAL;
|
return false;
|
||||||
break;
|
dactyl.trapErrors(callback.get(), null, value);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -798,6 +800,20 @@ const Options = Module("options", {
|
|||||||
template.options(config.host + " Options", prefs()));
|
template.options(config.host + " Options", prefs()));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_observers: Class.memoize(function () ({})),
|
||||||
|
/**
|
||||||
|
* Adds a new preference observer for the given preference.
|
||||||
|
*
|
||||||
|
* @param {string} pref The preference to observe.
|
||||||
|
* @param {function(object)} callback The callback, called with the
|
||||||
|
* new value of the preference whenever it changes.
|
||||||
|
*/
|
||||||
|
observePref: function (pref, callback, weak) {
|
||||||
|
if (!this._observers[pref])
|
||||||
|
this._observers[pref] = [];
|
||||||
|
this._observers[pref].push(weak ? Cu.getWeakReference(callback) : { get: function () callback });
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a :set command's argument string.
|
* Parses a :set command's argument string.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ const Util = Module("Util", {
|
|||||||
if (observers[target])
|
if (observers[target])
|
||||||
observers[target].call(obj, subject, data);
|
observers[target].call(obj, subject, data);
|
||||||
});
|
});
|
||||||
|
obj.observe.unRegister = function () register("removeObserver");
|
||||||
register("addObserver");
|
register("addObserver");
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -248,7 +249,7 @@ const Util = Module("Util", {
|
|||||||
* @param {number} frames The number of frames to print.
|
* @param {number} frames The number of frames to print.
|
||||||
*/
|
*/
|
||||||
dumpStack: function dumpStack(msg, frames) {
|
dumpStack: function dumpStack(msg, frames) {
|
||||||
let stack = Error().stack.replace(/(?:.*\n){1}/, "");
|
let stack = Error().stack.replace(/(?:.*\n){2}/, "");
|
||||||
if (frames != null)
|
if (frames != null)
|
||||||
[stack] = stack.match(RegExp("(?:.*\n){0," + frames + "}"));
|
[stack] = stack.match(RegExp("(?:.*\n){0," + frames + "}"));
|
||||||
util.dump((msg || "Stack") + "\n" + stack + "\n");
|
util.dump((msg || "Stack") + "\n" + stack + "\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user