Ticket #8103: 8103.diff
File 8103.diff, 7.8 KB (added by , 16 years ago) |
---|
-
django/forms/widgets.py
35 35 media_attrs = media.__dict__ 36 36 else: 37 37 media_attrs = kwargs 38 38 39 39 self._css = {} 40 40 self._js = [] 41 41 42 42 for name in MEDIA_TYPES: 43 43 getattr(self, 'add_' + name)(media_attrs.get(name, None)) 44 44 45 45 # Any leftover attributes must be invalid. 46 46 # if media_attrs != {}: 47 47 # raise TypeError, "'class Media' has invalid attribute(s): %s" % ','.join(media_attrs.keys()) 48 48 49 49 def __unicode__(self): 50 50 return self.render() 51 51 52 52 def render(self): 53 53 return u'\n'.join(chain(*[getattr(self, 'render_' + name)() for name in MEDIA_TYPES])) 54 54 55 55 def render_js(self): 56 56 return [u'<script type="text/javascript" src="%s"></script>' % self.absolute_path(path) for path in self._js] 57 57 58 58 def render_css(self): 59 59 # To keep rendering order consistent, we can't just iterate over items(). 60 60 # We need to sort the keys, and iterate over the sorted list. 61 61 media = self._css.keys() 62 62 media.sort() 63 63 return chain(*[ 64 [u'<link href="%s" type="text/css" media="%s" rel="stylesheet" />' % (self.absolute_path(path), medium) 65 for path in self._css[medium]] 64 [u'<link href="%s" type="text/css" media="%s" rel="stylesheet" />' % (self.absolute_path(path), medium) 65 for path in self._css[medium]] 66 66 for medium in media]) 67 67 68 68 def absolute_path(self, path): 69 69 if path.startswith(u'http://') or path.startswith(u'https://') or path.startswith(u'/'): 70 70 return path … … 77 77 raise KeyError('Unknown media type "%s"' % name) 78 78 79 79 def add_js(self, data): 80 if data: 80 if data: 81 81 self._js.extend([path for path in data if path not in self._js]) 82 82 83 83 def add_css(self, data): 84 84 if data: 85 85 for medium, paths in data.items(): … … 99 99 base = super(cls, self).media 100 100 else: 101 101 base = Media() 102 103 # Get the media definition for this class 102 103 # Get the media definition for this class 104 104 definition = getattr(cls, 'Media', None) 105 105 if definition: 106 106 extend = getattr(definition, 'extend', True) … … 117 117 else: 118 118 return base 119 119 return property(_media) 120 120 121 121 class MediaDefiningClass(type): 122 122 "Metaclass for classes that can have media definitions" 123 def __new__(cls, name, bases, attrs): 123 def __new__(cls, name, bases, attrs): 124 124 new_class = super(MediaDefiningClass, cls).__new__(cls, name, bases, 125 125 attrs) 126 126 if 'media' not in attrs: 127 127 new_class.media = media_property(new_class) 128 128 return new_class 129 129 130 130 class Widget(object): 131 131 __metaclass__ = MediaDefiningClass 132 132 is_hidden = False # Determines whether this corresponds to an <input type="hidden">. … … 264 264 def value_from_datadict(self, data, files, name): 265 265 "File widgets take data from FILES, not POST" 266 266 return files.get(name, None) 267 267 268 268 def _has_changed(self, initial, data): 269 269 if data is None: 270 270 return False … … 334 334 return bool(initial) != bool(data) 335 335 336 336 class Select(Widget): 337 allow_multiple_selected = False 338 337 339 def __init__(self, attrs=None, choices=()): 338 340 super(Select, self).__init__(attrs) 339 341 # choices can be any iterable, but we may need to render this widget … … 354 356 def render_options(self, choices, selected_choices): 355 357 def render_option(option_value, option_label): 356 358 option_value = force_unicode(option_value) 357 selected_html = (option_value in selected_choices) and u' selected="selected"' or '' 359 if not getattr(render_option, 'selected', None)\ 360 and option_value in selected_choices: 361 if not self.allow_multiple_selected: 362 # Only allow for a single selection. 363 render_option.selected = True 364 selected_html = u' selected="selected"' 365 else: 366 selected_html = '' 358 367 return u'<option value="%s"%s>%s</option>' % ( 359 368 escape(option_value), selected_html, 360 369 conditional_escape(force_unicode(option_label))) … … 396 405 return bool(initial) != bool(data) 397 406 398 407 class SelectMultiple(Select): 408 allow_multiple_selected = True 409 399 410 def render(self, name, value, attrs=None, choices=()): 400 411 if value is None: value = [] 401 412 final_attrs = self.build_attrs(attrs, name=name) … … 410 421 if isinstance(data, MultiValueDict): 411 422 return data.getlist(name) 412 423 return data.get(name, None) 413 424 414 425 def _has_changed(self, initial, data): 415 426 if initial is None: 416 427 initial = [] … … 527 538 label_for = u' for="%s"' % final_attrs['id'] 528 539 else: 529 540 label_for = '' 530 541 531 542 cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values) 532 543 option_value = force_unicode(option_value) 533 544 rendered_cb = cb.render(name, option_value) … … 601 612 602 613 def value_from_datadict(self, data, files, name): 603 614 return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)] 604 615 605 616 def _has_changed(self, initial, data): 606 617 if initial is None: 607 618 initial = [u'' for x in range(0, len(data))] … … 637 648 media = media + w.media 638 649 return media 639 650 media = property(_get_media) 640 651 641 652 class SplitDateTimeWidget(MultiWidget): 642 653 """ 643 654 A Widget that splits datetime input into two <input type="text"> boxes. -
tests/regressiontests/forms/widgets.py
458 458 <option value="4">4</option> 459 459 </select> 460 460 461 Only one option can be selected: 462 >>> print w.render('choices', 0, choices=(('0', 'extra'),)) 463 <select name="choices"> 464 <option value="0" selected="selected">0</option> 465 <option value="1">1</option> 466 <option value="2">2</option> 467 <option value="3">3</option> 468 <option value="4">4</option> 469 <option value="0">extra</option> 470 </select> 471 472 Ensure that it still selects the first element next time round: 473 >>> print w.render('choices', 0, choices=(('0', 'extra'),)) 474 <select name="choices"> 475 <option value="0" selected="selected">0</option> 476 <option value="1">1</option> 477 <option value="2">2</option> 478 <option value="3">3</option> 479 <option value="4">4</option> 480 <option value="0">extra</option> 481 </select> 482 461 483 Choices can be nested one level in order to create HTML optgroups: 462 484 >>> w.choices=(('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2')))) 463 485 >>> print w.render('nestchoice', None) … … 655 677 >>> w._has_changed([1, 2], [u'1', u'3']) 656 678 True 657 679 680 Multiple options (with the same value) can be selected: 681 >>> print w.render('choices', [1], choices=(('1', 'extra'),)) 682 <select multiple="multiple" name="choices"> 683 <option value="1" selected="selected">1</option> 684 <option value="2">2</option> 685 <option value="3">3</option> 686 <option value="1" selected="selected">extra</option> 687 </select> 688 658 689 # Choices can be nested one level in order to create HTML optgroups: 659 690 >>> w.choices = (('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2')))) 660 691 >>> print w.render('nestchoice', None)