Skip to content

Commit

Permalink
Clicking on checkbox or radio button now changes the value and
Browse files Browse the repository at this point in the history
propagated the click event.  If `preventDefault`, the value is
changed back.
  • Loading branch information
assaf committed Jan 19, 2012
1 parent 3eec41f commit 446d57e
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 20 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,9 @@ zombie.js-changelog(7) -- Changelog
`Browser.fire` takes no options (that was an undocumented argument), and always fires events that bubble and can be
cancelled.

Clicking on checkbox or radio button now changes the value and propagated the click event. If `preventDefault`, the
value is changed back.


## Version 0.12.12 2012-01-16

Expand Down
25 changes: 11 additions & 14 deletions lib/zombie/browser.coffee
Expand Up @@ -231,10 +231,10 @@ class Browser extends EventEmitter
type = if name in MOUSE_EVENT_NAMES then "MouseEvents" else "HTMLEvents"
event = @window.document.createEvent(type)
event.initEvent name, true, true

@dispatchEvent target, event
if callback
@wait callback
@wait (error, browser)->
callback error, browser, event
else
return this

Expand Down Expand Up @@ -266,6 +266,8 @@ class Browser extends EventEmitter
context.querySelector(selector)
else
return context
$$: (selector, context)->
return @query(selector, context)

# ### browser.querySelector(selector) => Element
#
Expand Down Expand Up @@ -514,9 +516,10 @@ class Browser extends EventEmitter
if field.getAttribute("readonly")
throw new Error("This INPUT field is readonly")
if field.checked ^ value
@fire "click", field, callback
else if callback
callback null, false
field.click()

if callback
@wait callback
else
return this
else
Expand Down Expand Up @@ -552,16 +555,10 @@ class Browser extends EventEmitter
choose: (selector, callback)->
field = @field(selector) || @field("input[type=radio][value=\"#{escape(selector)}\"]")
if field && field.tagName == "INPUT" && field.type == "radio" && field.form
if !field.checked
radios = @querySelectorAll(":radio[name='#{field.getAttribute("name")}']", field.form)
for radio in radios
radio.checked = false unless radio.getAttribute("disabled") || radio.getAttribute("readonly")
field.checked = true
@fire "click", field
@fire "change", field, callback
field.click()
if callback
@wait callback
else
@fire "click", field, callback
unless callback
return this
else
throw new Error("No radio INPUT matching '#{selector}'")
Expand Down
49 changes: 43 additions & 6 deletions lib/zombie/forms.coffee
Expand Up @@ -109,9 +109,7 @@ HTML.HTMLInputElement.prototype._eventDefaults =
if form = input.form
form._dispatchSubmitEvent input
when "checkbox"
unless input.getAttribute("readonly")
input.checked = !input.checked
change()
change()
when "radio"
unless input.getAttribute("readonly")
input.checked = true
Expand All @@ -121,9 +119,48 @@ 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 = ->
event = @ownerDocument.createEvent("HTMLEvents")
event.initEvent "click", true, true
@ownerDocument.parentWindow.browser.dispatchEvent this, event
# First event we fire is click event
click = =>
event = @ownerDocument.createEvent("HTMLEvents")
event.initEvent "click", true, true
@ownerDocument.parentWindow.browser.dispatchEvent this, event
return !event._preventDefault

# If that works out, we follow with a change event
change = =>
event = @ownerDocument.createEvent("HTMLEvents")
event.initEvent "change", true, true
@ownerDocument.parentWindow.browser.dispatchEvent this, event

switch @type
when "checkbox"
unless @getAttribute("readonly")
original = @checked
@checked = !@checked
if click()
change()
else
@checked = original
when "radio"
unless @getAttribute("readonly")
if !@checked
radios = @ownerDocument.querySelectorAll(":radio[name='#{@getAttribute("name")}']", @form)
checked = null
for radio in radios
if radio.checked
checked = radio
radio.checked = false
@checked = true
if click()
change()
else
for radio in radios
radio.checked = radio == checked
else
click()
else
click()
return

# Default behavior for form BUTTON: submit form.
HTML.HTMLButtonElement.prototype._eventDefaults =
Expand Down
29 changes: 29 additions & 0 deletions spec/forms_spec.coffee
Expand Up @@ -85,6 +85,9 @@ Vows.describe("Forms").addBatch(
<input type="image" name="image" id="image_submit" value="Image Submit">
<button name="button" value="hit-me">Hit Me</button>
<input type="checkbox" id="field-prevent-check">
<input type="radio" id="field-prevent-radio">
</form>
</body>
</html>
Expand Down Expand Up @@ -242,6 +245,19 @@ Vows.describe("Forms").addBatch(
"should callback": (_, browser)->
assert.ok !browser.querySelector("#field-check").checked

"prevent default":
topic: (browser)->
check_box = browser.$$("#field-prevent-check")
values = [check_box.checked]
check_box.addEventListener "click", (event)=>
values.push check_box.checked
event.preventDefault()
browser.check check_box, =>
values.push check_box.checked
@callback null, values
"should turn checkbox on then off": (values)->
assert.deepEqual values, [false, true, false]


"radio buttons":
Browser.wants "http://localhost:3003/forms/form"
Expand Down Expand Up @@ -279,6 +295,19 @@ Vows.describe("Forms").addBatch(
"should uncheck other radio": (browser)->
assert.ok !browser.querySelector("#field-scary").checked

"prevent default":
topic: (browser)->
radio = browser.$$("#field-prevent-radio")
values = [radio.checked]
radio.addEventListener "click", (event)=>
values.push radio.checked
event.preventDefault()
browser.choose radio, =>
values.push radio.checked
@callback null, values
"should turn radio on then off": (values)->
assert.deepEqual values, [false, true, false]


"select option":
Browser.wants "http://localhost:3003/forms/form"
Expand Down

0 comments on commit 446d57e

Please sign in to comment.