10 def attrget(obj, attr, value=None):
12 if hasattr(obj, 'has_key') and obj.has_key(attr):
15 # Handle the case where has_key takes different number of arguments.
16 # This is the case with Model objects on appengine. See #134
18 if hasattr(obj, attr):
19 return getattr(obj, attr)
26 >>> f = Form(Textbox("x"))
28 u'<table>\n <tr><th><label for="x">x</label></th><td><input type="text" id="x" name="x"/></td></tr>\n</table>'
30 def __init__(self, *inputs, **kw):
34 self.validators = kw.pop('validators', [])
36 def __call__(self, x=None):
37 o = copy.deepcopy(self)
43 out += self.rendernote(self.note)
47 html = utils.safeunicode(i.pre) + i.render() + self.rendernote(i.note) + utils.safeunicode(i.post)
49 out += ' <tr style="display: none;"><th></th><td>%s</td></tr>\n' % (html)
51 out += ' <tr><th><label for="%s">%s</label></th><td>%s</td></tr>\n' % (i.id, net.websafe(i.description), html)
57 out.append(self.rendernote(self.note))
60 out.append('<label for="%s">%s</label>' % (i.id, net.websafe(i.description)))
62 out.append(i.render())
63 out.append(self.rendernote(i.note))
68 def rendernote(self, note):
69 if note: return '<strong class="wrong">%s</strong>' % net.websafe(note)
72 def validates(self, source=None, _validate=True, **kw):
73 source = source or kw or web.input()
76 v = attrget(source, i.name)
78 out = i.validate(v) and out
82 out = out and self._validate(source)
86 def _validate(self, value):
88 for v in self.validators:
89 if not v.valid(value):
94 def fill(self, source=None, **kw):
95 return self.validates(source, _validate=False, **kw)
97 def __getitem__(self, i):
99 if x.name == i: return x
102 def __getattr__(self, name):
103 # don't interfere with deepcopy
104 inputs = self.__dict__.get('inputs') or []
106 if x.name == name: return x
107 raise AttributeError, name
109 def get(self, i, default=None):
115 def _get_d(self): #@@ should really be form.attr, no?
116 return utils.storage([(i.name, i.get_value()) for i in self.inputs])
120 def __init__(self, name, *validators, **attrs):
122 self.validators = validators
123 self.attrs = attrs = AttributeList(attrs)
125 self.description = attrs.pop('description', name)
126 self.value = attrs.pop('value', None)
127 self.pre = attrs.pop('pre', "")
128 self.post = attrs.pop('post', "")
131 self.id = attrs.setdefault('id', self.get_default_id())
133 if 'class_' in attrs:
134 attrs['class'] = attrs['class_']
141 raise NotImplementedError
143 def get_default_id(self):
146 def validate(self, value):
147 self.set_value(value)
149 for v in self.validators:
150 if not v.valid(value):
155 def set_value(self, value):
162 attrs = self.attrs.copy()
163 attrs['type'] = self.get_type()
164 if self.value is not None:
165 attrs['value'] = self.value
166 attrs['name'] = self.name
167 return '<input %s/>' % attrs
169 def rendernote(self, note):
170 if note: return '<strong class="wrong">%s</strong>' % net.websafe(note)
174 # add leading space for backward-compatibility
175 return " " + str(self.attrs)
177 class AttributeList(dict):
178 """List of atributes of input.
180 >>> a = AttributeList(type='text', name='x', value=20)
182 <attrs: 'type="text" name="x" value="20"'>
185 return AttributeList(self)
188 return " ".join(['%s="%s"' % (k, net.websafe(v)) for k, v in self.items()])
191 return '<attrs: %s>' % repr(str(self))
193 class Textbox(Input):
196 >>> Textbox(name='foo', value='bar').render()
197 u'<input type="text" id="foo" value="bar" name="foo"/>'
198 >>> Textbox(name='foo', value=0).render()
199 u'<input type="text" id="foo" value="0" name="foo"/>'
204 class Password(Input):
207 >>> Password(name='password', value='secret').render()
208 u'<input type="password" id="password" value="secret" name="password"/>'
214 class Textarea(Input):
217 >>> Textarea(name='foo', value='bar').render()
218 u'<textarea id="foo" name="foo">bar</textarea>'
221 attrs = self.attrs.copy()
222 attrs['name'] = self.name
223 value = net.websafe(self.value or '')
224 return '<textarea %s>%s</textarea>' % (attrs, value)
226 class Dropdown(Input):
227 r"""Dropdown/select input.
229 >>> Dropdown(name='foo', args=['a', 'b', 'c'], value='b').render()
230 u'<select id="foo" name="foo">\n <option value="a">a</option>\n <option selected="selected" value="b">b</option>\n <option value="c">c</option>\n</select>\n'
231 >>> Dropdown(name='foo', args=[('a', 'aa'), ('b', 'bb'), ('c', 'cc')], value='b').render()
232 u'<select id="foo" name="foo">\n <option value="a">aa</option>\n <option selected="selected" value="b">bb</option>\n <option value="c">cc</option>\n</select>\n'
234 def __init__(self, name, args, *validators, **attrs):
236 super(Dropdown, self).__init__(name, *validators, **attrs)
239 attrs = self.attrs.copy()
240 attrs['name'] = self.name
242 x = '<select %s>\n' % attrs
244 for arg in self.args:
245 x += self._render_option(arg)
250 def _render_option(self, arg, indent=' '):
251 if isinstance(arg, (tuple, list)):
254 value, desc = arg, arg
256 if self.value == value or (isinstance(self.value, list) and value in self.value):
257 select_p = ' selected="selected"'
260 return indent + '<option%s value="%s">%s</option>\n' % (select_p, net.websafe(value), net.websafe(desc))
263 class GroupedDropdown(Dropdown):
264 r"""Grouped Dropdown/select input.
266 >>> GroupedDropdown(name='car_type', args=(('Swedish Cars', ('Volvo', 'Saab')), ('German Cars', ('Mercedes', 'Audi'))), value='Audi').render()
267 u'<select id="car_type" name="car_type">\n <optgroup label="Swedish Cars">\n <option value="Volvo">Volvo</option>\n <option value="Saab">Saab</option>\n </optgroup>\n <optgroup label="German Cars">\n <option value="Mercedes">Mercedes</option>\n <option selected="selected" value="Audi">Audi</option>\n </optgroup>\n</select>\n'
268 >>> GroupedDropdown(name='car_type', args=(('Swedish Cars', (('v', 'Volvo'), ('s', 'Saab'))), ('German Cars', (('m', 'Mercedes'), ('a', 'Audi')))), value='a').render()
269 u'<select id="car_type" name="car_type">\n <optgroup label="Swedish Cars">\n <option value="v">Volvo</option>\n <option value="s">Saab</option>\n </optgroup>\n <optgroup label="German Cars">\n <option value="m">Mercedes</option>\n <option selected="selected" value="a">Audi</option>\n </optgroup>\n</select>\n'
272 def __init__(self, name, args, *validators, **attrs):
274 super(Dropdown, self).__init__(name, *validators, **attrs)
277 attrs = self.attrs.copy()
278 attrs['name'] = self.name
280 x = '<select %s>\n' % attrs
282 for label, options in self.args:
283 x += ' <optgroup label="%s">\n' % net.websafe(label)
285 x += self._render_option(arg, indent = ' ')
286 x += ' </optgroup>\n'
292 def __init__(self, name, args, *validators, **attrs):
294 super(Radio, self).__init__(name, *validators, **attrs)
298 for arg in self.args:
299 if isinstance(arg, (tuple, list)):
302 value, desc = arg, arg
303 attrs = self.attrs.copy()
304 attrs['name'] = self.name
305 attrs['type'] = 'radio'
306 attrs['value'] = value
307 if self.value == value:
308 attrs['checked'] = 'checked'
309 x += '<input %s/> %s' % (attrs, net.websafe(desc))
313 class Checkbox(Input):
316 >>> Checkbox('foo', value='bar', checked=True).render()
317 u'<input checked="checked" type="checkbox" id="foo_bar" value="bar" name="foo"/>'
318 >>> Checkbox('foo', value='bar').render()
319 u'<input type="checkbox" id="foo_bar" value="bar" name="foo"/>'
320 >>> c = Checkbox('foo', value='bar')
324 u'<input checked="checked" type="checkbox" id="foo_bar" value="bar" name="foo"/>'
326 def __init__(self, name, *validators, **attrs):
327 self.checked = attrs.pop('checked', False)
328 Input.__init__(self, name, *validators, **attrs)
330 def get_default_id(self):
331 value = utils.safestr(self.value or "")
332 return self.name + '_' + value.replace(' ', '_')
335 attrs = self.attrs.copy()
336 attrs['type'] = 'checkbox'
337 attrs['name'] = self.name
338 attrs['value'] = self.value
341 attrs['checked'] = 'checked'
342 return '<input %s/>' % attrs
344 def set_value(self, value):
345 self.checked = bool(value)
353 >>> Button("save").render()
354 u'<button id="save" name="save">save</button>'
355 >>> Button("action", value="save", html="<b>Save Changes</b>").render()
356 u'<button id="action" value="save" name="action"><b>Save Changes</b></button>'
358 def __init__(self, name, *validators, **attrs):
359 super(Button, self).__init__(name, *validators, **attrs)
360 self.description = ""
363 attrs = self.attrs.copy()
364 attrs['name'] = self.name
365 if self.value is not None:
366 attrs['value'] = self.value
367 html = attrs.pop('html', None) or net.websafe(self.name)
368 return '<button %s>%s</button>' % (attrs, html)
373 >>> Hidden(name='foo', value='bar').render()
374 u'<input type="hidden" id="foo" value="bar" name="foo"/>'
385 >>> File(name='f').render()
386 u'<input type="file" id="f" name="f"/>'
392 def __deepcopy__(self, memo): return copy.copy(self)
393 def __init__(self, msg, test, jstest=None): utils.autoassign(self, locals())
394 def valid(self, value):
395 try: return self.test(value)
398 notnull = Validator("Required", bool)
400 class regexp(Validator):
401 def __init__(self, rexp, msg):
402 self.rexp = re.compile(rexp)
405 def valid(self, value):
406 return bool(self.rexp.match(value))
408 if __name__ == "__main__":