aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Blott2015-02-14 12:23:28 +0000
committerStephen Blott2015-02-14 12:23:28 +0000
commit39545307beea82cae85030ecea936a248a6d1544 (patch)
tree13690e6ea9123a25a17ccc8104dc1721bb813b55
parent9bd6b7814fbee5508a4a746789d10c687a2c0c9b (diff)
parent05f229201a05101ab4947bd436ec02d8864392f9 (diff)
downloadvimium-39545307beea82cae85030ecea936a248a6d1544.tar.bz2
Merge branch 'grab-back-focus'
-rw-r--r--background_scripts/settings.coffee1
-rw-r--r--content_scripts/vimium_frontend.coffee32
-rw-r--r--pages/options.coffee1
-rw-r--r--pages/options.html14
-rw-r--r--tests/dom_tests/chrome.coffee21
-rw-r--r--tests/dom_tests/dom_tests.coffee22
6 files changed, 68 insertions, 23 deletions
diff --git a/background_scripts/settings.coffee b/background_scripts/settings.coffee
index f43bd4bc..3528e8a9 100644
--- a/background_scripts/settings.coffee
+++ b/background_scripts/settings.coffee
@@ -113,6 +113,7 @@ root.Settings = Settings =
# put in an example search engine
searchEngines: "w: http://www.wikipedia.org/w/index.php?title=Special:Search&search=%s wikipedia"
newTabUrl: "chrome://newtab"
+ grabBackFocus: false
settingsVersion: Utils.getCurrentVersion()
diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee
index 315e64cd..5bad1148 100644
--- a/content_scripts/vimium_frontend.coffee
+++ b/content_scripts/vimium_frontend.coffee
@@ -44,7 +44,7 @@ settings =
loadedValues: 0
valuesToLoad: [ "scrollStepSize", "linkHintCharacters", "linkHintNumbers", "filterLinkHints", "hideHud",
"previousPatterns", "nextPatterns", "regexFindMode", "userDefinedLinkHintCss",
- "helpDialog_showAdvancedCommands", "smoothScroll" ]
+ "helpDialog_showAdvancedCommands", "smoothScroll", "grabBackFocus" ]
isLoaded: false
eventListeners: {}
@@ -96,6 +96,33 @@ settings =
#
frameId = Math.floor(Math.random()*999999999)
+# If an input grabs the focus before the user has interacted with the page, then grab it back (if the
+# grabBackFocus option is set).
+class GrabBackFocus extends Mode
+ constructor: ->
+ super
+ name: "grab-back-focus"
+ keydown: => @alwaysContinueBubbling => @exit()
+
+ @push
+ _name: "grab-back-focus-mousedown"
+ mousedown: => @alwaysContinueBubbling => @exit()
+
+ activate = =>
+ return @exit() unless settings.get "grabBackFocus"
+ @push
+ _name: "grab-back-focus-focus"
+ focus: (event) => @grabBackFocus event.target
+ # An input may already be focused. If so, grab back the focus.
+ @grabBackFocus document.activeElement if document.activeElement
+
+ if settings.isLoaded then activate() else settings.addEventListener "load", activate
+
+ grabBackFocus: (element) ->
+ return @continueBubbling unless DomUtils.isEditable element
+ element.blur()
+ @suppressEvent
+
# Only exported for tests.
window.initializeModes = ->
class NormalMode extends Mode
@@ -114,6 +141,7 @@ window.initializeModes = ->
new NormalMode
new PassKeysMode
new InsertMode permanent: true
+ new GrabBackFocus
#
# Complete initialization work that sould be done prior to DOMReady.
@@ -179,7 +207,7 @@ window.initializeWhenEnabled = ->
unless installedListeners
# Key event handlers fire on window before they do on document. Prefer window for key events so the page
# can't set handlers to grab the keys before us.
- for type in ["keydown", "keypress", "keyup", "click", "focus", "blur"]
+ for type in [ "keydown", "keypress", "keyup", "click", "focus", "blur", "mousedown" ]
do (type) -> installListener window, type, (event) -> handlerStack.bubbleEvent type, event
installListener document, "DOMActivate", (event) -> handlerStack.bubbleEvent 'DOMActivate', event
installedListeners = true
diff --git a/pages/options.coffee b/pages/options.coffee
index 93c9b503..d2950348 100644
--- a/pages/options.coffee
+++ b/pages/options.coffee
@@ -257,6 +257,7 @@ initOptionsPage = ->
regexFindMode: CheckBoxOption
scrollStepSize: NumberOption
smoothScroll: CheckBoxOption
+ grabBackFocus: CheckBoxOption
searchEngines: TextOption
searchUrl: NonEmptyTextOption
userDefinedLinkHintCss: TextOption
diff --git a/pages/options.html b/pages/options.html
index d37646c4..889d5ea0 100644
--- a/pages/options.html
+++ b/pages/options.html
@@ -133,6 +133,20 @@ b: http://b.com/?q=%s description
<td verticalAlign="top" class="booleanOption">
<div class="help">
<div class="example">
+ Prevent pages from focusing an input on load (e.g. Google, Bing, etc.).
+ </div>
+ </div>
+ <label>
+ <input id="grabBackFocus" type="checkbox"/>
+ Don't let pages steal the focus on load
+ </label>
+ </td>
+ </tr>
+ <tr>
+ <td class="caption"></td>
+ <td verticalAlign="top" class="booleanOption">
+ <div class="help">
+ <div class="example">
When enabled, the HUD will not be displayed.
</div>
</div>
diff --git a/tests/dom_tests/chrome.coffee b/tests/dom_tests/chrome.coffee
index 2e7c6a5a..d6c03fc1 100644
--- a/tests/dom_tests/chrome.coffee
+++ b/tests/dom_tests/chrome.coffee
@@ -7,26 +7,23 @@ root.chromeMessages = []
document.hasFocus = -> true
-root.chrome = {
- runtime: {
- connect: -> {
- onMessage: {
+root.chrome =
+ runtime:
+ connect: ->
+ onMessage:
addListener: ->
- }
- onDisconnect: {
+ onDisconnect:
addListener: ->
- }
postMessage: ->
- }
- onMessage: {
+ onMessage:
addListener: ->
- }
sendMessage: (message) -> chromeMessages.unshift message
getManifest: ->
getURL: (url) -> "../../#{url}"
- }
storage:
local:
get: ->
set: ->
-}
+ sync:
+ get: ->
+ set: ->
diff --git a/tests/dom_tests/dom_tests.coffee b/tests/dom_tests/dom_tests.coffee
index 11fbe11f..a1ca8723 100644
--- a/tests/dom_tests/dom_tests.coffee
+++ b/tests/dom_tests/dom_tests.coffee
@@ -354,24 +354,24 @@ context "Triggering insert mode",
document.getElementById("test-div").innerHTML = ""
should "trigger insert mode on focus of text input", ->
- assert.isTrue Mode.top().name == "insert" and not Mode.top().isActive()
+ assert.isFalse InsertMode.permanentInstance.isActive()
document.getElementById("first").focus()
- assert.isTrue Mode.top().name == "insert" and Mode.top().isActive()
+ assert.isTrue InsertMode.permanentInstance.isActive()
should "trigger insert mode on focus of password input", ->
- assert.isTrue Mode.top().name == "insert" and not Mode.top().isActive()
+ assert.isFalse InsertMode.permanentInstance.isActive()
document.getElementById("third").focus()
- assert.isTrue Mode.top().name == "insert" and Mode.top().isActive()
+ assert.isTrue InsertMode.permanentInstance.isActive()
should "trigger insert mode on focus of contentEditable elements", ->
- assert.isTrue Mode.top().name == "insert" and not Mode.top().isActive()
+ assert.isFalse InsertMode.permanentInstance.isActive()
document.getElementById("fourth").focus()
- assert.isTrue Mode.top().name == "insert" and Mode.top().isActive()
+ assert.isTrue InsertMode.permanentInstance.isActive()
should "not trigger insert mode on other elements", ->
- assert.isTrue Mode.top().name == "insert" and not Mode.top().isActive()
+ assert.isFalse InsertMode.permanentInstance.isActive()
document.getElementById("fifth").focus()
- assert.isTrue Mode.top().name == "insert" and not Mode.top().isActive()
+ assert.isFalse InsertMode.permanentInstance.isActive()
context "Mode utilities",
setup ->
@@ -454,6 +454,10 @@ context "PostFindMode",
testContent = "<input type='text' id='first'/>"
document.getElementById("test-div").innerHTML = testContent
document.getElementById("first").focus()
+ # For these tests, we need to push GrabBackFocus out of the way. When it exits, it updates the badge,
+ # which interferes with event suppression within insert mode. This cannot happen in normal operation,
+ # because GrabBackFocus exits on the first keydown.
+ Mode.top().exit()
@postFindMode = new PostFindMode
tearDown ->
@@ -466,7 +470,7 @@ context "PostFindMode",
should "suppress unmapped printable keys", ->
sendKeyboardEvent "m"
- assert.equal pageKeyboardEventCount, 0
+ assert.equal 0, pageKeyboardEventCount
should "be deactivated on click events", ->
handlerStack.bubbleEvent "click", target: document.activeElement