[gen] Bugfix in generation of back reference for predefined Refs from model.py; bugfix while editing XHTML fields from class model.py::Page; bugfixes in the XhtmlCleaner.

This commit is contained in:
Gaetan Delannay 2013-01-11 17:16:36 +01:00
parent b76af3e0c2
commit 27197f5b9d
4 changed files with 54 additions and 34 deletions

View file

@ -1245,7 +1245,7 @@ class String(Type):
# (ie for image size when images are resized). So in this case we
# can't remove style-related information.
try:
value = XhtmlCleaner().clean(value, keepStyles=self.richText)
value = XhtmlCleaner(keepStyles=self.richText).clean(value)
except XhtmlCleaner.Error, e:
# Errors while parsing p_value can't prevent the user from
# storing it.

View file

@ -40,7 +40,9 @@ class ModelClass:
those classes are part of the Appy machinery and are prefixed with _appy_
in order to avoid name conflicts with user-defined parts of the
application model.'''
_appy_attributes = [] # We need to keep track of attributes order.
# In any ModelClass subclass we need to declare attributes in the following
# list (including back attributes), to keep track of attributes order.
_appy_attributes = []
folder = False
@classmethod
def _appy_getTypeBody(klass, appyType, wrapperName):
@ -128,18 +130,18 @@ class ModelClass:
pageShow = '%s.%s' % (wrapperName, pageShow.__name__)
res += '"%s":Pge("%s", show=%s),'% (page.name, page.name, pageShow)
res += '}\n'
# Secondly, dump every attribute
# Secondly, dump every (not Ref.isBack) attribute
for name in klass._appy_attributes:
exec 'appyType = klass.%s' % name
if (appyType.type == 'Ref') and appyType.isBack: continue
typeBody = klass._appy_getTypeBody(appyType, wrapperName)
res += ' %s=%s\n' % (name, typeBody)
return res
# The User class ---------------------------------------------------------------
class User(ModelClass):
# In a ModelClass we need to declare attributes in the following list.
_appy_attributes = ['title', 'name', 'firstName', 'login', 'password1',
'password2', 'email', 'roles']
'password2', 'email', 'roles', 'groups', 'toTool']
# All methods defined below are fake. Real versions are in the wrapper.
title = gen.String(show=False, indexed=True)
gm = {'group': 'main', 'width': 25}
@ -165,8 +167,7 @@ class User(ModelClass):
# The Group class --------------------------------------------------------------
class Group(ModelClass):
# In a ModelClass we need to declare attributes in the following list.
_appy_attributes = ['title', 'login', 'roles', 'users']
_appy_attributes = ['title', 'login', 'roles', 'users', 'toTool2']
# All methods defined below are fake. Real versions are in the wrapper.
m = {'group': 'main', 'width': 25, 'indexed': True}
title = gen.String(multiplicity=(1,1), **m)
@ -183,7 +184,7 @@ class Group(ModelClass):
# The Translation class --------------------------------------------------------
class Translation(ModelClass):
_appy_attributes = ['po', 'title', 'sourceLanguage']
_appy_attributes = ['po', 'title', 'sourceLanguage', 'trToTool']
# All methods defined below are fake. Real versions are in the wrapper.
actionsPage = gen.Page('actions')
def getPoFile(self): pass
@ -195,9 +196,9 @@ class Translation(ModelClass):
# The Page class ---------------------------------------------------------------
class Page(ModelClass):
_appy_attributes = ['title', 'content', 'pages']
_appy_attributes = ['title', 'content', 'pages', 'parent', 'toTool3']
folder = True
title = gen.String(show='edit', indexed=True)
title = gen.String(show='edit', multiplicity=(1,1), indexed=True)
content = gen.String(format=gen.String.XHTML, layouts='f', richText=True)
# Pages can contain other pages.
def showSubPages(self): pass

View file

@ -50,7 +50,7 @@
layout The layout object that will dictate how object content
will be rendered.
</tal:comment>
<metal:show define-macro="show" tal:define="tagId python: 'content'">
<metal:show define-macro="show" tal:define="tagId python: 'pageLayout'">
<metal:layout use-macro="context/ui/widgets/show/macros/layout"/>
</metal:show>

View file

@ -961,19 +961,21 @@ class XhtmlCleaner(XmlParser):
Appy-compliant format.'''
class Error(Exception): pass
# Tags that will not be in the result, content included, if keepStyles is
# False.
# Tags that will never be in the result, content included.
tagsToIgnoreWithContent = ('style', 'colgroup', 'head')
# Tags that will be removed from the result, but whose content will be kept,
# if keepStyles is False.
tagsToIgnoreKeepContent= ('x', 'font', 'center', 'html', 'body')
# All tags to ignore
tagsToIgnore = tagsToIgnoreWithContent + tagsToIgnoreKeepContent
tagsToIgnoreKeepContent = ('x', 'html', 'body')
allTagsToIgnore = tagsToIgnoreWithContent + tagsToIgnoreKeepContent
# Additional tags that will be removed, but content kept, if keepStyles is
# False.
tagsToIgnoreKeepContentDropStyles = ('font', 'center')
# Attributes to ignore, if keepStyles if False.
attrsToIgnore = ('align', 'valign', 'cellpadding', 'cellspacing', 'width',
'height', 'bgcolor', 'lang', 'border', 'class', 'rules')
# CSS attributes to keep, if keepStyles if False. These attributes can be
# used by appy.pod (to align a paragraph, center/resize an image...).
# CSS attributes to keep even if keepStyles if False. These attributes can
# be used by pod (to align a paragraph, center/resize an image...).
cssAttrsToKeep = ('width', 'height', 'float', 'text-align',
'font-style', 'font-weight')
# Attrs to add, if not present, to ensure good formatting, be it at the web
@ -981,10 +983,21 @@ class XhtmlCleaner(XmlParser):
attrsToAdd = {'table': {'cellspacing':'0', 'cellpadding':'6', 'border':'1'},
'tr': {'valign': 'top'}}
# Tags that required a line break to be inserted after them.
# Tags that require a line break to be inserted after them.
lineBreakTags = ('p', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td')
def clean(self, s, keepStyles=True):
# No-end tags
noEndTags = ('br', 'img')
def __init__(self, keepStyles=True):
XmlParser.__init__(self)
self.keepStyles = keepStyles
# Compute tags to ignore, which may vary according to p_keepStyles.
self.tagsToIgnore = self.allTagsToIgnore
if not keepStyles:
self.tagsToIgnore += self.tagsToIgnoreKeepContentDropStyles
def clean(self, s):
'''Cleaning XHTML code is done for 2 reasons:
1. The main objective is to format XHTML p_s to be storable in the
@ -999,8 +1012,6 @@ class XhtmlCleaner(XmlParser):
content that can be dumped in an elegant and systematic manner
into a POD template.
'''
# Must we keep style-related information or not?
self.env.keepStyles = keepStyles
self.env.currentContent = ''
# The stack of currently parsed elements (will contain only ignored
# ones).
@ -1040,7 +1051,7 @@ class XhtmlCleaner(XmlParser):
self.res.append(e.currentContent)
e.currentContent = ''
if e.ignoreTag and e.ignoreContent: return
if not e.keepStyles and (elem in self.tagsToIgnore):
if elem in self.tagsToIgnore:
e.ignoreTag = True
if elem in self.tagsToIgnoreWithContent:
e.ignoreContent = True
@ -1058,7 +1069,7 @@ class XhtmlCleaner(XmlParser):
res = '%s<%s' % (prefix, elem)
# Include the found attributes, excepted those that must be ignored.
for name, value in attrs.items():
if not e.keepStyles:
if not self.keepStyles:
if name in self.attrsToIgnore: continue
elif name == 'style':
value = self.cleanStyleAttribute(value)
@ -1068,7 +1079,12 @@ class XhtmlCleaner(XmlParser):
if elem in self.attrsToAdd:
for name, value in self.attrsToAdd[elem].iteritems():
res += ' %s="%s"' % (name, value)
self.res.append('%s>' % res)
# Close the tag if it is a no-end tag
if elem in self.noEndTags:
suffix = '/>'
else:
suffix = '>'
self.res.append('%s%s' % (res, suffix))
def endElement(self, elem):
e = self.env
@ -1087,14 +1103,17 @@ class XhtmlCleaner(XmlParser):
else:
if self.env.currentContent:
self.res.append(self.env.currentContent)
# Add a line break after the end tag if required (ie: xhtml differ
# needs to get paragraphs and other elements on separate lines).
if (elem in self.lineBreakTags) and self.res and \
(self.res[-1][-1] != '\n'):
suffix = '\n'
else:
suffix = ''
self.res.append('</%s>%s' % (elem, suffix))
# Close the tag only if it is a no-end tag.
if elem not in self.noEndTags:
# Add a line break after the end tag if required (ie: xhtml
# differ needs to get paragraphs and other elements on separate
# lines).
if (elem in self.lineBreakTags) and self.res and \
(self.res[-1][-1] != '\n'):
suffix = '\n'
else:
suffix = ''
self.res.append('</%s>%s' % (elem, suffix))
self.env.currentContent = ''
def characters(self, content):