PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/regressiontests/forms/tests/media.py

https://code.google.com/p/mango-py/
Python | 920 lines | 913 code | 4 blank | 3 comment | 0 complexity | c3ecf15f6dd23e7f4441ab935c7db1dc MD5 | raw file
Possible License(s): BSD-3-Clause
  1. # -*- coding: utf-8 -*-
  2. from django.conf import settings
  3. from django.forms import TextInput, Media, TextInput, CharField, Form, MultiWidget
  4. from django.utils.unittest import TestCase
  5. class FormsMediaTestCase(TestCase):
  6. # Tests for the media handling on widgets and forms
  7. def setUp(self):
  8. super(FormsMediaTestCase, self).setUp()
  9. self.original_media_url = settings.MEDIA_URL
  10. settings.MEDIA_URL = 'http://media.example.com/media/'
  11. def tearDown(self):
  12. settings.MEDIA_URL = self.original_media_url
  13. super(FormsMediaTestCase, self).tearDown()
  14. def test_construction(self):
  15. # Check construction of media objects
  16. m = Media(css={'all': ('path/to/css1','/path/to/css2')}, js=('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3'))
  17. self.assertEqual(str(m), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  18. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  19. <script type="text/javascript" src="/path/to/js1"></script>
  20. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  21. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  22. class Foo:
  23. css = {
  24. 'all': ('path/to/css1','/path/to/css2')
  25. }
  26. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  27. m3 = Media(Foo)
  28. self.assertEqual(str(m3), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  29. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  30. <script type="text/javascript" src="/path/to/js1"></script>
  31. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  32. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  33. # A widget can exist without a media definition
  34. class MyWidget(TextInput):
  35. pass
  36. w = MyWidget()
  37. self.assertEqual(str(w.media), '')
  38. def test_media_dsl(self):
  39. ###############################################################
  40. # DSL Class-based media definitions
  41. ###############################################################
  42. # A widget can define media if it needs to.
  43. # Any absolute path will be preserved; relative paths are combined
  44. # with the value of settings.MEDIA_URL
  45. class MyWidget1(TextInput):
  46. class Media:
  47. css = {
  48. 'all': ('path/to/css1','/path/to/css2')
  49. }
  50. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  51. w1 = MyWidget1()
  52. self.assertEqual(str(w1.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  53. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  54. <script type="text/javascript" src="/path/to/js1"></script>
  55. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  56. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  57. # Media objects can be interrogated by media type
  58. self.assertEqual(str(w1.media['css']), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  59. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />""")
  60. self.assertEqual(str(w1.media['js']), """<script type="text/javascript" src="/path/to/js1"></script>
  61. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  62. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  63. def test_combine_media(self):
  64. # Media objects can be combined. Any given media resource will appear only
  65. # once. Duplicated media definitions are ignored.
  66. class MyWidget1(TextInput):
  67. class Media:
  68. css = {
  69. 'all': ('path/to/css1','/path/to/css2')
  70. }
  71. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  72. class MyWidget2(TextInput):
  73. class Media:
  74. css = {
  75. 'all': ('/path/to/css2','/path/to/css3')
  76. }
  77. js = ('/path/to/js1','/path/to/js4')
  78. class MyWidget3(TextInput):
  79. class Media:
  80. css = {
  81. 'all': ('/path/to/css3','path/to/css1')
  82. }
  83. js = ('/path/to/js1','/path/to/js4')
  84. w1 = MyWidget1()
  85. w2 = MyWidget2()
  86. w3 = MyWidget3()
  87. self.assertEqual(str(w1.media + w2.media + w3.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  88. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  89. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  90. <script type="text/javascript" src="/path/to/js1"></script>
  91. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  92. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  93. <script type="text/javascript" src="/path/to/js4"></script>""")
  94. # Check that media addition hasn't affected the original objects
  95. self.assertEqual(str(w1.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  96. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  97. <script type="text/javascript" src="/path/to/js1"></script>
  98. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  99. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  100. # Regression check for #12879: specifying the same CSS or JS file
  101. # multiple times in a single Media instance should result in that file
  102. # only being included once.
  103. class MyWidget4(TextInput):
  104. class Media:
  105. css = {'all': ('/path/to/css1', '/path/to/css1')}
  106. js = ('/path/to/js1', '/path/to/js1')
  107. w4 = MyWidget4()
  108. self.assertEqual(str(w4.media), """<link href="/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  109. <script type="text/javascript" src="/path/to/js1"></script>""")
  110. def test_media_property(self):
  111. ###############################################################
  112. # Property-based media definitions
  113. ###############################################################
  114. # Widget media can be defined as a property
  115. class MyWidget4(TextInput):
  116. def _media(self):
  117. return Media(css={'all': ('/some/path',)}, js = ('/some/js',))
  118. media = property(_media)
  119. w4 = MyWidget4()
  120. self.assertEqual(str(w4.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
  121. <script type="text/javascript" src="/some/js"></script>""")
  122. # Media properties can reference the media of their parents
  123. class MyWidget5(MyWidget4):
  124. def _media(self):
  125. return super(MyWidget5, self).media + Media(css={'all': ('/other/path',)}, js = ('/other/js',))
  126. media = property(_media)
  127. w5 = MyWidget5()
  128. self.assertEqual(str(w5.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
  129. <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
  130. <script type="text/javascript" src="/some/js"></script>
  131. <script type="text/javascript" src="/other/js"></script>""")
  132. def test_media_property_parent_references(self):
  133. # Media properties can reference the media of their parents,
  134. # even if the parent media was defined using a class
  135. class MyWidget1(TextInput):
  136. class Media:
  137. css = {
  138. 'all': ('path/to/css1','/path/to/css2')
  139. }
  140. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  141. class MyWidget6(MyWidget1):
  142. def _media(self):
  143. return super(MyWidget6, self).media + Media(css={'all': ('/other/path',)}, js = ('/other/js',))
  144. media = property(_media)
  145. w6 = MyWidget6()
  146. self.assertEqual(str(w6.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  147. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  148. <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
  149. <script type="text/javascript" src="/path/to/js1"></script>
  150. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  151. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  152. <script type="text/javascript" src="/other/js"></script>""")
  153. def test_media_inheritance(self):
  154. ###############################################################
  155. # Inheritance of media
  156. ###############################################################
  157. # If a widget extends another but provides no media definition, it inherits the parent widget's media
  158. class MyWidget1(TextInput):
  159. class Media:
  160. css = {
  161. 'all': ('path/to/css1','/path/to/css2')
  162. }
  163. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  164. class MyWidget7(MyWidget1):
  165. pass
  166. w7 = MyWidget7()
  167. self.assertEqual(str(w7.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  168. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  169. <script type="text/javascript" src="/path/to/js1"></script>
  170. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  171. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  172. # If a widget extends another but defines media, it extends the parent widget's media by default
  173. class MyWidget8(MyWidget1):
  174. class Media:
  175. css = {
  176. 'all': ('/path/to/css3','path/to/css1')
  177. }
  178. js = ('/path/to/js1','/path/to/js4')
  179. w8 = MyWidget8()
  180. self.assertEqual(str(w8.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  181. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  182. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  183. <script type="text/javascript" src="/path/to/js1"></script>
  184. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  185. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  186. <script type="text/javascript" src="/path/to/js4"></script>""")
  187. def test_media_inheritance_from_property(self):
  188. # If a widget extends another but defines media, it extends the parents widget's media,
  189. # even if the parent defined media using a property.
  190. class MyWidget1(TextInput):
  191. class Media:
  192. css = {
  193. 'all': ('path/to/css1','/path/to/css2')
  194. }
  195. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  196. class MyWidget4(TextInput):
  197. def _media(self):
  198. return Media(css={'all': ('/some/path',)}, js = ('/some/js',))
  199. media = property(_media)
  200. class MyWidget9(MyWidget4):
  201. class Media:
  202. css = {
  203. 'all': ('/other/path',)
  204. }
  205. js = ('/other/js',)
  206. w9 = MyWidget9()
  207. self.assertEqual(str(w9.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
  208. <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
  209. <script type="text/javascript" src="/some/js"></script>
  210. <script type="text/javascript" src="/other/js"></script>""")
  211. # A widget can disable media inheritance by specifying 'extend=False'
  212. class MyWidget10(MyWidget1):
  213. class Media:
  214. extend = False
  215. css = {
  216. 'all': ('/path/to/css3','path/to/css1')
  217. }
  218. js = ('/path/to/js1','/path/to/js4')
  219. w10 = MyWidget10()
  220. self.assertEqual(str(w10.media), """<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  221. <link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  222. <script type="text/javascript" src="/path/to/js1"></script>
  223. <script type="text/javascript" src="/path/to/js4"></script>""")
  224. def test_media_inheritance_extends(self):
  225. # A widget can explicitly enable full media inheritance by specifying 'extend=True'
  226. class MyWidget1(TextInput):
  227. class Media:
  228. css = {
  229. 'all': ('path/to/css1','/path/to/css2')
  230. }
  231. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  232. class MyWidget11(MyWidget1):
  233. class Media:
  234. extend = True
  235. css = {
  236. 'all': ('/path/to/css3','path/to/css1')
  237. }
  238. js = ('/path/to/js1','/path/to/js4')
  239. w11 = MyWidget11()
  240. self.assertEqual(str(w11.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  241. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  242. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  243. <script type="text/javascript" src="/path/to/js1"></script>
  244. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  245. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  246. <script type="text/javascript" src="/path/to/js4"></script>""")
  247. def test_media_inheritance_single_type(self):
  248. # A widget can enable inheritance of one media type by specifying extend as a tuple
  249. class MyWidget1(TextInput):
  250. class Media:
  251. css = {
  252. 'all': ('path/to/css1','/path/to/css2')
  253. }
  254. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  255. class MyWidget12(MyWidget1):
  256. class Media:
  257. extend = ('css',)
  258. css = {
  259. 'all': ('/path/to/css3','path/to/css1')
  260. }
  261. js = ('/path/to/js1','/path/to/js4')
  262. w12 = MyWidget12()
  263. self.assertEqual(str(w12.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  264. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  265. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  266. <script type="text/javascript" src="/path/to/js1"></script>
  267. <script type="text/javascript" src="/path/to/js4"></script>""")
  268. def test_multi_media(self):
  269. ###############################################################
  270. # Multi-media handling for CSS
  271. ###############################################################
  272. # A widget can define CSS media for multiple output media types
  273. class MultimediaWidget(TextInput):
  274. class Media:
  275. css = {
  276. 'screen, print': ('/file1','/file2'),
  277. 'screen': ('/file3',),
  278. 'print': ('/file4',)
  279. }
  280. js = ('/path/to/js1','/path/to/js4')
  281. multimedia = MultimediaWidget()
  282. self.assertEqual(str(multimedia.media), """<link href="/file4" type="text/css" media="print" rel="stylesheet" />
  283. <link href="/file3" type="text/css" media="screen" rel="stylesheet" />
  284. <link href="/file1" type="text/css" media="screen, print" rel="stylesheet" />
  285. <link href="/file2" type="text/css" media="screen, print" rel="stylesheet" />
  286. <script type="text/javascript" src="/path/to/js1"></script>
  287. <script type="text/javascript" src="/path/to/js4"></script>""")
  288. def test_multi_widget(self):
  289. ###############################################################
  290. # Multiwidget media handling
  291. ###############################################################
  292. class MyWidget1(TextInput):
  293. class Media:
  294. css = {
  295. 'all': ('path/to/css1','/path/to/css2')
  296. }
  297. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  298. class MyWidget2(TextInput):
  299. class Media:
  300. css = {
  301. 'all': ('/path/to/css2','/path/to/css3')
  302. }
  303. js = ('/path/to/js1','/path/to/js4')
  304. class MyWidget3(TextInput):
  305. class Media:
  306. css = {
  307. 'all': ('/path/to/css3','path/to/css1')
  308. }
  309. js = ('/path/to/js1','/path/to/js4')
  310. # MultiWidgets have a default media definition that gets all the
  311. # media from the component widgets
  312. class MyMultiWidget(MultiWidget):
  313. def __init__(self, attrs=None):
  314. widgets = [MyWidget1, MyWidget2, MyWidget3]
  315. super(MyMultiWidget, self).__init__(widgets, attrs)
  316. mymulti = MyMultiWidget()
  317. self.assertEqual(str(mymulti.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  318. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  319. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  320. <script type="text/javascript" src="/path/to/js1"></script>
  321. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  322. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  323. <script type="text/javascript" src="/path/to/js4"></script>""")
  324. def test_form_media(self):
  325. ###############################################################
  326. # Media processing for forms
  327. ###############################################################
  328. class MyWidget1(TextInput):
  329. class Media:
  330. css = {
  331. 'all': ('path/to/css1','/path/to/css2')
  332. }
  333. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  334. class MyWidget2(TextInput):
  335. class Media:
  336. css = {
  337. 'all': ('/path/to/css2','/path/to/css3')
  338. }
  339. js = ('/path/to/js1','/path/to/js4')
  340. class MyWidget3(TextInput):
  341. class Media:
  342. css = {
  343. 'all': ('/path/to/css3','path/to/css1')
  344. }
  345. js = ('/path/to/js1','/path/to/js4')
  346. # You can ask a form for the media required by its widgets.
  347. class MyForm(Form):
  348. field1 = CharField(max_length=20, widget=MyWidget1())
  349. field2 = CharField(max_length=20, widget=MyWidget2())
  350. f1 = MyForm()
  351. self.assertEqual(str(f1.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  352. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  353. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  354. <script type="text/javascript" src="/path/to/js1"></script>
  355. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  356. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  357. <script type="text/javascript" src="/path/to/js4"></script>""")
  358. # Form media can be combined to produce a single media definition.
  359. class AnotherForm(Form):
  360. field3 = CharField(max_length=20, widget=MyWidget3())
  361. f2 = AnotherForm()
  362. self.assertEqual(str(f1.media + f2.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  363. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  364. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  365. <script type="text/javascript" src="/path/to/js1"></script>
  366. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  367. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  368. <script type="text/javascript" src="/path/to/js4"></script>""")
  369. # Forms can also define media, following the same rules as widgets.
  370. class FormWithMedia(Form):
  371. field1 = CharField(max_length=20, widget=MyWidget1())
  372. field2 = CharField(max_length=20, widget=MyWidget2())
  373. class Media:
  374. js = ('/some/form/javascript',)
  375. css = {
  376. 'all': ('/some/form/css',)
  377. }
  378. f3 = FormWithMedia()
  379. self.assertEqual(str(f3.media), """<link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  380. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  381. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  382. <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />
  383. <script type="text/javascript" src="/path/to/js1"></script>
  384. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  385. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  386. <script type="text/javascript" src="/path/to/js4"></script>
  387. <script type="text/javascript" src="/some/form/javascript"></script>""")
  388. # Media works in templates
  389. from django.template import Template, Context
  390. self.assertEqual(Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3})), """<script type="text/javascript" src="/path/to/js1"></script>
  391. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  392. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  393. <script type="text/javascript" src="/path/to/js4"></script>
  394. <script type="text/javascript" src="/some/form/javascript"></script><link href="http://media.example.com/media/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  395. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  396. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  397. <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />""")
  398. class StaticFormsMediaTestCase(TestCase):
  399. # Tests for the media handling on widgets and forms
  400. def setUp(self):
  401. super(StaticFormsMediaTestCase, self).setUp()
  402. self.original_media_url = settings.MEDIA_URL
  403. self.original_static_url = settings.STATIC_URL
  404. settings.MEDIA_URL = 'http://media.example.com/static/'
  405. settings.STATIC_URL = 'http://media.example.com/static/'
  406. def tearDown(self):
  407. settings.MEDIA_URL = self.original_media_url
  408. settings.STATIC_URL = self.original_static_url
  409. super(StaticFormsMediaTestCase, self).tearDown()
  410. def test_construction(self):
  411. # Check construction of media objects
  412. m = Media(css={'all': ('path/to/css1','/path/to/css2')}, js=('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3'))
  413. self.assertEqual(str(m), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  414. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  415. <script type="text/javascript" src="/path/to/js1"></script>
  416. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  417. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  418. class Foo:
  419. css = {
  420. 'all': ('path/to/css1','/path/to/css2')
  421. }
  422. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  423. m3 = Media(Foo)
  424. self.assertEqual(str(m3), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  425. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  426. <script type="text/javascript" src="/path/to/js1"></script>
  427. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  428. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  429. # A widget can exist without a media definition
  430. class MyWidget(TextInput):
  431. pass
  432. w = MyWidget()
  433. self.assertEqual(str(w.media), '')
  434. def test_media_dsl(self):
  435. ###############################################################
  436. # DSL Class-based media definitions
  437. ###############################################################
  438. # A widget can define media if it needs to.
  439. # Any absolute path will be preserved; relative paths are combined
  440. # with the value of settings.MEDIA_URL
  441. class MyWidget1(TextInput):
  442. class Media:
  443. css = {
  444. 'all': ('path/to/css1','/path/to/css2')
  445. }
  446. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  447. w1 = MyWidget1()
  448. self.assertEqual(str(w1.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  449. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  450. <script type="text/javascript" src="/path/to/js1"></script>
  451. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  452. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  453. # Media objects can be interrogated by media type
  454. self.assertEqual(str(w1.media['css']), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  455. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />""")
  456. self.assertEqual(str(w1.media['js']), """<script type="text/javascript" src="/path/to/js1"></script>
  457. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  458. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  459. def test_combine_media(self):
  460. # Media objects can be combined. Any given media resource will appear only
  461. # once. Duplicated media definitions are ignored.
  462. class MyWidget1(TextInput):
  463. class Media:
  464. css = {
  465. 'all': ('path/to/css1','/path/to/css2')
  466. }
  467. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  468. class MyWidget2(TextInput):
  469. class Media:
  470. css = {
  471. 'all': ('/path/to/css2','/path/to/css3')
  472. }
  473. js = ('/path/to/js1','/path/to/js4')
  474. class MyWidget3(TextInput):
  475. class Media:
  476. css = {
  477. 'all': ('/path/to/css3','path/to/css1')
  478. }
  479. js = ('/path/to/js1','/path/to/js4')
  480. w1 = MyWidget1()
  481. w2 = MyWidget2()
  482. w3 = MyWidget3()
  483. self.assertEqual(str(w1.media + w2.media + w3.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  484. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  485. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  486. <script type="text/javascript" src="/path/to/js1"></script>
  487. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  488. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  489. <script type="text/javascript" src="/path/to/js4"></script>""")
  490. # Check that media addition hasn't affected the original objects
  491. self.assertEqual(str(w1.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  492. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  493. <script type="text/javascript" src="/path/to/js1"></script>
  494. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  495. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  496. # Regression check for #12879: specifying the same CSS or JS file
  497. # multiple times in a single Media instance should result in that file
  498. # only being included once.
  499. class MyWidget4(TextInput):
  500. class Media:
  501. css = {'all': ('/path/to/css1', '/path/to/css1')}
  502. js = ('/path/to/js1', '/path/to/js1')
  503. w4 = MyWidget4()
  504. self.assertEqual(str(w4.media), """<link href="/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  505. <script type="text/javascript" src="/path/to/js1"></script>""")
  506. def test_media_property(self):
  507. ###############################################################
  508. # Property-based media definitions
  509. ###############################################################
  510. # Widget media can be defined as a property
  511. class MyWidget4(TextInput):
  512. def _media(self):
  513. return Media(css={'all': ('/some/path',)}, js = ('/some/js',))
  514. media = property(_media)
  515. w4 = MyWidget4()
  516. self.assertEqual(str(w4.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
  517. <script type="text/javascript" src="/some/js"></script>""")
  518. # Media properties can reference the media of their parents
  519. class MyWidget5(MyWidget4):
  520. def _media(self):
  521. return super(MyWidget5, self).media + Media(css={'all': ('/other/path',)}, js = ('/other/js',))
  522. media = property(_media)
  523. w5 = MyWidget5()
  524. self.assertEqual(str(w5.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
  525. <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
  526. <script type="text/javascript" src="/some/js"></script>
  527. <script type="text/javascript" src="/other/js"></script>""")
  528. def test_media_property_parent_references(self):
  529. # Media properties can reference the media of their parents,
  530. # even if the parent media was defined using a class
  531. class MyWidget1(TextInput):
  532. class Media:
  533. css = {
  534. 'all': ('path/to/css1','/path/to/css2')
  535. }
  536. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  537. class MyWidget6(MyWidget1):
  538. def _media(self):
  539. return super(MyWidget6, self).media + Media(css={'all': ('/other/path',)}, js = ('/other/js',))
  540. media = property(_media)
  541. w6 = MyWidget6()
  542. self.assertEqual(str(w6.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  543. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  544. <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
  545. <script type="text/javascript" src="/path/to/js1"></script>
  546. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  547. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  548. <script type="text/javascript" src="/other/js"></script>""")
  549. def test_media_inheritance(self):
  550. ###############################################################
  551. # Inheritance of media
  552. ###############################################################
  553. # If a widget extends another but provides no media definition, it inherits the parent widget's media
  554. class MyWidget1(TextInput):
  555. class Media:
  556. css = {
  557. 'all': ('path/to/css1','/path/to/css2')
  558. }
  559. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  560. class MyWidget7(MyWidget1):
  561. pass
  562. w7 = MyWidget7()
  563. self.assertEqual(str(w7.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  564. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  565. <script type="text/javascript" src="/path/to/js1"></script>
  566. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  567. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""")
  568. # If a widget extends another but defines media, it extends the parent widget's media by default
  569. class MyWidget8(MyWidget1):
  570. class Media:
  571. css = {
  572. 'all': ('/path/to/css3','path/to/css1')
  573. }
  574. js = ('/path/to/js1','/path/to/js4')
  575. w8 = MyWidget8()
  576. self.assertEqual(str(w8.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  577. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  578. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  579. <script type="text/javascript" src="/path/to/js1"></script>
  580. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  581. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  582. <script type="text/javascript" src="/path/to/js4"></script>""")
  583. def test_media_inheritance_from_property(self):
  584. # If a widget extends another but defines media, it extends the parents widget's media,
  585. # even if the parent defined media using a property.
  586. class MyWidget1(TextInput):
  587. class Media:
  588. css = {
  589. 'all': ('path/to/css1','/path/to/css2')
  590. }
  591. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  592. class MyWidget4(TextInput):
  593. def _media(self):
  594. return Media(css={'all': ('/some/path',)}, js = ('/some/js',))
  595. media = property(_media)
  596. class MyWidget9(MyWidget4):
  597. class Media:
  598. css = {
  599. 'all': ('/other/path',)
  600. }
  601. js = ('/other/js',)
  602. w9 = MyWidget9()
  603. self.assertEqual(str(w9.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
  604. <link href="/other/path" type="text/css" media="all" rel="stylesheet" />
  605. <script type="text/javascript" src="/some/js"></script>
  606. <script type="text/javascript" src="/other/js"></script>""")
  607. # A widget can disable media inheritance by specifying 'extend=False'
  608. class MyWidget10(MyWidget1):
  609. class Media:
  610. extend = False
  611. css = {
  612. 'all': ('/path/to/css3','path/to/css1')
  613. }
  614. js = ('/path/to/js1','/path/to/js4')
  615. w10 = MyWidget10()
  616. self.assertEqual(str(w10.media), """<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  617. <link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  618. <script type="text/javascript" src="/path/to/js1"></script>
  619. <script type="text/javascript" src="/path/to/js4"></script>""")
  620. def test_media_inheritance_extends(self):
  621. # A widget can explicitly enable full media inheritance by specifying 'extend=True'
  622. class MyWidget1(TextInput):
  623. class Media:
  624. css = {
  625. 'all': ('path/to/css1','/path/to/css2')
  626. }
  627. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  628. class MyWidget11(MyWidget1):
  629. class Media:
  630. extend = True
  631. css = {
  632. 'all': ('/path/to/css3','path/to/css1')
  633. }
  634. js = ('/path/to/js1','/path/to/js4')
  635. w11 = MyWidget11()
  636. self.assertEqual(str(w11.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  637. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  638. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  639. <script type="text/javascript" src="/path/to/js1"></script>
  640. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  641. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  642. <script type="text/javascript" src="/path/to/js4"></script>""")
  643. def test_media_inheritance_single_type(self):
  644. # A widget can enable inheritance of one media type by specifying extend as a tuple
  645. class MyWidget1(TextInput):
  646. class Media:
  647. css = {
  648. 'all': ('path/to/css1','/path/to/css2')
  649. }
  650. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  651. class MyWidget12(MyWidget1):
  652. class Media:
  653. extend = ('css',)
  654. css = {
  655. 'all': ('/path/to/css3','path/to/css1')
  656. }
  657. js = ('/path/to/js1','/path/to/js4')
  658. w12 = MyWidget12()
  659. self.assertEqual(str(w12.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  660. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  661. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  662. <script type="text/javascript" src="/path/to/js1"></script>
  663. <script type="text/javascript" src="/path/to/js4"></script>""")
  664. def test_multi_media(self):
  665. ###############################################################
  666. # Multi-media handling for CSS
  667. ###############################################################
  668. # A widget can define CSS media for multiple output media types
  669. class MultimediaWidget(TextInput):
  670. class Media:
  671. css = {
  672. 'screen, print': ('/file1','/file2'),
  673. 'screen': ('/file3',),
  674. 'print': ('/file4',)
  675. }
  676. js = ('/path/to/js1','/path/to/js4')
  677. multimedia = MultimediaWidget()
  678. self.assertEqual(str(multimedia.media), """<link href="/file4" type="text/css" media="print" rel="stylesheet" />
  679. <link href="/file3" type="text/css" media="screen" rel="stylesheet" />
  680. <link href="/file1" type="text/css" media="screen, print" rel="stylesheet" />
  681. <link href="/file2" type="text/css" media="screen, print" rel="stylesheet" />
  682. <script type="text/javascript" src="/path/to/js1"></script>
  683. <script type="text/javascript" src="/path/to/js4"></script>""")
  684. def test_multi_widget(self):
  685. ###############################################################
  686. # Multiwidget media handling
  687. ###############################################################
  688. class MyWidget1(TextInput):
  689. class Media:
  690. css = {
  691. 'all': ('path/to/css1','/path/to/css2')
  692. }
  693. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  694. class MyWidget2(TextInput):
  695. class Media:
  696. css = {
  697. 'all': ('/path/to/css2','/path/to/css3')
  698. }
  699. js = ('/path/to/js1','/path/to/js4')
  700. class MyWidget3(TextInput):
  701. class Media:
  702. css = {
  703. 'all': ('/path/to/css3','path/to/css1')
  704. }
  705. js = ('/path/to/js1','/path/to/js4')
  706. # MultiWidgets have a default media definition that gets all the
  707. # media from the component widgets
  708. class MyMultiWidget(MultiWidget):
  709. def __init__(self, attrs=None):
  710. widgets = [MyWidget1, MyWidget2, MyWidget3]
  711. super(MyMultiWidget, self).__init__(widgets, attrs)
  712. mymulti = MyMultiWidget()
  713. self.assertEqual(str(mymulti.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  714. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  715. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  716. <script type="text/javascript" src="/path/to/js1"></script>
  717. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  718. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  719. <script type="text/javascript" src="/path/to/js4"></script>""")
  720. def test_form_media(self):
  721. ###############################################################
  722. # Media processing for forms
  723. ###############################################################
  724. class MyWidget1(TextInput):
  725. class Media:
  726. css = {
  727. 'all': ('path/to/css1','/path/to/css2')
  728. }
  729. js = ('/path/to/js1','http://media.other.com/path/to/js2','https://secure.other.com/path/to/js3')
  730. class MyWidget2(TextInput):
  731. class Media:
  732. css = {
  733. 'all': ('/path/to/css2','/path/to/css3')
  734. }
  735. js = ('/path/to/js1','/path/to/js4')
  736. class MyWidget3(TextInput):
  737. class Media:
  738. css = {
  739. 'all': ('/path/to/css3','path/to/css1')
  740. }
  741. js = ('/path/to/js1','/path/to/js4')
  742. # You can ask a form for the media required by its widgets.
  743. class MyForm(Form):
  744. field1 = CharField(max_length=20, widget=MyWidget1())
  745. field2 = CharField(max_length=20, widget=MyWidget2())
  746. f1 = MyForm()
  747. self.assertEqual(str(f1.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  748. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  749. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  750. <script type="text/javascript" src="/path/to/js1"></script>
  751. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  752. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  753. <script type="text/javascript" src="/path/to/js4"></script>""")
  754. # Form media can be combined to produce a single media definition.
  755. class AnotherForm(Form):
  756. field3 = CharField(max_length=20, widget=MyWidget3())
  757. f2 = AnotherForm()
  758. self.assertEqual(str(f1.media + f2.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  759. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  760. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  761. <script type="text/javascript" src="/path/to/js1"></script>
  762. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  763. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  764. <script type="text/javascript" src="/path/to/js4"></script>""")
  765. # Forms can also define media, following the same rules as widgets.
  766. class FormWithMedia(Form):
  767. field1 = CharField(max_length=20, widget=MyWidget1())
  768. field2 = CharField(max_length=20, widget=MyWidget2())
  769. class Media:
  770. js = ('/some/form/javascript',)
  771. css = {
  772. 'all': ('/some/form/css',)
  773. }
  774. f3 = FormWithMedia()
  775. self.assertEqual(str(f3.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  776. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  777. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  778. <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />
  779. <script type="text/javascript" src="/path/to/js1"></script>
  780. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  781. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  782. <script type="text/javascript" src="/path/to/js4"></script>
  783. <script type="text/javascript" src="/some/form/javascript"></script>""")
  784. # Media works in templates
  785. from django.template import Template, Context
  786. self.assertEqual(Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3})), """<script type="text/javascript" src="/path/to/js1"></script>
  787. <script type="text/javascript" src="http://media.other.com/path/to/js2"></script>
  788. <script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>
  789. <script type="text/javascript" src="/path/to/js4"></script>
  790. <script type="text/javascript" src="/some/form/javascript"></script><link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
  791. <link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
  792. <link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
  793. <link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />""")