1 """ |
1 """ |
2 HTML Widget classes |
2 HTML Widget classes |
3 """ |
3 """ |
4 |
4 |
5 try: |
5 import django.utils.copycompat as copy |
6 set |
|
7 except NameError: |
|
8 from sets import Set as set # Python 2.3 fallback |
|
9 |
|
10 import copy |
|
11 from itertools import chain |
6 from itertools import chain |
12 from django.conf import settings |
7 from django.conf import settings |
13 from django.utils.datastructures import MultiValueDict, MergeDict |
8 from django.utils.datastructures import MultiValueDict, MergeDict |
14 from django.utils.html import escape, conditional_escape |
9 from django.utils.html import escape, conditional_escape |
15 from django.utils.translation import ugettext |
10 from django.utils.translation import ugettext |
16 from django.utils.encoding import StrAndUnicode, force_unicode |
11 from django.utils.encoding import StrAndUnicode, force_unicode |
17 from django.utils.safestring import mark_safe |
12 from django.utils.safestring import mark_safe |
18 from django.utils import datetime_safe |
13 from django.utils import formats |
19 from datetime import time |
14 import time |
|
15 import datetime |
20 from util import flatatt |
16 from util import flatatt |
21 from urlparse import urljoin |
17 from urlparse import urljoin |
22 |
18 |
23 __all__ = ( |
19 __all__ = ( |
24 'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'PasswordInput', |
20 'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'PasswordInput', |
245 self.choices = choices |
245 self.choices = choices |
246 |
246 |
247 def render(self, name, value, attrs=None, choices=()): |
247 def render(self, name, value, attrs=None, choices=()): |
248 if value is None: value = [] |
248 if value is None: value = [] |
249 final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) |
249 final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) |
250 return mark_safe(u'\n'.join([(u'<input%s />' % |
250 id_ = final_attrs.get('id', None) |
251 flatatt(dict(value=force_unicode(v), **final_attrs))) |
251 inputs = [] |
252 for v in value])) |
252 for i, v in enumerate(value): |
|
253 input_attrs = dict(value=force_unicode(v), **final_attrs) |
|
254 if id_: |
|
255 # An ID attribute was given. Add a numeric index as a suffix |
|
256 # so that the inputs don't all have the same ID attribute. |
|
257 input_attrs['id'] = '%s_%s' % (id_, i) |
|
258 inputs.append(u'<input%s />' % flatatt(input_attrs)) |
|
259 return mark_safe(u'\n'.join(inputs)) |
253 |
260 |
254 def value_from_datadict(self, data, files, name): |
261 def value_from_datadict(self, data, files, name): |
255 if isinstance(data, (MultiValueDict, MergeDict)): |
262 if isinstance(data, (MultiValueDict, MergeDict)): |
256 return data.getlist(name) |
263 return data.getlist(name) |
257 return data.get(name, None) |
264 return data.get(name, None) |
286 return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), |
293 return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), |
287 conditional_escape(force_unicode(value)))) |
294 conditional_escape(force_unicode(value)))) |
288 |
295 |
289 class DateInput(Input): |
296 class DateInput(Input): |
290 input_type = 'text' |
297 input_type = 'text' |
291 format = '%Y-%m-%d' # '2006-10-25' |
298 format = None |
292 |
299 |
293 def __init__(self, attrs=None, format=None): |
300 def __init__(self, attrs=None, format=None): |
294 super(DateInput, self).__init__(attrs) |
301 super(DateInput, self).__init__(attrs) |
295 if format: |
302 if format: |
296 self.format = format |
303 self.format = format |
297 |
304 |
298 def _format_value(self, value): |
305 def _format_value(self, value): |
299 if value is None: |
306 if value is None: |
300 return '' |
307 return '' |
301 elif hasattr(value, 'strftime'): |
308 elif hasattr(value, 'strftime'): |
302 value = datetime_safe.new_date(value) |
309 return formats.localize_input(value, self.format) |
303 return value.strftime(self.format) |
|
304 return value |
310 return value |
305 |
311 |
306 def render(self, name, value, attrs=None): |
312 def render(self, name, value, attrs=None): |
307 value = self._format_value(value) |
313 value = self._format_value(value) |
308 return super(DateInput, self).render(name, value, attrs) |
314 return super(DateInput, self).render(name, value, attrs) |
309 |
315 |
310 def _has_changed(self, initial, data): |
316 def _has_changed(self, initial, data): |
|
317 # If our field has show_hidden_initial=True, initial will be a string |
|
318 # formatted by HiddenInput using formats.localize_input, which is not |
|
319 # necessarily the format used for this widget. Attempt to convert it. |
|
320 try: |
|
321 input_format = formats.get_format('DATE_INPUT_FORMATS')[0] |
|
322 initial = datetime.date(*time.strptime(initial, input_format)[:3]) |
|
323 except (TypeError, ValueError): |
|
324 pass |
311 return super(DateInput, self)._has_changed(self._format_value(initial), data) |
325 return super(DateInput, self)._has_changed(self._format_value(initial), data) |
312 |
326 |
313 class DateTimeInput(Input): |
327 class DateTimeInput(Input): |
314 input_type = 'text' |
328 input_type = 'text' |
315 format = '%Y-%m-%d %H:%M:%S' # '2006-10-25 14:30:59' |
329 format = None |
316 |
330 |
317 def __init__(self, attrs=None, format=None): |
331 def __init__(self, attrs=None, format=None): |
318 super(DateTimeInput, self).__init__(attrs) |
332 super(DateTimeInput, self).__init__(attrs) |
319 if format: |
333 if format: |
320 self.format = format |
334 self.format = format |
321 |
335 |
322 def _format_value(self, value): |
336 def _format_value(self, value): |
323 if value is None: |
337 if value is None: |
324 return '' |
338 return '' |
325 elif hasattr(value, 'strftime'): |
339 elif hasattr(value, 'strftime'): |
326 value = datetime_safe.new_datetime(value) |
340 return formats.localize_input(value, self.format) |
327 return value.strftime(self.format) |
|
328 return value |
341 return value |
329 |
342 |
330 def render(self, name, value, attrs=None): |
343 def render(self, name, value, attrs=None): |
331 value = self._format_value(value) |
344 value = self._format_value(value) |
332 return super(DateTimeInput, self).render(name, value, attrs) |
345 return super(DateTimeInput, self).render(name, value, attrs) |
333 |
346 |
334 def _has_changed(self, initial, data): |
347 def _has_changed(self, initial, data): |
|
348 # If our field has show_hidden_initial=True, initial will be a string |
|
349 # formatted by HiddenInput using formats.localize_input, which is not |
|
350 # necessarily the format used for this widget. Attempt to convert it. |
|
351 try: |
|
352 input_format = formats.get_format('DATETIME_INPUT_FORMATS')[0] |
|
353 initial = datetime.datetime(*time.strptime(initial, input_format)[:6]) |
|
354 except (TypeError, ValueError): |
|
355 pass |
335 return super(DateTimeInput, self)._has_changed(self._format_value(initial), data) |
356 return super(DateTimeInput, self)._has_changed(self._format_value(initial), data) |
336 |
357 |
337 class TimeInput(Input): |
358 class TimeInput(Input): |
338 input_type = 'text' |
359 input_type = 'text' |
339 format = '%H:%M:%S' # '14:30:59' |
360 format = None |
340 |
361 |
341 def __init__(self, attrs=None, format=None): |
362 def __init__(self, attrs=None, format=None): |
342 super(TimeInput, self).__init__(attrs) |
363 super(TimeInput, self).__init__(attrs) |
343 if format: |
364 if format: |
344 self.format = format |
365 self.format = format |
345 |
366 |
346 def _format_value(self, value): |
367 def _format_value(self, value): |
347 if value is None: |
368 if value is None: |
348 return '' |
369 return '' |
349 elif hasattr(value, 'strftime'): |
370 elif hasattr(value, 'strftime'): |
350 return value.strftime(self.format) |
371 return formats.localize_input(value, self.format) |
351 return value |
372 return value |
352 |
373 |
353 def render(self, name, value, attrs=None): |
374 def render(self, name, value, attrs=None): |
354 value = self._format_value(value) |
375 value = self._format_value(value) |
355 return super(TimeInput, self).render(name, value, attrs) |
376 return super(TimeInput, self).render(name, value, attrs) |
356 |
377 |
357 def _has_changed(self, initial, data): |
378 def _has_changed(self, initial, data): |
|
379 # If our field has show_hidden_initial=True, initial will be a string |
|
380 # formatted by HiddenInput using formats.localize_input, which is not |
|
381 # necessarily the format used for this widget. Attempt to convert it. |
|
382 try: |
|
383 input_format = formats.get_format('TIME_INPUT_FORMATS')[0] |
|
384 initial = datetime.time(*time.strptime(initial, input_format)[3:6]) |
|
385 except (TypeError, ValueError): |
|
386 pass |
358 return super(TimeInput, self)._has_changed(self._format_value(initial), data) |
387 return super(TimeInput, self)._has_changed(self._format_value(initial), data) |
359 |
388 |
360 class CheckboxInput(Widget): |
389 class CheckboxInput(Widget): |
361 def __init__(self, attrs=None, check_test=bool): |
390 def __init__(self, attrs=None, check_test=bool): |
362 super(CheckboxInput, self).__init__(attrs) |
391 super(CheckboxInput, self).__init__(attrs) |