-
Notifications
You must be signed in to change notification settings - Fork 7
/
form.py
196 lines (164 loc) · 6.2 KB
/
form.py
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import urlparse
import htmlunit
from lazyproperty import lazyproperty
from ignore_urls import filterIgnoreUrlParts
from vectors import formvector
from form_field import FormField
from link import Link, AbstractLink, Links
from utils import all_same
class Form(Link):
SUBMITTABLES = [("input", "type", "submit"),
("input", "type", "image"),
("button", "type", "submit")]
GET, POST = ("GET", "POST")
@lazyproperty
def method(self):
methodattr = self.internal.getMethodAttribute().upper()
if not methodattr:
methodattr = "GET"
assert methodattr in ("GET", "POST")
return methodattr
@lazyproperty
def action(self):
action = self.internal.getActionAttribute()
action = filterIgnoreUrlParts(action)
return action
@lazyproperty
def actionurl(self):
return urlparse.urlparse(self.action)
@lazyproperty
def _str(self):
return "Form(%s %s)" % (self.method, self.action)
@lazyproperty
def linkvector(self):
return formvector(self.method, self.actionurl, self.elemnames, self.hiddennames)
@lazyproperty
def elemnames(self):
return [i.name for i in self.elems]
@lazyproperty
def elems(self):
return self.inputs + self.textareas + self.selects + self.submittables
def buildFormField(self, e):
tag = e.getTagName().upper()
if tag == FormField.Tag.INPUT:
etype = e.getAttribute('type').lower()
name = e.getAttribute('name').encode('ascii', 'ignore')
value = e.getAttribute('value').encode('ascii', 'ignore')
if etype == "hidden":
type = FormField.Type.HIDDEN
elif etype == "text":
type = FormField.Type.TEXT
elif etype == "password":
type = FormField.Type.PASSWORD
elif etype == "checkbox":
type = FormField.Type.CHECKBOX
elif etype == "submit":
type = FormField.Type.SUBMIT
elif etype == "image":
type = FormField.Type.IMAGE
elif etype == "button":
type = FormField.Type.BUTTON
elif etype == "file":
type = FormField.Type.FILE
else:
type = FormField.Type.OTHER
elif tag == FormField.Tag.TEXTAREA:
type = None
name = e.getAttribute('name').encode('ascii', 'ignore')
textarea = htmlunit.HtmlTextArea.cast_(e)
value = textarea.getText()
elif tag == FormField.Tag.BUTTON and \
e.getAttribute('type').upper() == FormField.Type.SUBMIT:
type = FormField.Type.SUBMIT
name = e.getAttribute('name').encode('ascii', 'ignore')
value = e.getAttribute('value').encode('ascii', 'ignore')
else:
raise RuntimeError("unexpcted form field tag %s" % tag)
# TODO: properly support it
attrs = list(e.getAttributesMap().keySet())
for a in attrs:
if a.startswith("on") or a == "target":
e.removeAttribute(a)
return FormField(tag, type, name, value)
@lazyproperty
def inputnames(self):
return [i.name for i in self.inputs]
@lazyproperty
def hiddennames(self):
return [i.name for i in self.hiddens]
@lazyproperty
def textareanames(self):
return [i.name for i in self.textareas]
@lazyproperty
def selectnames(self):
return [i.name for i in self.selectnames]
@lazyproperty
def inputs(self):
return [self.buildFormField(e)
for e in (htmlunit.HtmlElement.cast_(i)
for i in self.internal.getHtmlElementsByTagName('input'))
if e.getAttribute('type').lower() not in ["hidden", "button", "submit"] ]
@lazyproperty
def hiddens(self):
return [self.buildFormField(e)
for e in (htmlunit.HtmlElement.cast_(i)
for i in self.internal.getHtmlElementsByTagName('input'))
if e.getAttribute('type').lower() == "hidden"]
@lazyproperty
def textareas(self):
return [self.buildFormField(e)
for e in (htmlunit.HtmlElement.cast_(i)
for i in self.internal.getHtmlElementsByTagName('textarea'))]
@lazyproperty
def selects(self):
# TODO
return []
@lazyproperty
def submittables(self):
result = []
for submittable in Form.SUBMITTABLES:
try:
submitters = self.internal.getElementsByAttribute(*submittable)
result.extend(self.buildFormField(
htmlunit.HtmlElement.cast_(i)) for i in submitters)
except htmlunit.JavaError, e:
javaex = e.getJavaException()
if not htmlunit.ElementNotFoundException.instance_(javaex):
raise
continue
return result
class AbstractForm(AbstractLink):
def __init__(self, forms):
if not isinstance(forms, list):
forms = list(forms)
AbstractLink.__init__(self, forms)
self.forms = forms
self.methods = set(i.method for i in forms)
self.actions = set(i.action for i in forms)
self.type = Links.Type.FORM
self._elemset = None
def update(self, forms):
self.forms = forms
self.methods = set(i.method for i in forms)
self.actions = set(i.action for i in forms)
self._elemset = None
@property
def _str(self):
return "AbstractForm(targets=%s)" % (self.targets)
def equals(self, f):
return (self.methods, self.actions) == (f.methods, f.actions)
@lazyproperty
def isPOST(self):
return Form.POST in self.methods
@lazyproperty
def action(self):
# XXX multiple hrefs not supported yet
assert len(self.actions) == 1
return iter(self.actions).next()
@property
def elemset(self):
if self._elemset is None:
elemnamesets = [frozenset(i.elemnames) for i in self.forms]
assert all_same(elemnamesets)
self._elemset = frozenset(self.forms[0].elems)
return self._elemset