forked from assaf/zombie
/
forms.coffee
133 lines (118 loc) · 4.61 KB
/
forms.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# Patches to JSDOM for properly handling forms.
core = require("jsdom").dom.level3.core
path = require("path")
fs = require("fs")
mime = require("mime")
base64 = require("base64")
# The Form
# --------
UploadedFile = (filename)->
file = new String(path.basename(filename))
file.mime = ()-> mime.lookup(filename)
file.encoding = ()->
if @mime().match(/^text/)
null
else
"base64"
file.contents = ()->
result = fs.readFileSync(filename)
result = base64.encode(result).replace(/(.{76})/g, "$1\r\n") if @encoding() == "base64"
result
return file
# Implement form.submit such that it actually submits a request to the server.
# This method takes the submitting button so we can send the button name/value.
core.HTMLFormElement.prototype.submit = (button)->
document = @ownerDocument
params = {}
process = (index)=>
if field = @elements.item(index)
if !field.getAttribute("disabled") && name = field.getAttribute("name")
if field.nodeName == "SELECT"
selected = []
for option in field.options
selected.push(option.value) if option.selected
if field.multiple
value = selected
else
value = selected.shift()
if !value && option = field.options[0]
value = option.value
params[name] = value if value
else if field.nodeName == "INPUT" && (field.type == "checkbox" || field.type == "radio")
params[name] = field.value if field.checked
else if field.nodeName == "INPUT" && field.type == "file"
params[name] = new UploadedFile(field.value) if field.value
else if field.nodeName == "TEXTAREA" || field.nodeName == "INPUT"
if field.value && field.type != "submit" && field.type != "image"
params[name] = field.value
process index + 1
else
params[button.name] = button.value if button && button.name
history = document.parentWindow.history
history._submit @getAttribute("action"), @getAttribute("method"), params, @getAttribute("enctype")
process 0
# Implement form.reset to reset all form fields.
core.HTMLFormElement.prototype.reset = ->
for field in @elements
if field.nodeName == "SELECT"
for option in field.options
option.selected = option._defaultSelected
else if field.nodeName == "INPUT" && field.type == "check" || field.type == "radio"
field.checked = field._defaultChecked
else if field.nodeName == "INPUT" || field.nodeName == "TEXTAREA"
field.value = field._defaultValue
# Replace dispatchEvent so we can send the button along the event.
core.HTMLFormElement.prototype._dispatchSubmitEvent = (button)->
event = @ownerDocument.createEvent("HTMLEvents")
event.initEvent "submit", true, true
event._button = button
@dispatchEvent event
# Default behavior for submit events is to call the form's submit method, but we
# also pass the submitting button.
core.HTMLFormElement.prototype._eventDefaults["submit"] = (event)->
event.target.submit event._button
# Buttons
# -------
# Default behavior for clicking on inputs.
core.HTMLInputElement.prototype._eventDefaults =
click: (event)->
input = event.target
change = ->
event = input.ownerDocument.createEvent("HTMLEvents")
event.initEvent "change", true, true
input.ownerDocument.dispatchEvent event
switch input.type
when "reset"
if form = input.form
form.reset()
when "submit", "image"
if form = input.form
form._dispatchSubmitEvent input
when "checkbox"
unless input.getAttribute("readonly")
input.checked = !input.checked
change()
when "radio"
unless input.getAttribute("readonly")
input.checked = true
change()
# Current INPUT behavior on click is to capture sumbit and handle it, but
# ignore all other clicks. We need those other clicks to occur, so we're going
# to dispatch them all.
core.HTMLInputElement.prototype.click = ->
event = @ownerDocument.createEvent("HTMLEvents")
event.initEvent "click", true, true
@dispatchEvent event
# Default behavior for form BUTTON: submit form.
core.HTMLButtonElement.prototype._eventDefaults =
click: (event)->
button = event.target
return if button.getAttribute("disabled")
if form = button.form
form._dispatchSubmitEvent button
# Default type for button is submit. jQuery live submit handler looks
# for the type attribute, so we've got to make sure it's there.
core.Document.prototype._elementBuilders["button"] = (doc, s)->
button = new core.HTMLButtonElement(doc, s)
button.type ||= "submit"
return button