drop xhtml content-type support (closes #2065651)

  • HTMLStream does not care about xml any more
  • reqquest.demote_to_html and .xhtml_browser are deprecated
  • web config: drop force-html-content-type option
  • adjust tests
authorAurelien Campeas <aurelien.campeas@logilab.fr>
changeset7b26fe71404f
branchdefault
phasepublic
hiddenno
parent revision#ae898a084da2 [htmlparser] exclude <script> tag from html source
child revision#8bf959e7c405 [schema/bootstrap|syncschema|schemaserial] store default attribute values in a Bytes field, allowing arbitrary python objects as default values (closes #2414591), #d95e1a6e78e6 fix typo in notification causing NameError, #0f60f1061a2e [test] stop deepcopying for nothing
files modified by this revision
devtools/htmlparser.py
devtools/httptest.py
devtools/test/unittest_testlib.py
utils.py
view.py
web/data/cubicweb.edition.js
web/request.py
web/test/test_views.py
web/test/unittest_idownloadable.py
web/test/unittest_views_basecontrollers.py
web/test/unittest_views_baseviews.py
web/views/calendar.py
web/webconfig.py
# HG changeset patch
# User Aurelien Campeas <aurelien.campeas@logilab.fr>
# Date 1366971037 -7200
# Fri Apr 26 12:10:37 2013 +0200
# Node ID 7b26fe71404f8e3899c588482bff1b687271ee37
# Parent ae898a084da2aeb55531523fc9977714f66f711d
drop xhtml content-type support (closes #2065651)

* HTMLStream does not care about xml any more

* reqquest.demote_to_html and .xhtml_browser are deprecated

* web config: drop force-html-content-type option

* adjust tests

diff --git a/devtools/htmlparser.py b/devtools/htmlparser.py
@@ -37,11 +37,11 @@
1          try:
2              return PageInfo(self, data)
3          except etree.XMLSyntaxError as exc:
4              def save_in(fname=''):
5                  file(fname, 'w').write(data)
6 -            new_exc = AssertionError(u'invalid xml %s' % exc)
7 +            new_exc = AssertionError(u'invalid document: %s' % exc)
8              new_exc.position = exc.position
9              raise new_exc
10 
11      def preprocess_data(self, data):
12          return data
diff --git a/devtools/httptest.py b/devtools/httptest.py
@@ -76,14 +76,10 @@
13          return 'http://127.0.0.1:%d/' % self['port']
14 
15      def pyro_enabled(self):
16          return False
17 
18 -    def load_configuration(self):
19 -        super(CubicWebServerConfig, self).load_configuration()
20 -        self.global_set_option('force-html-content-type', True)
21 -
22 
23  class CubicWebServerTC(CubicWebTC):
24      """Class for running test web server. See :class:`CubicWebServerConfig`.
25 
26      Class attributes:
diff --git a/devtools/test/unittest_testlib.py b/devtools/test/unittest_testlib.py
@@ -95,11 +95,13 @@
27 
28 
29  class HTMLPageInfoTC(TestCase):
30      """test cases for PageInfo"""
31      def setUp(self):
32 -        parser = htmlparser.DTDValidator()
33 +        parser = htmlparser.HTMLValidator()
34 +        # disable cleanup that would remove doctype
35 +        parser.preprocess_data = lambda data: data
36          self.page_info = parser.parse_string(HTML_PAGE2)
37 
38      def test_source1(self):
39          """make sure source is stored correctly"""
40          self.assertEqual(self.page_info.source, HTML_PAGE2)
diff --git a/utils.py b/utils.py
@@ -227,15 +227,12 @@
41      """
42      js_unload_code = u'''if (typeof(pageDataUnloaded) == 'undefined') {
43      jQuery(window).unload(unloadPageData);
44      pageDataUnloaded = true;
45  }'''
46 -    # Making <script> tag content work properly with all possible
47 -    # content-types (xml/html) and all possible browsers is very
48 -    # tricky, see http://www.hixie.ch/advocacy/xhtml for an in-depth discussion
49 -    xhtml_safe_script_opening = u'<script type="text/javascript"><!--//--><![CDATA[//><!--\n'
50 -    xhtml_safe_script_closing = u'\n//--><!]]></script>'
51 +    script_opening = u'<script type="text/javascript">\n'
52 +    script_closing = u'\n</script>'
53 
54      def __init__(self, req):
55          super(HTMLHead, self).__init__()
56          self.jsvars = []
57          self.jsfiles = []
@@ -342,18 +339,18 @@
58          resources declaration
59          """
60          w = self.write
61          # 1/ variable declaration if any
62          if self.jsvars:
63 -            w(self.xhtml_safe_script_opening)
64 +            w(self.script_opening)
65              for var, value, override in self.jsvars:
66                  vardecl = u'%s = %s;' % (var, json.dumps(value))
67                  if not override:
68                      vardecl = (u'if (typeof %s == "undefined") {%s}' %
69                                 (var, vardecl))
70                  w(vardecl + u'\n')
71 -            w(self.xhtml_safe_script_closing)
72 +            w(self.script_closing)
73          # 2/ css files
74          ie_cssfiles = ((x, (y, z)) for x, y, z in self.ie_cssfiles)
75          if self.datadir_url and self._cw.vreg.config['concat-resources']:
76              cssfiles = self.group_urls(self.cssfiles)
77              ie_cssfiles = self.group_urls(ie_cssfiles)
@@ -395,13 +392,13 @@
78                  for script in self.post_inlined_scripts:
79                      w(u'<pre class="script">')
80                      w(xml_escape(script))
81                      w(u'</pre>')
82              else:
83 -                w(self.xhtml_safe_script_opening)
84 +                w(self.script_opening)
85                  w(u'\n\n'.join(self.post_inlined_scripts))
86 -                w(self.xhtml_safe_script_closing)
87 +                w(self.script_closing)
88          header = super(HTMLHead, self).getvalue()
89          if skiphead:
90              return header
91          return u'<head>\n%s</head>\n' % header
92 
@@ -420,55 +417,53 @@
93          # stream for <head>
94          self.head = req.html_headers
95          # main stream
96          self.body = UStringIO()
97          self.doctype = u''
98 -        # xmldecl and html opening tag
99 -        self.xmldecl = u'<?xml version="1.0" encoding="%s"?>\n' % req.encoding
100 -        self._namespaces = [('xmlns', 'http://www.w3.org/1999/xhtml'),
101 -                            ('xmlns:cubicweb','http://www.logilab.org/2008/cubicweb')]
102 -        self._htmlattrs = [('xml:lang', req.lang),
103 -                           ('lang', req.lang)]
104 +        self._htmlattrs = [('lang', req.lang)]
105          # keep main_stream's reference on req for easier text/html demoting
106          req.main_stream = self
107 
108 +    @deprecated('[3.17] there are no namespaces in html, xhtml is not served any longer')
109      def add_namespace(self, prefix, uri):
110 -        self._namespaces.append( (prefix, uri) )
111 +        pass
112 
113 +    @deprecated('[3.17] there are no namespaces in html, xhtml is not served any longer')
114      def set_namespaces(self, namespaces):
115 -        self._namespaces = namespaces
116 +        pass
117 
118      def add_htmlattr(self, attrname, attrvalue):
119          self._htmlattrs.append( (attrname, attrvalue) )
120 
121      def set_htmlattrs(self, attrs):
122          self._htmlattrs = attrs
123 
124 -    def set_doctype(self, doctype, reset_xmldecl=True):
125 +    def set_doctype(self, doctype, reset_xmldecl=None):
126          self.doctype = doctype
127 -        if reset_xmldecl:
128 -            self.xmldecl = u''
129 +        if reset_xmldecl is not None:
130 +            warn('[3.17] xhtml is no more supported',
131 +                 DeprecationWarning, stacklevel=2)
132 
133      def write(self, data):
134          """StringIO interface: this method will be assigned to self.w
135          """
136          self.body.write(data)
137 
138      @property
139      def htmltag(self):
140          attrs = ' '.join('%s="%s"' % (attr, xml_escape(value))
141 -                         for attr, value in (self._namespaces + self._htmlattrs))
142 +                         for attr, value in self._htmlattrs)
143          if attrs:
144              return '<html %s>' % attrs
145          return '<html>'
146 
147      def getvalue(self):
148          """writes HTML headers, closes </head> tag and writes HTML body"""
149 -        return u'%s\n%s\n%s\n%s\n%s\n</html>' % (self.xmldecl, self.doctype,
150 -                                                 self.htmltag,
151 -                                                 self.head.getvalue(),
152 -                                                 self.body.getvalue())
153 +        return u'%s\n%s\n%s\n%s\n</html>' % (self.doctype,
154 +                                             self.htmltag,
155 +                                             self.head.getvalue(),
156 +                                             self.body.getvalue())
157 
158  try:
159      # may not be there if cubicweb-web not installed
160      if sys.version_info < (2, 6):
161          import simplejson as json
diff --git a/view.py b/view.py
@@ -40,54 +40,15 @@
162 
163  # robots control
164  NOINDEX = u'<meta name="ROBOTS" content="NOINDEX" />'
165  NOFOLLOW = u'<meta name="ROBOTS" content="NOFOLLOW" />'
166 
167 -CW_XHTML_EXTENSIONS = '''[
168 -  <!ATTLIST html xmlns:cubicweb CDATA  #FIXED \'http://www.logilab.org/2008/cubicweb\'  >
169 -
170 -<!ENTITY % coreattrs
171 - "id          ID            #IMPLIED
172 -  class       CDATA         #IMPLIED
173 -  style       CDATA         #IMPLIED
174 -  title       CDATA         #IMPLIED
175 +TRANSITIONAL_DOCTYPE_NOEXT = u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n'
176 +TRANSITIONAL_DOCTYPE = TRANSITIONAL_DOCTYPE_NOEXT # bw compat
177 
178 - cubicweb:accesskey         CDATA   #IMPLIED
179 - cubicweb:actualrql         CDATA   #IMPLIED
180 - cubicweb:dataurl           CDATA   #IMPLIED
181 - cubicweb:facetName         CDATA   #IMPLIED
182 - cubicweb:facetargs         CDATA   #IMPLIED
183 - cubicweb:fallbackvid       CDATA   #IMPLIED
184 - cubicweb:fname             CDATA   #IMPLIED
185 - cubicweb:initfunc          CDATA   #IMPLIED
186 - cubicweb:inputid           CDATA   #IMPLIED
187 - cubicweb:inputname         CDATA   #IMPLIED
188 - cubicweb:limit             CDATA   #IMPLIED
189 - cubicweb:loadtype          CDATA   #IMPLIED
190 - cubicweb:loadurl           CDATA   #IMPLIED
191 - cubicweb:maxlength         CDATA   #IMPLIED
192 - cubicweb:required          CDATA   #IMPLIED
193 - cubicweb:rooteid           CDATA   #IMPLIED
194 - cubicweb:rql               CDATA   #IMPLIED
195 - cubicweb:size              CDATA   #IMPLIED
196 - cubicweb:sortvalue         CDATA   #IMPLIED
197 - cubicweb:target            CDATA   #IMPLIED
198 - cubicweb:tindex            CDATA   #IMPLIED
199 - cubicweb:tlunit            CDATA   #IMPLIED
200 - cubicweb:type              CDATA   #IMPLIED
201 - cubicweb:unselimg          CDATA   #IMPLIED
202 - cubicweb:uselabel          CDATA   #IMPLIED
203 - cubicweb:value             CDATA   #IMPLIED
204 - cubicweb:variables         CDATA   #IMPLIED
205 - cubicweb:vid               CDATA   #IMPLIED
206 - cubicweb:wdgtype           CDATA   #IMPLIED
207 -  "> ] '''
208 -
209 -TRANSITIONAL_DOCTYPE = u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" %s>\n' % CW_XHTML_EXTENSIONS
210 -TRANSITIONAL_DOCTYPE_NOEXT = u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n'
211 -STRICT_DOCTYPE = u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" %s>\n' % CW_XHTML_EXTENSIONS
212  STRICT_DOCTYPE_NOEXT = u'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n'
213 +STRICT_DOCTYPE = STRICT_DOCTYPE_NOEXT # bw compat
214 
215  # base view object ############################################################
216 
217  class View(AppObject):
218      """This class is an abstraction of a view class, used as a base class for
@@ -508,15 +469,11 @@
219      """main template are primary access point to render a full HTML page.
220      There is usually at least a regular main template and a simple fallback
221      one to display error if the first one failed
222      """
223 
224 -    @property
225 -    def doctype(self):
226 -        if self._cw.xhtml_browser():
227 -            return STRICT_DOCTYPE
228 -        return STRICT_DOCTYPE_NOEXT
229 +    doctype = STRICT_DOCTYPE
230 
231      def set_stream(self, w=None):
232          if self.w is not None:
233              return
234          if w is None:
diff --git a/web/data/cubicweb.edition.js b/web/data/cubicweb.edition.js
@@ -541,20 +541,23 @@
235   *
236   * called on load to set target and iframeso object.
237   *
238   * .. note::
239   *
240 - *    this is a hack to make the XHTML compliant.
241 + *    This was a hack to make form loop handling XHTML compliant.
242 + *    Since we do not care about xhtml any longer, this may go away.
243   *
244   * .. note::
245   *
246   *   `object` nodes might be a potential replacement for iframes
247   *
248   * .. note::
249   *
250 - *    there is a XHTML module allowing iframe elements but there
251 - *    is still the problem of the form's `target` attribute
252 + *    The form's `target` attribute should probably become a simple data-target
253 + *    immediately generated server-side.
254 + *    Since we don't do xhtml any longer, the iframe should probably be either
255 + *    reconsidered or at least emitted server-side.
256   */
257  function setFormsTarget(node) {
258      var $node = jQuery(node || document.body);
259      $node.find('form').each(function() {
260          var form = jQuery(this);
diff --git a/web/request.py b/web/request.py
@@ -40,11 +40,11 @@
261  from logilab.mtconverter import xml_escape
262 
263  from cubicweb.dbapi import DBAPIRequest
264  from cubicweb.uilib import remove_html_tags, js
265  from cubicweb.utils import SizeConstrainedList, HTMLHead, make_uid
266 -from cubicweb.view import STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE_NOEXT
267 +from cubicweb.view import TRANSITIONAL_DOCTYPE_NOEXT
268  from cubicweb.web import (INTERNAL_FIELD_VALUE, LOGGER, NothingToEdit,
269                            RequestError, StatusResponse)
270  from cubicweb.web.httpcache import GMTOFFSET, get_validators
271  from cubicweb.web.http_headers import Headers, Cookie, parseDateTime
272 
@@ -900,33 +900,30 @@
273              value_parser = value_sort_key = None
274          accepteds = self.get_header(header, '')
275          values = _parse_accept_header(accepteds, value_parser, value_sort_key)
276          return (raw_value for (raw_value, parsed_value, score) in values)
277 
278 +    @deprecated('[3.17] demote_to_html is deprecated as we always serve html')
279      def demote_to_html(self):
280          """helper method to dynamically set request content type to text/html
281 
282          The global doctype and xmldec must also be changed otherwise the browser
283          will display '<[' at the beginning of the page
284          """
285 -        if not self.vreg.config['force-html-content-type']:
286 -            if not hasattr(self, 'main_stream'):
287 -                raise Exception("Can't demote to html from an ajax context. You "
288 -                                "should change force-html-content-type to yes "
289 -                                "in the instance configuration file.")
290 -            self.set_content_type('text/html')
291 -            self.main_stream.set_doctype(TRANSITIONAL_DOCTYPE_NOEXT)
292 +        pass
293 +
294 
295      # xml doctype #############################################################
296 
297 -    def set_doctype(self, doctype, reset_xmldecl=True):
298 +    def set_doctype(self, doctype, reset_xmldecl=None):
299          """helper method to dynamically change page doctype
300 
301          :param doctype: the new doctype, e.g. '<!DOCTYPE html>'
302 -        :param reset_xmldecl: if True, remove the '<?xml version="1.0"?>'
303 -                              declaration from the page
304          """
305 +        if reset_xmldecl is not None:
306 +            warn('[3.17] reset_xmldecl is deprecated as we only serve html',
307 +                 DeprecationWarning, stacklevel=2)
308          self.main_stream.set_doctype(doctype, reset_xmldecl)
309 
310      # page data management ####################################################
311 
312      def get_page_data(self, key, default=None):
@@ -963,37 +960,24 @@
313 
314      def ie_browser(self):
315          useragent = self.useragent()
316          return useragent and 'MSIE' in useragent
317 
318 +    @deprecated('[3.17] xhtml_browser is deprecated (xhtml is no longer served)')
319      def xhtml_browser(self):
320          """return True if the browser is considered as xhtml compatible.
321 
322          If the instance is configured to always return text/html and not
323          application/xhtml+xml, this method will always return False, even though
324          this is semantically different
325          """
326 -        if self.vreg.config['force-html-content-type']:
327 -            return False
328 -        useragent = self.useragent()
329 -        # * MSIE/Konqueror does not support xml content-type
330 -        # * Opera supports xhtml and handles namespaces properly but it breaks
331 -        #   jQuery.attr()
332 -        if useragent and ('MSIE' in useragent or 'KHTML' in useragent
333 -                          or 'Opera' in useragent):
334 -            return False
335 -        return True
336 +        return False
337 
338      def html_content_type(self):
339 -        if self.xhtml_browser():
340 -            return 'application/xhtml+xml'
341          return 'text/html'
342 
343      def document_surrounding_div(self):
344 -        if self.xhtml_browser():
345 -            return (u'<?xml version="1.0"?>\n' + STRICT_DOCTYPE + # XXX encoding ?
346 -                    u'<div xmlns="http://www.w3.org/1999/xhtml" xmlns:cubicweb="http://www.logilab.org/2008/cubicweb">')
347          return u'<div>'
348 
349      @deprecated('[3.9] use req.uiprops[rid]')
350      def external_resource(self, rid, default=_MARKER):
351          """return a path to an external resource, using its identifier
diff --git a/web/test/test_views.py b/web/test/test_views.py
@@ -1,6 +1,6 @@
352 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
353 +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
354  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
355  #
356  # This file is part of CubicWeb.
357  #
358  # CubicWeb is free software: you can redistribute it and/or modify it under the
@@ -14,11 +14,11 @@
359  # details.
360  #
361  # You should have received a copy of the GNU Lesser General Public License along
362  # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
363  """automatic tests"""
364 -
365 +from cubicweb.devtools import htmlparser
366  from cubicweb.devtools.testlib import CubicWebTC, AutoPopulateTest, AutomaticWebTest
367  from cubicweb.view import AnyRsetView
368 
369  class AutomaticWebTest(AutomaticWebTest):
370      application_rql = [
@@ -49,11 +49,11 @@
371          rset = self.execute('CWUser X')
372          # sortable.js should not be included by default
373          self.assertFalse('jquery.tablesorter.js' in self.view('oneline', rset))
374          # but should be included by the tableview
375          rset = self.execute('Any P,F,S LIMIT 1 WHERE P is CWUser, P firstname F, P surname S')
376 -        self.assertTrue('jquery.tablesorter.js' in self.view('table', rset))
377 +        self.assertIn('jquery.tablesorter.js', self.view('table', rset).source)
378 
379      def test_js_added_only_once(self):
380          self.vreg._loadedmods[__name__] = {}
381          self.vreg.register(SomeView)
382          rset = self.execute('CWUser X')
diff --git a/web/test/unittest_idownloadable.py b/web/test/unittest_idownloadable.py
@@ -144,11 +144,11 @@
383          try:
384              data = self.app_handle_request(req)
385          finally:
386              self.app.error_handler = errhdlr
387          get = req.headers_out.getRawHeaders
388 -        self.assertEqual(['application/xhtml+xml'],
389 +        self.assertEqual(['text/html;charset=UTF-8'],
390                           get('content-type'))
391          self.assertEqual(None,
392                           get('content-disposition'))
393          self.assertEqual(req.status_out, 500)
394 
diff --git a/web/test/unittest_views_basecontrollers.py b/web/test/unittest_views_basecontrollers.py
@@ -564,15 +564,10 @@
395                             pageid='123', fname='view')
396          ctrl = self.ctrl(req)
397          rset = self.john.as_rset()
398          rset.req = req
399          source = ctrl.publish()
400 -        self.assertTrue(source.startswith('<?xml version="1.0"?>\n' + STRICT_DOCTYPE +
401 -                                          u'<div xmlns="http://www.w3.org/1999/xhtml" xmlns:cubicweb="http://www.logilab.org/2008/cubicweb">')
402 -                        )
403 -        req.xhtml_browser = lambda: False
404 -        source = ctrl.publish()
405          self.assertTrue(source.startswith('<div>'))
406 
407  #     def test_json_exec(self):
408  #         rql = 'Any T,N WHERE T is Tag, T name N'
409  #         ctrl = self.ctrl(self.request(mode='json', rql=rql, pageid='123'))
@@ -742,13 +737,11 @@
410          @monkeypatch(JSonController)
411          @xhtmlize
412          def js_foo(self):
413              return u'hello'
414          res, req = self.remote_call('foo')
415 -        self.assertEqual(res,
416 -                         '<?xml version="1.0"?>\n' + STRICT_DOCTYPE +
417 -                         u'<div xmlns="http://www.w3.org/1999/xhtml" xmlns:cubicweb="http://www.logilab.org/2008/cubicweb">hello</div>')
418 +        self.assertEqual(u'<div>hello</div>', res)
419 
420      def test_monkeypatch_jsoncontroller_jsonize(self):
421          self.assertRaises(RemoteCallFailed, self.remote_call, 'foo')
422          @monkeypatch(JSonController)
423          @jsonize
diff --git a/web/test/unittest_views_baseviews.py b/web/test/unittest_views_baseviews.py
@@ -19,11 +19,11 @@
424  from logilab.common.testlib import unittest_main
425  from logilab.mtconverter import html_unescape
426 
427  from cubicweb.devtools.testlib import CubicWebTC
428  from cubicweb.utils import json
429 -from cubicweb.view import StartupView, TRANSITIONAL_DOCTYPE_NOEXT
430 +from cubicweb.view import StartupView, TRANSITIONAL_DOCTYPE
431  from cubicweb.web.htmlwidgets import TableWidget
432  from cubicweb.web.views import vid_from_rset
433 
434  def loadjson(value):
435      return json.loads(html_unescape(value))
@@ -131,33 +131,28 @@
436 
437          with self.temporary_appobjects(MyView):
438              html_source = self.view('my-view').source
439              source_lines = [line.strip() for line in html_source.splitlines(False)
440                              if line.strip()]
441 -            self.assertListEqual(source_lines[:2],
442 -                                 ['<!DOCTYPE html>',
443 -                                  '<html xmlns="http://www.w3.org/1999/xhtml" xmlns:cubicweb="http://www.logilab.org/2008/cubicweb" xml:lang="en" lang="en">'])
444 +            self.assertListEqual(['<!DOCTYPE html>', '<html lang="en">'], source_lines[:2])
445 
446      def test_set_doctype_no_reset_xmldecl(self):
447          """
448          tests `cubicweb.web.request.CubicWebRequestBase.set_doctype`
449          with no xmldecl reset
450          """
451 -        html_doctype = TRANSITIONAL_DOCTYPE_NOEXT.strip()
452 +        html_doctype = TRANSITIONAL_DOCTYPE.strip()
453          class MyView(StartupView):
454              __regid__ = 'my-view'
455              def call(self):
456                  self._cw.set_doctype(html_doctype, reset_xmldecl=False)
457 -                self._cw.main_stream.set_namespaces([('xmlns', 'http://www.w3.org/1999/xhtml')])
458                  self._cw.main_stream.set_htmlattrs([('lang', 'cz')])
459 
460          with self.temporary_appobjects(MyView):
461              html_source = self.view('my-view').source
462              source_lines = [line.strip() for line in html_source.splitlines(False)
463                              if line.strip()]
464 -            self.assertListEqual(source_lines[:3],
465 -                                 ['<?xml version="1.0" encoding="UTF-8"?>',
466 -                                  html_doctype,
467 -                                  '<html xmlns="http://www.w3.org/1999/xhtml" lang="cz">'])
468 +            self.assertListEqual([html_doctype, '<html lang="cz">', '<head>'],
469 +                                 source_lines[:3])
470 
471  if __name__ == '__main__':
472      unittest_main()
diff --git a/web/views/calendar.py b/web/views/calendar.py
@@ -1,6 +1,6 @@
473 -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
474 +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
475  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
476  #
477  # This file is part of CubicWeb.
478  #
479  # CubicWeb is free software: you can redistribute it and/or modify it under the
@@ -186,11 +186,10 @@
480                     'right': 'month,agendaWeek,agendaDay',
481                     },
482          }
483 
484      def call(self):
485 -        self._cw.demote_to_html()
486          self._cw.add_css(('fullcalendar.css', 'cubicweb.calendar.css'))
487          self._cw.add_js(('jquery.ui.js', 'fullcalendar.min.js', 'jquery.qtip.min.js', 'fullcalendar.locale.js'))
488          self.calendar_id = 'cal' + make_uid('uid')
489          self.add_onload()
490          # write calendar div to load jquery fullcalendar object
diff --git a/web/webconfig.py b/web/webconfig.py
@@ -168,17 +168,10 @@
491            'help': 'Same as cleanup-session-time but specific to anonymous '
492            'sessions. You can have a much smaller timeout here since it will be '
493            'transparent to the user. Default to 5min.',
494            'group': 'web', 'level': 3,
495            }),
496 -        ('force-html-content-type',
497 -         {'type' : 'yn',
498 -          'default': False,
499 -          'help': 'force text/html content type for your html pages instead of cubicweb user-agent based'\
500 -          'deduction of an appropriate content type',
501 -          'group': 'web', 'level': 3,
502 -          }),
503          ('embed-allowed',
504           {'type' : 'regexp',
505            'default': None,
506            'help': 'regular expression matching URLs that may be embeded. \
507  leave it blank if you don\'t want the embedding feature, or set it to ".*" \