diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index e4ff6e6..cb453df 100644
a
|
b
|
class Feed(object):
|
138 | 138 | feed_copyright=self.__get_dynamic_attr('feed_copyright', obj), |
139 | 139 | feed_guid=self.__get_dynamic_attr('feed_guid', obj), |
140 | 140 | ttl=self.__get_dynamic_attr('ttl', obj), |
| 141 | stylesheets = self.__get_dynamic_attr('stylesheets', obj), |
141 | 142 | **self.feed_extra_kwargs(obj) |
142 | 143 | ) |
143 | 144 | |
diff --git a/django/utils/feedgenerator.py b/django/utils/feedgenerator.py
index 52c0ecc..ac94d37 100644
a
|
b
|
class SyndicationFeed(object):
|
87 | 87 | "Base class for all syndication feeds. Subclasses should provide write()" |
88 | 88 | def __init__(self, title, link, description, language=None, author_email=None, |
89 | 89 | author_name=None, author_link=None, subtitle=None, categories=None, |
90 | | feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, **kwargs): |
| 90 | feed_url=None, feed_copyright=None, feed_guid=None, ttl=None, stylesheets=None, **kwargs): |
91 | 91 | to_unicode = lambda s: force_text(s, strings_only=True) |
92 | 92 | if categories: |
93 | 93 | categories = [force_text(c) for c in categories] |
94 | 94 | if ttl is not None: |
95 | 95 | # Force ints to unicode |
96 | 96 | ttl = force_text(ttl) |
| 97 | if stylesheets: |
| 98 | stylesheets = [iri_to_uri(s) for s in stylesheets] |
97 | 99 | self.feed = { |
98 | 100 | 'title': to_unicode(title), |
99 | 101 | 'link': iri_to_uri(link), |
… |
… |
class SyndicationFeed(object):
|
108 | 110 | 'feed_copyright': to_unicode(feed_copyright), |
109 | 111 | 'id': feed_guid or link, |
110 | 112 | 'ttl': ttl, |
| 113 | 'stylesheets': stylesheets or (), |
111 | 114 | } |
112 | 115 | self.feed.update(kwargs) |
113 | 116 | self.items = [] |
… |
… |
class RssFeed(SyndicationFeed):
|
223 | 226 | def write(self, outfile, encoding): |
224 | 227 | handler = SimplerXMLGenerator(outfile, encoding) |
225 | 228 | handler.startDocument() |
| 229 | for s in self.feed['stylesheets']: |
| 230 | # http://www.w3.org/TR/xml-stylesheet/ |
| 231 | handler.processingInstruction('xml-stylesheet', 'type="text/css" href="%s"' % s) |
226 | 232 | handler.startElement("rss", self.rss_attributes()) |
227 | 233 | handler.startElement("channel", self.root_attributes()) |
228 | 234 | self.add_root_elements(handler) |
… |
… |
class Atom1Feed(SyndicationFeed):
|
322 | 328 | def write(self, outfile, encoding): |
323 | 329 | handler = SimplerXMLGenerator(outfile, encoding) |
324 | 330 | handler.startDocument() |
| 331 | for s in self.feed['stylesheets']: |
| 332 | # http://www.w3.org/TR/xml-stylesheet/ |
| 333 | handler.processingInstruction('xml-stylesheet', 'type="text/css" href="%s"' % s) |
325 | 334 | handler.startElement('feed', self.root_attributes()) |
326 | 335 | self.add_root_elements(handler) |
327 | 336 | self.write_items(handler) |
diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt
index 7e31eb0..9a213b6 100644
a
|
b
|
Atom feeds require a ``<link rel="self">`` that defines the feed's current
|
323 | 323 | location. The syndication framework populates this automatically, using the |
324 | 324 | domain of the current site according to the :setting:`SITE_ID` setting. |
325 | 325 | |
| 326 | Stylesheets |
| 327 | ----------- |
| 328 | |
| 329 | .. versionadded:: 1.8 |
| 330 | |
| 331 | RSS and Atom feeds support the inclusion of stylesheets via the ``stylesheets`` |
| 332 | attribute, as a sequence of stylesheets to be added to the feed. |
| 333 | |
326 | 334 | Publishing Atom and RSS feeds in tandem |
327 | 335 | --------------------------------------- |
328 | 336 | |
… |
… |
This example illustrates all possible attributes and methods for a
|
587 | 595 | |
588 | 596 | ttl = 600 # Hard-coded Time To Live. |
589 | 597 | |
| 598 | stylesheets = ('http://www.example.com/example.css',) # Hard-coded stylesheets to be added to feed |
| 599 | |
590 | 600 | # ITEMS -- One of the following three is required. The framework looks |
591 | 601 | # for them in this order. |
592 | 602 | |
… |
… |
They share this interface:
|
914 | 924 | * ``feed_copyright`` |
915 | 925 | * ``feed_guid`` |
916 | 926 | * ``ttl`` |
| 927 | * ``stylesheets`` |
917 | 928 | |
918 | 929 | Any extra keyword arguments you pass to ``__init__`` will be stored in |
919 | 930 | ``self.feed`` for use with `custom feed generators`_. |
920 | 931 | |
921 | | All parameters should be Unicode objects, except ``categories``, which |
922 | | should be a sequence of Unicode objects. |
| 932 | All parameters should be Unicode objects, except ``categories`` and |
| 933 | ``stylesheets``, which should be sequences of Unicode objects. |
923 | 934 | |
924 | 935 | :meth:`.SyndicationFeed.add_item` |
925 | 936 | Add an item to the feed with the given parameters. |
diff --git a/tests/syndication_tests/tests.py b/tests/syndication_tests/tests.py
index 8da3d5e..33952ea 100644
a
|
b
|
class SyndicationFeedTest(FeedTestCase):
|
70 | 70 | feed = feed_elem[0] |
71 | 71 | self.assertEqual(feed.getAttribute('version'), '2.0') |
72 | 72 | |
| 73 | # Verify document has a stylesheet element (processing instruction <?xml-stylesheet ... ?>) |
| 74 | self.assertEqual(doc.firstChild.target, 'xml-stylesheet') |
| 75 | self.assertEqual(doc.firstChild.data, 'type="text/css" href="http://www.example.com/example.css"') |
| 76 | |
73 | 77 | # Making sure there's only one `channel` element w/in the |
74 | 78 | # `rss` element. |
75 | 79 | chan_elem = feed.getElementsByTagName('channel') |