Ticket #13978: 0001-Allow-inline-JS-CSS-in-forms.Media-13978.patch
File 0001-Allow-inline-JS-CSS-in-forms.Media-13978.patch, 7.7 KB (added by , 12 years ago) |
---|
-
django/forms/widgets.py
From 36f0556de03a65f35f7c69e130bc853c1e01e7a5 Mon Sep 17 00:00:00 2001 From: dmpayton <derek.payton@gmail.com> Date: Tue, 20 Nov 2012 15:34:44 -0800 Subject: [PATCH] Allow inline JS/CSS in forms.Media (#13978) --- django/forms/widgets.py | 44 ++++++++++++++++++++-------- docs/topics/forms/media.txt | 37 +++++++++++++++++++++++ tests/regressiontests/forms/tests/media.py | 37 +++++++++++++++++++++++ 3 files changed, 106 insertions(+), 12 deletions(-) diff --git a/django/forms/widgets.py b/django/forms/widgets.py index c761ea8..65e59e2 100644
a b 34 34 35 35 @python_2_unicode_compatible 36 36 class Media(object): 37 class Inline(object): 38 def __init__(self, content): 39 self.content = content 40 41 def __eq__(self, other): 42 return ( 43 type(self) is type(other) and 44 self.content == other.content 45 ) 46 37 47 def __init__(self, media=None, **kwargs): 38 48 if media: 39 49 media_attrs = media.__dict__ … … def render(self): 57 67 return mark_safe('\n'.join(chain(*[getattr(self, 'render_' + name)() for name in MEDIA_TYPES]))) 58 68 59 69 def render_js(self): 60 return [format_html('<script type="text/javascript" src="{0}"></script>', self.absolute_path(path)) for path in self._js] 70 html = [] 71 for script in self._js: 72 if isinstance(script, self.Inline): 73 html.append(format_html('<script type="text/javascript">{0}</script>', mark_safe(script.content))) 74 else: 75 html.append(format_html('<script type="text/javascript" src="{0}"></script>', self.absolute_path(script))) 76 return html 61 77 62 78 def render_css(self): 63 79 # To keep rendering order consistent, we can't just iterate over items(). 64 80 # We need to sort the keys, and iterate over the sorted list. 81 html = [] 65 82 media = sorted(self._css.keys()) 66 return chain(*[ 67 [format_html('<link href="{0}" type="text/css" media="{1}" rel="stylesheet" />', self.absolute_path(path), medium) 68 for path in self._css[medium]] 69 for medium in media]) 83 for medium in media: 84 for style in self._css[medium]: 85 if isinstance(style, self.Inline): 86 html.append(format_html('<style type="text/css" media="{0}">{1}</style>', medium, mark_safe(style.content))) 87 else: 88 html.append(format_html('<link href="{0}" type="text/css" media="{1}" rel="stylesheet" />', self.absolute_path(style), medium)) 89 return html 70 90 71 91 def absolute_path(self, path, prefix=None): 72 92 if path.startswith(('http://', 'https://', '/')): … … def __getitem__(self, name): 87 107 88 108 def add_js(self, data): 89 109 if data: 90 for pathin data:91 if pathnot in self._js:92 self._js.append( path)110 for script in data: 111 if script not in self._js: 112 self._js.append(script) 93 113 94 114 def add_css(self, data): 95 115 if data: 96 for medium, paths in data.items():97 for path in paths:98 if not self._css.get(medium) or pathnot in self._css[medium]:99 self._css.setdefault(medium, []).append( path)116 for medium, styles in data.items(): 117 for style in styles: 118 if not self._css.get(medium) or style not in self._css[medium]: 119 self._css.setdefault(medium, []).append(style) 100 120 101 121 def __add__(self, other): 102 122 combined = Media() -
docs/topics/forms/media.txt
diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt index 98e70e5..34d5f89 100644
a b If you require even more control over media inheritance, define your media 167 167 using a :ref:`dynamic property <dynamic-property>`. Dynamic properties give 168 168 you complete control over which media files are inherited, and which are not. 169 169 170 Specifying inline media 171 ----------------------- 172 173 .. versionadded:: 1.5 174 175 At some point you may run into a situation that calls for a bit of inline CSS 176 or JavaScript, such as initializing a JavaScript plugin. To do this, simply 177 pass your inline code as a ``forms.Media.Inline`` object in the Media class:: 178 179 >>> class FancyCalendarWidget(CalendarWidget): 180 ... class Media: 181 ... css = { 182 ... 'all': ('fancy.css',) 183 ... } 184 ... js = ( 185 ... 'whizbang.js', 186 ... forms.Media.Inline('init_fancification();'), 187 ... ) 188 189 >>> w = FancyCalendarWidget() 190 >>> print(w.media) 191 <link href="/static/fancy.css" type="text/css" media="all" rel="stylesheet" /> 192 <script type="text/javascript" src="/static/whizbang.js"></script> 193 <script type="text/javascript">init_fancification();</script> 194 195 Inline CSS works the same way:: 196 197 >>> class HoneypotWidget(forms.TextInput): 198 ... class Media: 199 ... css = { 200 ... 'all': (forms.Media.Inline(".honeypot_row { display: none; }"),) 201 ... } 202 203 >>> w = HoneypotWidget() 204 >>> print(w.media) 205 <style type="text/css" media="all">.honeypot_row { display: none; }</style> 206 170 207 .. _dynamic-property: 171 208 172 209 Media as a dynamic property -
tests/regressiontests/forms/tests/media.py
diff --git a/tests/regressiontests/forms/tests/media.py b/tests/regressiontests/forms/tests/media.py index c492a1e..71e969e 100644
a b class Media: 455 455 <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" /> 456 456 <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />""") 457 457 458 def test_inline_media(self): 459 ## Inline JavaScript and CSS 460 class MyWidget(TextInput): 461 class Media: 462 css = {'all': (Media.Inline('.mywidget { display: none; }'),)} 463 js = (Media.Inline('init_mywidget();'),) 464 465 w = MyWidget() 466 self.assertEqual('<style type="text/css" media="all">.mywidget { display: none; }</style>', str(w.media['css'])) 467 self.assertEqual('<script type="text/javascript">init_mywidget();</script>', str(w.media['js'])) 468 469 def test_inline_media_property(self): 470 ## Inline JavaScript and CSS as a media property 471 class MyWidget(TextInput): 472 def _media(self): 473 return Media(css={'all': (Media.Inline('.mywidget { display: none; }'),)}, 474 js=(Media.Inline('init_mywidget();'),)) 475 media = property(_media) 476 477 w = MyWidget() 478 self.assertEqual('<style type="text/css" media="all">.mywidget { display: none; }</style>', str(w.media['css'])) 479 self.assertEqual('<script type="text/javascript">init_mywidget();</script>', str(w.media['js'])) 480 481 def test_inline_media_mutiple(self): 482 ## Multiple instances of inline media should only be rendered once 483 class MyWidget(TextInput): 484 class Media: 485 css = {'all': (Media.Inline('.mywidget { display: none; }'),)} 486 js = (Media.Inline('init_mywidget();'),) 487 488 class MyForm(Form): 489 field1 = CharField(widget=MyWidget) 490 field2 = CharField(widget=MyWidget) 491 492 f = MyForm() 493 self.assertEqual("""<style type="text/css" media="all">.mywidget { display: none; }</style> 494 <script type="text/javascript">init_mywidget();</script>""", str(f.media)) 458 495 459 496 @override_settings( 460 497 STATIC_URL='http://media.example.com/static/',