# HG changeset patch # User Adrien Di Mascio # Date 1302098479 -7200 # Node ID 496f51b9215412816843cec3cb1ef9d52ea40803 # Parent 59d953d8694e1ca02b6a55fda510c49ce68ad856 [views] extend HTMLStream API to be able to change doctype / xmldecl When generating RDFa (for instance), the doctype must be : This changeset adds a ``set_doctype()`` method on request objects to allow such changes during page generation. diff -r 59d953d8694e -r 496f51b92154 utils.py --- a/utils.py Wed Apr 06 10:10:21 2011 +0200 +++ b/utils.py Wed Apr 06 16:01:19 2011 +0200 @@ -361,17 +361,43 @@ self.doctype = u'' # xmldecl and html opening tag self.xmldecl = u'\n' % req.encoding - self.htmltag = u'' % (req.lang, req.lang) + self._namespaces = [('xmlns', 'http://www.w3.org/1999/xhtml'), + ('xmlns:cubicweb','http://www.logilab.org/2008/cubicweb')] + self._htmlattrs = [('xml:lang', req.lang), + ('lang', req.lang)] # keep main_stream's reference on req for easier text/html demoting req.main_stream = self + def add_namespace(self, prefix, uri): + self._namespaces.append( (prefix, uri) ) + + def set_namespaces(self, namespaces): + self._namespaces = namespaces + + def add_htmlattr(self, attrname, attrvalue): + self._htmlattrs.append( (attrname, attrvalue) ) + + def set_htmlattrs(self, attrs): + self._htmlattrs = attrs + + def set_doctype(self, doctype, reset_xmldecl=True): + self.doctype = doctype + if reset_xmldecl: + self.xmldecl = u'' + def write(self, data): """StringIO interface: this method will be assigned to self.w """ self.body.write(data) + @property + def htmltag(self): + attrs = ' '.join('%s="%s"' % (attr, xml_escape(value)) + for attr, value in (self._namespaces + self._htmlattrs)) + if attrs: + return '' % attrs + return '' + def getvalue(self): """writes HTML headers, closes tag and writes HTML body""" return u'%s\n%s\n%s\n%s\n%s\n' % (self.xmldecl, self.doctype, @@ -379,7 +405,6 @@ self.head.getvalue(), self.body.getvalue()) - try: # may not be there if cubicweb-web not installed if sys.version_info < (2, 6): diff -r 59d953d8694e -r 496f51b92154 web/request.py --- a/web/request.py Wed Apr 06 10:10:21 2011 +0200 +++ b/web/request.py Wed Apr 06 16:01:19 2011 +0200 @@ -756,8 +756,16 @@ will display '<[' at the beginning of the page """ self.set_content_type('text/html') - self.main_stream.doctype = TRANSITIONAL_DOCTYPE_NOEXT - self.main_stream.xmldecl = u'' + self.main_stream.set_doctype(TRANSITIONAL_DOCTYPE_NOEXT) + + def set_doctype(self, doctype, reset_xmldecl=True): + """helper method to dynamically change page doctype + + :param doctype: the new doctype, e.g. '' + :param reset_xmldecl: if True, remove the '' + declaration from the page + """ + self.main_stream.set_doctype(doctype, reset_xmldecl) # page data management #################################################### diff -r 59d953d8694e -r 496f51b92154 web/test/unittest_views_baseviews.py --- a/web/test/unittest_views_baseviews.py Wed Apr 06 10:10:21 2011 +0200 +++ b/web/test/unittest_views_baseviews.py Wed Apr 06 16:01:19 2011 +0200 @@ -16,11 +16,14 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . +from __future__ import with_statement + from logilab.common.testlib import unittest_main from logilab.mtconverter import html_unescape from cubicweb.devtools.testlib import CubicWebTC from cubicweb.utils import json +from cubicweb.view import StartupView, TRANSITIONAL_DOCTYPE_NOEXT from cubicweb.web.htmlwidgets import TableWidget from cubicweb.web.views import vid_from_rset @@ -125,5 +128,47 @@ self.assertListEqual(got, expected) +class HTMLStreamTests(CubicWebTC): + + def test_set_doctype_reset_xmldecl(self): + """ + tests `cubicweb.web.request.CubicWebRequestBase.set_doctype` + with xmldecl reset + """ + class MyView(StartupView): + __regid__ = 'my-view' + def call(self): + self._cw.set_doctype('') + + with self.temporary_appobjects(MyView): + html_source = self.view('my-view').source + source_lines = [line.strip() for line in html_source.splitlines(False) + if line.strip()] + self.assertListEqual(source_lines[:2], + ['', + '']) + + def test_set_doctype_no_reset_xmldecl(self): + """ + tests `cubicweb.web.request.CubicWebRequestBase.set_doctype` + with no xmldecl reset + """ + html_doctype = TRANSITIONAL_DOCTYPE_NOEXT.strip() + class MyView(StartupView): + __regid__ = 'my-view' + def call(self): + self._cw.set_doctype(html_doctype, reset_xmldecl=False) + self._cw.main_stream.set_namespaces([('xmlns', 'http://www.w3.org/1999/xhtml')]) + self._cw.main_stream.set_htmlattrs([('lang', 'cz')]) + + with self.temporary_appobjects(MyView): + html_source = self.view('my-view').source + source_lines = [line.strip() for line in html_source.splitlines(False) + if line.strip()] + self.assertListEqual(source_lines[:3], + ['', + html_doctype, + '']) + if __name__ == '__main__': unittest_main()