Permalink
Browse files

Browser should set focus to element with autofocus

  • Loading branch information...
1 parent 5609042 commit c8273075e2e61e4e0920b4d571509e34b35dc089 @assaf committed Oct 5, 2012
View
@@ -26,8 +26,11 @@ issue.
the last top-most page load. All other resources available from
`browser.resources`. These replace `lastRequest` and `lastResponse`.
- 559 tests
- 10.4 sec to complete
+Added `browser.activeElement` (removed `browser.focus`) and support for
+`autofocus` attribute.
+
+ 566 tests
+ 11.0 sec to complete
## Version 1.4.1 2012-08-22
@@ -405,6 +405,10 @@ class Browser extends EventEmitter
@prototype.__defineGetter__ "body", ->
return @document.querySelector("body")
+ # Element that has the current focus.
+ @prototype.__defineGetter__ "activeElement", ->
+ return @document.activeElement
+
# ### browser.statusCode => Number
#
# Returns the status code of the request for loading the window.
@@ -857,12 +861,6 @@ class Browser extends EventEmitter
button.focus()
return @fire("click", button, callback)
- # ### browser.focused => element
- #
- # Returns the element in focus.
- focused: ->
- return @document._focused
-
# Cookies and storage
# -------------------
@@ -0,0 +1,95 @@
+# Create an empty document. Each window gets a new document.
+
+JSDOM = require("jsdom")
+Scripts = require("./scripts")
+
+HTML = JSDOM.dom.level3.html
+
+
+# Creates an returns a new document attached to the window.
+#
+# browser - The browser
+# window - The window
+createDocument = (browser, window)->
+ # Create new DOM Level 3 document, add features (load external resources,
+ # etc) and associate it with current document. From this point on the browser
+ # sees a new document, client register event handler for
+ # DOMContentLoaded/error.
+ jsdomOpts =
+ deferClose: true
+ features:
+ MutationEvents: "2.0"
+ ProcessExternalResources: []
+ FetchExternalResources: ["iframe"]
+ parser: browser.htmlParser
+
+ if browser.runScripts
+ jsdomOpts.features.ProcessExternalResources.push("script")
+ jsdomOpts.features.FetchExternalResources.push("script")
+ if browser.loadCSS
+ jsdomOpts.features.FetchExternalResources.push("css")
+
+ document = JSDOM.jsdom(null, HTML, jsdomOpts)
+
+ # Add support for running in-line scripts
+ if browser.runScripts
+ Scripts.addInlineScriptSupport(document)
+
+
+ # Tie document and window together
+ Object.defineProperty document, "window",
+ value: window
+ Object.defineProperty document, "parentWindow",
+ value: window.parent # JSDOM property?
+
+ Object.defineProperty document, "location",
+ get: ->
+ return window.location
+ set: (url)->
+ window.location = url
+ Object.defineProperty document, "URL",
+ get: ->
+ return window.location.href
+
+ return document
+
+
+# The element in focus.
+HTML.HTMLDocument.prototype.__defineGetter__ "activeElement", ->
+ @_inFocus || @body
+
+# Change the current element in focus (or null for blur)
+setFocus = (document, element)->
+ unless element == document._inFocus
+ if document._inFocus
+ onblur = document.createEvent("HTMLEvents")
+ onblur.initEvent "blur", false, false
+ document.window._dispatchEvent(document._inFocus, onblur)
+ if element
+ onfocus = document.createEvent("HTMLEvents")
+ onfocus.initEvent("focus", false, false)
+ document.window._dispatchEvent(element, onfocus)
+ document._inFocus = element
+
+# Focus/blur exist on all elements but do nothing if not an input
+HTML.Element.prototype.focus = ->
+HTML.Element.prototype.blur = ->
+
+for element in [HTML.HTMLInputElement, HTML.HTMLSelectElement, HTML.HTMLTextAreaElement, HTML.HTMLButtonElement, HTML.HTMLAnchorElement]
+ element.prototype.focus = ->
+ setFocus(@ownerDocument, this)
+ element.prototype.blur = ->
+ if @ownerDocument.activeElement == this
+ setFocus(@ownerDocument, null)
+
+
+# Capture the autofocus element and use it to change focus
+setAttribute = HTML.HTMLElement.prototype.setAttribute
+HTML.HTMLElement.prototype.setAttribute = (name, value)->
+ setAttribute.call(this, name, value)
+ if name == "autofocus" && ~["INPUT", "SELECT", "TEXTAREA", "BUTTON", "ANCHOR"].indexOf(@tagName)
+ @ownerDocument._inFocus = this
+
+
+module.exports = createDocument
+
@@ -130,7 +130,7 @@ HTML.HTMLInputElement.prototype._eventDefaults =
# ignore all other clicks. We need those other clicks to occur, so we're going
# to dispatch them all.
HTML.HTMLInputElement.prototype.click = ->
- focus(@ownerDocument, this)
+ @focus()
# First event we fire is click event
click = =>
@@ -196,27 +196,3 @@ HTML.Document.prototype._elementBuilders["button"] = (doc, s)->
button.type ||= "submit"
return button
-
-# The element in focus.
-HTML.HTMLDocument.prototype.__defineGetter__ "activeElement", ->
- @parentWindow.document._focused
-
-# Change the current element in focus
-focus = (document, element)->
- unless element == document._focused
- if document._focused
- onblur = document.createEvent("HTMLEvents")
- onblur.initEvent "blur", false, false
- document.window._dispatchEvent(document._focused, onblur)
- if element
- onfocus = document.createEvent("HTMLEvents")
- onfocus.initEvent("focus", false, false)
- document.window._dispatchEvent(element, onfocus)
- document._focused = element
-
-for element in [HTML.HTMLInputElement, HTML.HTMLSelectElement, HTML.HTMLTextAreaElement, HTML.HTMLButtonElement, HTML.HTMLAnchorElement]
- element.prototype.focus = ->
- focus @ownerDocument, this
- element.prototype.blur = ->
- focus @ownerDocument, null
-
@@ -3,13 +3,14 @@
# Also responsible for creating associated document and loading it.
-Console = require("./console")
-EventSource = require("eventsource")
-History = require("./history")
-JSDOM = require("jsdom")
-WebSocket = require("ws")
-Scripts = require("./scripts")
-URL = require("url")
+Console = require("./console")
+EventSource = require("eventsource")
+History = require("./history")
+JSDOM = require("jsdom")
+WebSocket = require("ws")
+URL = require("url")
+createDocument = require("./document")
+
Events = JSDOM.dom.level3.events
HTML = JSDOM.dom.level3.html
@@ -289,51 +290,6 @@ createWindow = ({ browser, data, encoding, history, method, name, opener, parent
return window
-# Create an empty document. Each window gets a new document.
-createDocument = (browser, window)->
- # Create new DOM Level 3 document, add features (load external resources,
- # etc) and associate it with current document. From this point on the browser
- # sees a new document, client register event handler for
- # DOMContentLoaded/error.
- jsdom_opts =
- deferClose: true
- features:
- MutationEvents: "2.0"
- ProcessExternalResources: []
- FetchExternalResources: ["iframe"]
- parser: browser.htmlParser
-
- if browser.runScripts
- jsdom_opts.features.ProcessExternalResources.push("script")
- jsdom_opts.features.FetchExternalResources.push("script")
- if browser.loadCSS
- jsdom_opts.features.FetchExternalResources.push("css")
-
- document = JSDOM.jsdom(null, HTML, jsdom_opts)
-
- # Add support for running in-line scripts
- if browser.runScripts
- Scripts.addInlineScriptSupport(document)
-
-
- # Tie document and window together
- Object.defineProperty document, "window",
- value: window
- Object.defineProperty document, "parentWindow",
- value: window.parent # JSDOM property?
-
- Object.defineProperty document, "location",
- get: ->
- return window.location
- set: (url)->
- window.location = url
- Object.defineProperty document, "URL",
- get: ->
- return window.location.href
-
- return document
-
-
# Load document. Also used to submit form.
loadDocument = ({ document, history, url, method, encoding, data })->
window = document.window
@@ -2,12 +2,12 @@
describe.skip "angularjs", ->
before (done)->
- brains.get "/templates/show.html", (req, res)->
+ brains.get "/angular/show.html", (req, res)->
res.send """
<h1>{{title}}</h1>
"""
- brains.get "/templates/list.html", (req, res)->
+ brains.get "/angular/list.html", (req, res)->
res.send """
<ul>
<li ng-repeat="item in items">
@@ -16,21 +16,21 @@ describe.skip "angularjs", ->
</ul>
"""
- brains.get "/app", (req, res)->
+ brains.get "/angular", (req, res)->
res.send """
<html ng-app="test">
<head>
<title>Angular</title>
- <script src="/scripts/angular-1.0.1.js"></script>
+ <script src="/scripts/angular-1.0.2.js"></script>
</head>
<body>
<div ng-view></div>
<script>
angular.module('test', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
- when('/show', {templateUrl: '/templates/show.html', controller: ShowCtrl}).
- when('/list', {templateUrl: '/templates/list.html', controller: ListCtrl}).
+ when('/show', {templateUrl: '/angular/show.html', controller: ShowCtrl}).
+ when('/list', {templateUrl: '/angular/list.html', controller: ListCtrl}).
otherwise({redirectTo: '/list'});
}]);
function ListCtrl($scope) {
@@ -50,8 +50,10 @@ describe.skip "angularjs", ->
before (done)->
@browser = new Browser()
- @browser.visit("http://localhost:3003/app").then =>
- @browser.clickLink "my link", done
+ @browser.visit("http://localhost:3003/angular")
+ @browser.wait 3000, =>
+ @browser.clickLink "my link"
+ @browser.wait 1000, done
it "should follow the link to the detail", ->
assert.equal @browser.text("h1"), "my title"
@@ -0,0 +1,89 @@
+{ assert, brains, Browser } = require("./helpers")
+
+describe "Document", ->
+
+ describe "activeElement", ->
+ before (done)->
+ brains.get "/document/activeElement", (req, res)->
+ res.send """
+ <html>
+ </html>
+ """
+ brains.ready done
+
+ before (done)->
+ @browser = new Browser()
+ @browser.visit("/document/activeElement", done)
+
+ it "should be document body", ->
+ assert.equal @browser.activeElement, @browser.document.body
+
+ describe "autofocus on div", ->
+ before (done)->
+ div = @browser.document.createElement("div")
+ div.setAttribute("autofocus")
+ @browser.document.body.appendChild(div)
+ @browser.wait(done)
+
+ it "should not change active element", ->
+ assert.equal @browser.activeElement, @browser.document.body
+
+ describe "autofocus on input", ->
+ before (done)->
+ @input = @browser.document.createElement("input")
+ @input.setAttribute("autofocus")
+ @browser.document.body.appendChild(@input)
+ @browser.wait(done)
+
+ it "should change active element", ->
+ assert.equal @browser.activeElement, @input
+
+ describe "autofocus on textarea", ->
+ before (done)->
+ @textarea = @browser.document.createElement("textarea")
+ @textarea.setAttribute("autofocus")
+ @browser.document.body.appendChild(@input)
+ @browser.wait(done)
+
+ it "should change active element", ->
+ assert.equal @browser.activeElement, @textarea
+
+ describe "focus on div", ->
+ before (done)->
+ @browser.reload(done)
+ before (done)->
+ div = @browser.document.createElement("div")
+ @browser.document.body.appendChild(div)
+ div.focus()
+ @browser.wait(done)
+
+ it "should change active element", ->
+ assert.equal @browser.activeElement, @browser.document.body
+
+ describe "focus on input", ->
+ before (done)->
+ @browser.reload(done)
+ before (done)->
+ @input = @browser.document.createElement("input")
+ @browser.document.body.appendChild(@input)
+ @input.focus()
+ @browser.wait(done)
+
+ it "should change active element", ->
+ assert.equal @browser.activeElement, @input
+
+ describe "focus on textarea", ->
+ before (done)->
+ @browser.reload(done)
+ before (done)->
+ @textarea = @browser.document.createElement("input")
+ @browser.document.body.appendChild(@textarea)
+ @textarea.focus()
+ @browser.wait(done)
+
+ it "should change active element", ->
+ assert.equal @browser.activeElement, @textarea
+
+ after ->
+ @browser.destroy()
+
Oops, something went wrong.

0 comments on commit c827307

Please sign in to comment.