From 6b857b6eeb59137a71385f98c82c440ac82cd45d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 27 Feb 2014 13:59:34 +0100 Subject: [PATCH] [FIX] whitespace/indent lost by RTE Didn't manage to find RTE settings to avoid losing leading whitespace of lines, so reindeint arch after doing all integration, right before saving back to view's field. * html.fromstring(parser=HTMLParser(remove_blank_text=True) does not seem to work, so serialize to XML, and parse back with remove_blank_text. remove_blank_text necessary for lxml's pretty_print to work correctly. * pretty_print only & always uses 2 spaces/indent level. Our files (and the HTML editor's Format button) uses 4 spaces -> need a second pass to double indents. bzr revid: xmo@openerp.com-20140227125934-q8j3z440px2ic6kx --- addons/website/models/ir_ui_view.py | 26 +++++++++++++++++++++++++- addons/website/tests/test_views.py | 4 ++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index 27af03310a9..857b99d40d2 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import copy +import re import simplejson import werkzeug @@ -158,6 +159,29 @@ class view(osv.osv): return super(view, self).render(cr, uid, id_or_xml_id, values=values, engine=engine, context=context) + def _pretty_arch(self, arch): + # remove_blank_string does not seem to work on HTMLParser, and + # pretty-printing with lxml more or less requires stripping + # whitespace: http://lxml.de/FAQ.html#why-doesn-t-the-pretty-print-option-reformat-my-xml-output + # so serialize to XML, parse as XML (remove whitespace) then serialize + # as XML (pretty print) + arch_no_whitespace = etree.fromstring( + etree.tostring(arch, encoding='utf-8'), + parser=etree.XMLParser(encoding='utf-8', remove_blank_text=True)) + arch_pretty_indent_2 = etree.tostring( + arch_no_whitespace, encoding='unicode', pretty_print=True) + + # pretty_print uses a fixed indent level of 2, we want an indent of 4, + # double up leading spaces. + def repl(m): + indent = len(m.group(0)) / 2 + return u' ' * 4 * indent + # FIXME: If py2.7 only, can use re.M in sub and don't have to do replacement line by line + return u'\n'.join( + re.sub(ur'^((?: )+)', repl, line) + for line in arch_pretty_indent_2.split(u'\n') + ) + def save(self, cr, uid, res_id, value, xpath=None, context=None): """ Update a view section. The view section may embed fields to write @@ -183,5 +207,5 @@ class view(osv.osv): arch = self.replace_arch_section(cr, uid, res_id, xpath, arch_section, context=context) self.write(cr, uid, res_id, { - 'arch': etree.tostring(arch, encoding='utf-8').decode('utf-8') + 'arch': self._pretty_arch(arch) }, context=context) diff --git a/addons/website/tests/test_views.py b/addons/website/tests/test_views.py index 8041a7e5f1c..1adb11712ec 100644 --- a/addons/website/tests/test_views.py +++ b/addons/website/tests/test_views.py @@ -13,8 +13,8 @@ class TestViewSaving(common.TransactionCase): def eq(self, a, b): self.assertEqual(a.tag, b.tag) self.assertEqual(a.attrib, b.attrib) - self.assertEqual(a.text, b.text) - self.assertEqual(a.tail, b.tail) + self.assertEqual((a.text or '').strip(), (b.text or '').strip()) + self.assertEqual((a.tail or '').strip(), (b.tail or '').strip()) for ca, cb in itertools.izip_longest(a, b): self.eq(ca, cb)