[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:
parent
b76af3e0c2
commit
27197f5b9d
|
@ -1245,7 +1245,7 @@ class String(Type):
|
||||||
# (ie for image size when images are resized). So in this case we
|
# (ie for image size when images are resized). So in this case we
|
||||||
# can't remove style-related information.
|
# can't remove style-related information.
|
||||||
try:
|
try:
|
||||||
value = XhtmlCleaner().clean(value, keepStyles=self.richText)
|
value = XhtmlCleaner(keepStyles=self.richText).clean(value)
|
||||||
except XhtmlCleaner.Error, e:
|
except XhtmlCleaner.Error, e:
|
||||||
# Errors while parsing p_value can't prevent the user from
|
# Errors while parsing p_value can't prevent the user from
|
||||||
# storing it.
|
# storing it.
|
||||||
|
|
19
gen/model.py
19
gen/model.py
|
@ -40,7 +40,9 @@ class ModelClass:
|
||||||
those classes are part of the Appy machinery and are prefixed with _appy_
|
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
|
in order to avoid name conflicts with user-defined parts of the
|
||||||
application model.'''
|
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
|
folder = False
|
||||||
@classmethod
|
@classmethod
|
||||||
def _appy_getTypeBody(klass, appyType, wrapperName):
|
def _appy_getTypeBody(klass, appyType, wrapperName):
|
||||||
|
@ -128,18 +130,18 @@ class ModelClass:
|
||||||
pageShow = '%s.%s' % (wrapperName, pageShow.__name__)
|
pageShow = '%s.%s' % (wrapperName, pageShow.__name__)
|
||||||
res += '"%s":Pge("%s", show=%s),'% (page.name, page.name, pageShow)
|
res += '"%s":Pge("%s", show=%s),'% (page.name, page.name, pageShow)
|
||||||
res += '}\n'
|
res += '}\n'
|
||||||
# Secondly, dump every attribute
|
# Secondly, dump every (not Ref.isBack) attribute
|
||||||
for name in klass._appy_attributes:
|
for name in klass._appy_attributes:
|
||||||
exec 'appyType = klass.%s' % name
|
exec 'appyType = klass.%s' % name
|
||||||
|
if (appyType.type == 'Ref') and appyType.isBack: continue
|
||||||
typeBody = klass._appy_getTypeBody(appyType, wrapperName)
|
typeBody = klass._appy_getTypeBody(appyType, wrapperName)
|
||||||
res += ' %s=%s\n' % (name, typeBody)
|
res += ' %s=%s\n' % (name, typeBody)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# The User class ---------------------------------------------------------------
|
# The User class ---------------------------------------------------------------
|
||||||
class User(ModelClass):
|
class User(ModelClass):
|
||||||
# In a ModelClass we need to declare attributes in the following list.
|
|
||||||
_appy_attributes = ['title', 'name', 'firstName', 'login', 'password1',
|
_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.
|
# All methods defined below are fake. Real versions are in the wrapper.
|
||||||
title = gen.String(show=False, indexed=True)
|
title = gen.String(show=False, indexed=True)
|
||||||
gm = {'group': 'main', 'width': 25}
|
gm = {'group': 'main', 'width': 25}
|
||||||
|
@ -165,8 +167,7 @@ class User(ModelClass):
|
||||||
|
|
||||||
# The Group class --------------------------------------------------------------
|
# The Group class --------------------------------------------------------------
|
||||||
class Group(ModelClass):
|
class Group(ModelClass):
|
||||||
# In a ModelClass we need to declare attributes in the following list.
|
_appy_attributes = ['title', 'login', 'roles', 'users', 'toTool2']
|
||||||
_appy_attributes = ['title', 'login', 'roles', 'users']
|
|
||||||
# All methods defined below are fake. Real versions are in the wrapper.
|
# All methods defined below are fake. Real versions are in the wrapper.
|
||||||
m = {'group': 'main', 'width': 25, 'indexed': True}
|
m = {'group': 'main', 'width': 25, 'indexed': True}
|
||||||
title = gen.String(multiplicity=(1,1), **m)
|
title = gen.String(multiplicity=(1,1), **m)
|
||||||
|
@ -183,7 +184,7 @@ class Group(ModelClass):
|
||||||
|
|
||||||
# The Translation class --------------------------------------------------------
|
# The Translation class --------------------------------------------------------
|
||||||
class Translation(ModelClass):
|
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.
|
# All methods defined below are fake. Real versions are in the wrapper.
|
||||||
actionsPage = gen.Page('actions')
|
actionsPage = gen.Page('actions')
|
||||||
def getPoFile(self): pass
|
def getPoFile(self): pass
|
||||||
|
@ -195,9 +196,9 @@ class Translation(ModelClass):
|
||||||
|
|
||||||
# The Page class ---------------------------------------------------------------
|
# The Page class ---------------------------------------------------------------
|
||||||
class Page(ModelClass):
|
class Page(ModelClass):
|
||||||
_appy_attributes = ['title', 'content', 'pages']
|
_appy_attributes = ['title', 'content', 'pages', 'parent', 'toTool3']
|
||||||
folder = True
|
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)
|
content = gen.String(format=gen.String.XHTML, layouts='f', richText=True)
|
||||||
# Pages can contain other pages.
|
# Pages can contain other pages.
|
||||||
def showSubPages(self): pass
|
def showSubPages(self): pass
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
layout The layout object that will dictate how object content
|
layout The layout object that will dictate how object content
|
||||||
will be rendered.
|
will be rendered.
|
||||||
</tal:comment>
|
</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:layout use-macro="context/ui/widgets/show/macros/layout"/>
|
||||||
</metal:show>
|
</metal:show>
|
||||||
|
|
||||||
|
|
|
@ -961,19 +961,21 @@ class XhtmlCleaner(XmlParser):
|
||||||
Appy-compliant format.'''
|
Appy-compliant format.'''
|
||||||
class Error(Exception): pass
|
class Error(Exception): pass
|
||||||
|
|
||||||
# Tags that will not be in the result, content included, if keepStyles is
|
# Tags that will never be in the result, content included.
|
||||||
# False.
|
|
||||||
tagsToIgnoreWithContent = ('style', 'colgroup', 'head')
|
tagsToIgnoreWithContent = ('style', 'colgroup', 'head')
|
||||||
# Tags that will be removed from the result, but whose content will be kept,
|
# Tags that will be removed from the result, but whose content will be kept,
|
||||||
# if keepStyles is False.
|
tagsToIgnoreKeepContent = ('x', 'html', 'body')
|
||||||
tagsToIgnoreKeepContent= ('x', 'font', 'center', 'html', 'body')
|
allTagsToIgnore = tagsToIgnoreWithContent + tagsToIgnoreKeepContent
|
||||||
# All tags to ignore
|
|
||||||
tagsToIgnore = 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.
|
# Attributes to ignore, if keepStyles if False.
|
||||||
attrsToIgnore = ('align', 'valign', 'cellpadding', 'cellspacing', 'width',
|
attrsToIgnore = ('align', 'valign', 'cellpadding', 'cellspacing', 'width',
|
||||||
'height', 'bgcolor', 'lang', 'border', 'class', 'rules')
|
'height', 'bgcolor', 'lang', 'border', 'class', 'rules')
|
||||||
# CSS attributes to keep, if keepStyles if False. These attributes can be
|
# CSS attributes to keep even if keepStyles if False. These attributes can
|
||||||
# used by appy.pod (to align a paragraph, center/resize an image...).
|
# be used by pod (to align a paragraph, center/resize an image...).
|
||||||
cssAttrsToKeep = ('width', 'height', 'float', 'text-align',
|
cssAttrsToKeep = ('width', 'height', 'float', 'text-align',
|
||||||
'font-style', 'font-weight')
|
'font-style', 'font-weight')
|
||||||
# Attrs to add, if not present, to ensure good formatting, be it at the web
|
# 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'},
|
attrsToAdd = {'table': {'cellspacing':'0', 'cellpadding':'6', 'border':'1'},
|
||||||
'tr': {'valign': 'top'}}
|
'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')
|
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:
|
'''Cleaning XHTML code is done for 2 reasons:
|
||||||
|
|
||||||
1. The main objective is to format XHTML p_s to be storable in the
|
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
|
content that can be dumped in an elegant and systematic manner
|
||||||
into a POD template.
|
into a POD template.
|
||||||
'''
|
'''
|
||||||
# Must we keep style-related information or not?
|
|
||||||
self.env.keepStyles = keepStyles
|
|
||||||
self.env.currentContent = ''
|
self.env.currentContent = ''
|
||||||
# The stack of currently parsed elements (will contain only ignored
|
# The stack of currently parsed elements (will contain only ignored
|
||||||
# ones).
|
# ones).
|
||||||
|
@ -1040,7 +1051,7 @@ class XhtmlCleaner(XmlParser):
|
||||||
self.res.append(e.currentContent)
|
self.res.append(e.currentContent)
|
||||||
e.currentContent = ''
|
e.currentContent = ''
|
||||||
if e.ignoreTag and e.ignoreContent: return
|
if e.ignoreTag and e.ignoreContent: return
|
||||||
if not e.keepStyles and (elem in self.tagsToIgnore):
|
if elem in self.tagsToIgnore:
|
||||||
e.ignoreTag = True
|
e.ignoreTag = True
|
||||||
if elem in self.tagsToIgnoreWithContent:
|
if elem in self.tagsToIgnoreWithContent:
|
||||||
e.ignoreContent = True
|
e.ignoreContent = True
|
||||||
|
@ -1058,7 +1069,7 @@ class XhtmlCleaner(XmlParser):
|
||||||
res = '%s<%s' % (prefix, elem)
|
res = '%s<%s' % (prefix, elem)
|
||||||
# Include the found attributes, excepted those that must be ignored.
|
# Include the found attributes, excepted those that must be ignored.
|
||||||
for name, value in attrs.items():
|
for name, value in attrs.items():
|
||||||
if not e.keepStyles:
|
if not self.keepStyles:
|
||||||
if name in self.attrsToIgnore: continue
|
if name in self.attrsToIgnore: continue
|
||||||
elif name == 'style':
|
elif name == 'style':
|
||||||
value = self.cleanStyleAttribute(value)
|
value = self.cleanStyleAttribute(value)
|
||||||
|
@ -1068,7 +1079,12 @@ class XhtmlCleaner(XmlParser):
|
||||||
if elem in self.attrsToAdd:
|
if elem in self.attrsToAdd:
|
||||||
for name, value in self.attrsToAdd[elem].iteritems():
|
for name, value in self.attrsToAdd[elem].iteritems():
|
||||||
res += ' %s="%s"' % (name, value)
|
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):
|
def endElement(self, elem):
|
||||||
e = self.env
|
e = self.env
|
||||||
|
@ -1087,14 +1103,17 @@ class XhtmlCleaner(XmlParser):
|
||||||
else:
|
else:
|
||||||
if self.env.currentContent:
|
if self.env.currentContent:
|
||||||
self.res.append(self.env.currentContent)
|
self.res.append(self.env.currentContent)
|
||||||
# Add a line break after the end tag if required (ie: xhtml differ
|
# Close the tag only if it is a no-end tag.
|
||||||
# needs to get paragraphs and other elements on separate lines).
|
if elem not in self.noEndTags:
|
||||||
if (elem in self.lineBreakTags) and self.res and \
|
# Add a line break after the end tag if required (ie: xhtml
|
||||||
(self.res[-1][-1] != '\n'):
|
# differ needs to get paragraphs and other elements on separate
|
||||||
suffix = '\n'
|
# lines).
|
||||||
else:
|
if (elem in self.lineBreakTags) and self.res and \
|
||||||
suffix = ''
|
(self.res[-1][-1] != '\n'):
|
||||||
self.res.append('</%s>%s' % (elem, suffix))
|
suffix = '\n'
|
||||||
|
else:
|
||||||
|
suffix = ''
|
||||||
|
self.res.append('</%s>%s' % (elem, suffix))
|
||||||
self.env.currentContent = ''
|
self.env.currentContent = ''
|
||||||
|
|
||||||
def characters(self, content):
|
def characters(self, content):
|
||||||
|
|
Loading…
Reference in a new issue