diff options
| author | Jez Ng | 2012-01-18 01:47:21 +0800 |
|---|---|---|
| committer | Jez Ng | 2012-01-25 23:55:19 -0500 |
| commit | c9db525f07b4ac1ff1293e39d2944e01ebf3651e (patch) | |
| tree | cac2cdde455a74a35b01f761a94d3c215dc71975 | |
| parent | 5c99231271c021a1f8d2cccea2e9408ef6aaf1e3 (diff) | |
| download | vimium-c9db525f07b4ac1ff1293e39d2944e01ebf3651e.tar.bz2 | |
Do not enter insert mode automatically when searching.
Form input elements only trigger insert mode when the user hits <esc> or
<cr>.
Closes #183.
| -rw-r--r-- | vimiumFrontend.js | 90 |
1 files changed, 76 insertions, 14 deletions
diff --git a/vimiumFrontend.js b/vimiumFrontend.js index a55ac959..d0daa448 100644 --- a/vimiumFrontend.js +++ b/vimiumFrontend.js @@ -10,6 +10,7 @@ var insertModeLock = null; var findMode = false; var findModeQuery = { rawQuery: "" }; var findModeQueryHasResults = false; +var findModeAnchorNode = null; var isShowingHelpDialog = false; var handlerStack = []; var keyPort; @@ -234,7 +235,7 @@ function registerFrameIfSizeAvailable (is_top) { * Enters insert mode if the currently focused element in the DOM is focusable. */ function enterInsertModeIfElementIsFocused() { - if (document.activeElement && isEditable(document.activeElement)) + if (document.activeElement && isEditable(document.activeElement) && !findMode) enterInsertModeWithoutShowingIndicator(document.activeElement); } @@ -396,8 +397,7 @@ function onKeypress(event) { if (keyChar) { if (findMode) { handleKeyCharForFindMode(keyChar); - event.preventDefault(); - event.stopPropagation(); + suppressEvent(event); } else if (!isInsertMode() && !findMode) { if (currentCompletionKeys.indexOf(keyChar) != -1) { event.preventDefault(); @@ -427,6 +427,11 @@ function bubbleEvent(type, event) { return true; } +function suppressEvent(event) { + event.preventDefault(); + event.stopPropagation(); +} + function onKeydown(event) { if (!bubbleEvent('keydown', event)) return; @@ -476,17 +481,16 @@ function onKeydown(event) { } else if (findMode) { if (isEscape(event)) { - exitFindMode(); - event.stopPropagation(); + handleEscapeForFindMode(); + suppressEvent(event); } else if (event.keyCode == keyCodes.backspace || event.keyCode == keyCodes.deleteKey) { handleDeleteForFindMode(); - event.preventDefault(); - event.stopPropagation(); + suppressEvent(event); } else if (event.keyCode == keyCodes.enter) { handleEnterForFindMode(); - event.stopPropagation(); + suppressEvent(event); } else if (!modifiers) { event.stopPropagation(); @@ -558,7 +562,7 @@ function refreshCompletionKeys(response) { } function onFocusCapturePhase(event) { - if (isFocusable(event.target)) + if (isFocusable(event.target) && !findMode) enterInsertModeWithoutShowingIndicator(event.target); } @@ -671,6 +675,11 @@ function handleKeyCharForFindMode(keyChar) { showFindModeHUDForQuery(); } +function handleEscapeForFindMode() { + exitFindMode(); + focusFoundLink() || selectFoundInputElement(); +} + function handleDeleteForFindMode() { if (findModeQuery.rawQuery.length == 0) { exitFindMode(); @@ -684,10 +693,13 @@ function handleDeleteForFindMode() { } } +// <esc> sends us into insert mode if possible, but <cr> does not. +// <esc> corresponds approximately to 'nevermind, I have found it already' while <cr> means 'I want to save +// this query and do more searches with it' function handleEnterForFindMode() { exitFindMode(); + focusFoundLink(); settings.set("findModeRawQuery", findModeQuery.rawQuery); - performFindInPlace(); } function performFindInPlace() { @@ -718,8 +730,17 @@ function performFindInPlace() { // :options is an optional dict. valid parameters are 'caseSensitive' and 'backwards'. function executeFind(query, options) { + // rather hacky, but this is our way of signalling to the insertMode listener not to react to the focus + // changes that find() induces. + var oldFindMode = findMode; + findMode = true; options = options || {}; - return window.find(query, options.caseSensitive, options.backwards, true, false, true, false); + var rv = window.find(query, options.caseSensitive, options.backwards, true, false, true, false); + findMode = oldFindMode; + // we need to save the anchor node here because <esc> seems to nullify it, regardless of whether we do + // preventDefault() + findModeAnchorNode = document.getSelection().anchorNode; + return rv; } function focusFoundLink() { @@ -730,6 +751,29 @@ function focusFoundLink() { } } +function isDOMDescendant(parent, child) { + var node = child; + while (node !== null) { + if (node === parent) + return true; + node = node.parentNode; + } + return false; +} + +function selectFoundInputElement() { + // if the found text is in an input element, getSelection().anchorNode will be null, so we use activeElement + // instead. however, since the last focused element might not be the one currently pointed to by find (e.g. + // the current one might be disabled and therefore unable to receive focus), we use the approximate + // heuristic of checking that the last anchor node is an ancestor of our element. + if (findModeQueryHasResults && linkHints.isSelectable(document.activeElement) && + isDOMDescendant(findModeAnchorNode, document.activeElement)) { + linkHints.simulateSelect(document.activeElement); + // the element has already received focus via find(), so invoke insert mode manually + enterInsertModeWithoutShowingIndicator(document.activeElement); + } +} + function findAndFocus(backwards) { // check if the query has been changed by a script in another frame var mostRecentQuery = settings.get("findModeRawQuery"); @@ -757,7 +801,26 @@ function findAndFocus(backwards) { else var query = findModeQuery.parsedQuery; - executeFind(query, { backwards: backwards, caseSensitive: !findModeQuery.ignoreCase }); + findModeQueryHasResults = executeFind(query, { backwards: backwards, caseSensitive: !findModeQuery.ignoreCase }); + + // if we have found an input element via 'n', pressing <esc> immediately afterwards sends us into insert + // mode + var elementCanTakeInput = findModeQueryHasResults && domUtils.isSelectable(document.activeElement) && + isDOMDescendant(findModeAnchorNode, document.activeElement); + if (elementCanTakeInput) { + handlerStack.push({ + keydown: function(event) { + handlerStack.pop(); + if (isEscape(event)) { + linkHints.simulateSelect(document.activeElement); + enterInsertModeWithoutShowingIndicator(document.activeElement); + return false; // we have 'consumed' this event, so do not propagate + } + return true; + } + }); + } + focusFoundLink(); } @@ -767,7 +830,7 @@ function performBackwardsFind() { findAndFocus(true); } function getLinkFromSelection() { var node = window.getSelection().anchorNode; - while (node.nodeName.toLowerCase() !== 'body') { + while (node && node.nodeName.toLowerCase() !== 'body') { if (node.nodeName.toLowerCase() === 'a') return node; node = node.parentNode; } @@ -836,7 +899,6 @@ function enterFindMode() { function exitFindMode() { findMode = false; - focusFoundLink(); HUD.hide(); } |
