Worflow state can not be used in ref fields; mayNavigate is not static anymore, but an instance method.
This commit is contained in:
parent
e62e00d367
commit
2124cffa5e
|
@ -90,7 +90,8 @@ class Group:
|
||||||
def __init__(self, name, columns=['100%'], wide=True, style='section2',
|
def __init__(self, name, columns=['100%'], wide=True, style='section2',
|
||||||
hasLabel=True, hasDescr=False, hasHelp=False,
|
hasLabel=True, hasDescr=False, hasHelp=False,
|
||||||
hasHeaders=False, group=None, colspan=1, align='center',
|
hasHeaders=False, group=None, colspan=1, align='center',
|
||||||
valign='top', css_class='', master=None, masterValue=None):
|
valign='top', css_class='', master=None, masterValue=None,
|
||||||
|
cellpadding=1, cellspacing=1):
|
||||||
self.name = name
|
self.name = name
|
||||||
# In its simpler form, field "columns" below can hold a list or tuple
|
# In its simpler form, field "columns" below can hold a list or tuple
|
||||||
# of column widths expressed as strings, that will be given as is in
|
# of column widths expressed as strings, that will be given as is in
|
||||||
|
@ -127,6 +128,8 @@ class Group:
|
||||||
self.colspan = colspan
|
self.colspan = colspan
|
||||||
self.align = align
|
self.align = align
|
||||||
self.valign = valign
|
self.valign = valign
|
||||||
|
self.cellpadding = cellpadding
|
||||||
|
self.cellspacing = cellspacing
|
||||||
if style == 'tabs':
|
if style == 'tabs':
|
||||||
# Group content will be rendered as tabs. In this case, some
|
# Group content will be rendered as tabs. In this case, some
|
||||||
# param combinations have no sense.
|
# param combinations have no sense.
|
||||||
|
@ -289,8 +292,9 @@ class Search:
|
||||||
self.group = group # Searches may be visually grouped in the portlet
|
self.group = group # Searches may be visually grouped in the portlet
|
||||||
self.sortBy = sortBy
|
self.sortBy = sortBy
|
||||||
self.limit = limit
|
self.limit = limit
|
||||||
self.fields = fields # This is a dict whose keys are indexed field
|
# In the dict below, keys are indexed field names and values are
|
||||||
# names and whose values are search values.
|
# search values.
|
||||||
|
self.fields = fields
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getIndexName(fieldName, usage='search'):
|
def getIndexName(fieldName, usage='search'):
|
||||||
'''Gets the name of the technical index that corresponds to field named
|
'''Gets the name of the technical index that corresponds to field named
|
||||||
|
@ -1466,7 +1470,8 @@ class Ref(Type):
|
||||||
searchable=False, specificReadPermission=False,
|
searchable=False, specificReadPermission=False,
|
||||||
specificWritePermission=False, width=None, height=5,
|
specificWritePermission=False, width=None, height=5,
|
||||||
colspan=1, master=None, masterValue=None, focus=False,
|
colspan=1, master=None, masterValue=None, focus=False,
|
||||||
historized=False):
|
historized=False, queryable=False, queryFields=None,
|
||||||
|
queryNbCols=1):
|
||||||
self.klass = klass
|
self.klass = klass
|
||||||
self.attribute = attribute
|
self.attribute = attribute
|
||||||
# May the user add new objects through this ref ?
|
# May the user add new objects through this ref ?
|
||||||
|
@ -1503,6 +1508,15 @@ class Ref(Type):
|
||||||
self.maxPerPage = maxPerPage
|
self.maxPerPage = maxPerPage
|
||||||
# Specifies sync
|
# Specifies sync
|
||||||
sync = {'view': False, 'edit':True}
|
sync = {'view': False, 'edit':True}
|
||||||
|
# If param p_queryable is True, the user will be able to perform queries
|
||||||
|
# from the UI within referenced objects.
|
||||||
|
self.queryable = queryable
|
||||||
|
# Here is the list of fields that will appear on the search screen.
|
||||||
|
# If None is specified, by default we take every indexed field
|
||||||
|
# defined on referenced objects' class.
|
||||||
|
self.queryFields = queryFields
|
||||||
|
# The search screen will have this number of columns
|
||||||
|
self.queryNbCols = queryNbCols
|
||||||
Type.__init__(self, validator, multiplicity, index, default, optional,
|
Type.__init__(self, validator, multiplicity, index, default, optional,
|
||||||
editDefault, show, page, group, layouts, move, indexed,
|
editDefault, show, page, group, layouts, move, indexed,
|
||||||
False, specificReadPermission, specificWritePermission,
|
False, specificReadPermission, specificWritePermission,
|
||||||
|
|
|
@ -535,7 +535,6 @@ class UserClassDescriptor(ClassDescriptor):
|
||||||
self.klass = klass
|
self.klass = klass
|
||||||
self.customized = True
|
self.customized = True
|
||||||
def isFolder(self, klass=None): return True
|
def isFolder(self, klass=None): return True
|
||||||
def isRoot(self): return False
|
|
||||||
def generateSchema(self):
|
def generateSchema(self):
|
||||||
ClassDescriptor.generateSchema(self, configClass=True)
|
ClassDescriptor.generateSchema(self, configClass=True)
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,6 @@ class Generator(AbstractGenerator):
|
||||||
msg('max_ref_violated', '', msg.MAX_REF_VIOLATED),
|
msg('max_ref_violated', '', msg.MAX_REF_VIOLATED),
|
||||||
msg('no_ref', '', msg.REF_NO),
|
msg('no_ref', '', msg.REF_NO),
|
||||||
msg('add_ref', '', msg.REF_ADD),
|
msg('add_ref', '', msg.REF_ADD),
|
||||||
msg('ref_name', '', msg.REF_NAME),
|
|
||||||
msg('ref_actions', '', msg.REF_ACTIONS),
|
msg('ref_actions', '', msg.REF_ACTIONS),
|
||||||
msg('move_up', '', msg.REF_MOVE_UP),
|
msg('move_up', '', msg.REF_MOVE_UP),
|
||||||
msg('move_down', '', msg.REF_MOVE_DOWN),
|
msg('move_down', '', msg.REF_MOVE_DOWN),
|
||||||
|
@ -303,7 +302,7 @@ class Generator(AbstractGenerator):
|
||||||
repls['addPermissions'] = addPermissions
|
repls['addPermissions'] = addPermissions
|
||||||
# Compute root classes
|
# Compute root classes
|
||||||
rootClasses = ''
|
rootClasses = ''
|
||||||
for classDescr in self.classes:
|
for classDescr in self.getClasses(include='allButTool'):
|
||||||
if classDescr.isRoot():
|
if classDescr.isRoot():
|
||||||
rootClasses += "'%s'," % classDescr.name
|
rootClasses += "'%s'," % classDescr.name
|
||||||
repls['rootClasses'] = rootClasses
|
repls['rootClasses'] = rootClasses
|
||||||
|
@ -617,9 +616,20 @@ class Generator(AbstractGenerator):
|
||||||
if self.user.customized:
|
if self.user.customized:
|
||||||
Tool.users.klass = self.user.klass
|
Tool.users.klass = self.user.klass
|
||||||
|
|
||||||
|
# Generate the User class
|
||||||
|
self.user.generateSchema()
|
||||||
|
self.labels += [ Msg(self.userName, '', Msg.USER),
|
||||||
|
Msg('%s_edit_descr' % self.userName, '', ' '),
|
||||||
|
Msg('%s_plural' % self.userName, '',self.userName+'s')]
|
||||||
|
repls = self.repls.copy()
|
||||||
|
repls['fields'] = self.user.schema
|
||||||
|
repls['methods'] = self.user.methods
|
||||||
|
repls['wrapperClass'] = '%s_Wrapper' % self.user.name
|
||||||
|
self.copyFile('UserTemplate.py', repls,destName='%s.py' % self.userName)
|
||||||
|
|
||||||
# Before generating the Tool class, finalize it with query result
|
# Before generating the Tool class, finalize it with query result
|
||||||
# columns, with fields to propagate, workflow-related fields.
|
# columns, with fields to propagate, workflow-related fields.
|
||||||
for classDescr in self.classes:
|
for classDescr in self.getClasses(include='allButTool'):
|
||||||
for fieldName, fieldType in classDescr.toolFieldsToPropagate:
|
for fieldName, fieldType in classDescr.toolFieldsToPropagate:
|
||||||
for childDescr in classDescr.getChildren():
|
for childDescr in classDescr.getChildren():
|
||||||
childFieldName = fieldName % childDescr.name
|
childFieldName = fieldName % childDescr.name
|
||||||
|
@ -644,16 +654,6 @@ class Generator(AbstractGenerator):
|
||||||
repls['wrapperClass'] = '%s_Wrapper' % self.tool.name
|
repls['wrapperClass'] = '%s_Wrapper' % self.tool.name
|
||||||
self.copyFile('ToolTemplate.py', repls, destName='%s.py'% self.toolName)
|
self.copyFile('ToolTemplate.py', repls, destName='%s.py'% self.toolName)
|
||||||
|
|
||||||
# Generate the User class
|
|
||||||
self.user.generateSchema()
|
|
||||||
self.labels += [ Msg(self.userName, '', Msg.USER),
|
|
||||||
Msg('%s_edit_descr' % self.userName, '', ' ')]
|
|
||||||
repls = self.repls.copy()
|
|
||||||
repls['fields'] = self.user.schema
|
|
||||||
repls['methods'] = self.user.methods
|
|
||||||
repls['wrapperClass'] = '%s_Wrapper' % self.user.name
|
|
||||||
self.copyFile('UserTemplate.py', repls,destName='%s.py' % self.userName)
|
|
||||||
|
|
||||||
def generateClass(self, classDescr):
|
def generateClass(self, classDescr):
|
||||||
'''Is called each time an Appy class is found in the application, for
|
'''Is called each time an Appy class is found in the application, for
|
||||||
generating the corresponding Archetype class and schema.'''
|
generating the corresponding Archetype class and schema.'''
|
||||||
|
|
|
@ -164,16 +164,25 @@ class ToolMixin(BaseMixin):
|
||||||
res.append((appyType.name, self.translate(appyType.labelId)))
|
res.append((appyType.name, self.translate(appyType.labelId)))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getSearchableFields(self, contentType):
|
def getSearchInfo(self, contentType, refInfo=None):
|
||||||
'''Returns, among the list of all searchable fields (see method above),
|
'''Returns a tuple:
|
||||||
the list of fields that the user has configured as being effectively
|
1) The list of searchable fields (ie fields among all indexed fields)
|
||||||
used in the search screen.'''
|
2) The number of columns for layouting those fields.'''
|
||||||
res = []
|
fields = []
|
||||||
fieldNames = getattr(self.appy(), 'searchFieldsFor%s' % contentType, ())
|
if refInfo:
|
||||||
|
# The search is triggered from a Ref field.
|
||||||
|
refField = self.getRefInfo(refInfo)[1]
|
||||||
|
fieldNames = refField.queryFields or ()
|
||||||
|
nbOfColumns = refField.queryNbCols
|
||||||
|
else:
|
||||||
|
# The search is triggered from an app-wide search.
|
||||||
|
at = self.appy()
|
||||||
|
fieldNames = getattr(at, 'searchFieldsFor%s' % contentType,())
|
||||||
|
nbOfColumns = getattr(at, 'numberOfSearchColumnsFor%s' %contentType)
|
||||||
for name in fieldNames:
|
for name in fieldNames:
|
||||||
appyType = self.getAppyType(name, asDict=True,className=contentType)
|
appyType = self.getAppyType(name, asDict=True,className=contentType)
|
||||||
res.append(appyType)
|
fields.append(appyType)
|
||||||
return res
|
return fields, nbOfColumns
|
||||||
|
|
||||||
def getImportElements(self, contentType):
|
def getImportElements(self, contentType):
|
||||||
'''Returns the list of elements that can be imported from p_path for
|
'''Returns the list of elements that can be imported from p_path for
|
||||||
|
@ -220,7 +229,8 @@ class ToolMixin(BaseMixin):
|
||||||
def executeQuery(self, contentType, searchName=None, startNumber=0,
|
def executeQuery(self, contentType, searchName=None, startNumber=0,
|
||||||
search=None, remember=False, brainsOnly=False,
|
search=None, remember=False, brainsOnly=False,
|
||||||
maxResults=None, noSecurity=False, sortBy=None,
|
maxResults=None, noSecurity=False, sortBy=None,
|
||||||
sortOrder='asc', filterKey=None, filterValue=None):
|
sortOrder='asc', filterKey=None, filterValue=None,
|
||||||
|
refField=None):
|
||||||
'''Executes a query on a given p_contentType (or several, separated
|
'''Executes a query on a given p_contentType (or several, separated
|
||||||
with commas) in Plone's portal_catalog. If p_searchName is specified,
|
with commas) in Plone's portal_catalog. If p_searchName is specified,
|
||||||
it corresponds to:
|
it corresponds to:
|
||||||
|
@ -256,7 +266,10 @@ class ToolMixin(BaseMixin):
|
||||||
|
|
||||||
If p_filterKey is given, it represents an additional search parameter
|
If p_filterKey is given, it represents an additional search parameter
|
||||||
to take into account: the corresponding search value is in
|
to take into account: the corresponding search value is in
|
||||||
p_filterValue.'''
|
p_filterValue.
|
||||||
|
|
||||||
|
If p_refField is given, the query is limited to the objects that are
|
||||||
|
referenced through it.'''
|
||||||
# Is there one or several content types ?
|
# Is there one or several content types ?
|
||||||
if contentType.find(',') != -1:
|
if contentType.find(',') != -1:
|
||||||
portalTypes = contentType.split(',')
|
portalTypes = contentType.split(',')
|
||||||
|
@ -276,6 +289,9 @@ class ToolMixin(BaseMixin):
|
||||||
if search:
|
if search:
|
||||||
# Add additional search criteria
|
# Add additional search criteria
|
||||||
for fieldName, fieldValue in search.fields.iteritems():
|
for fieldName, fieldValue in search.fields.iteritems():
|
||||||
|
# Management of searches restricted to objects linked through a
|
||||||
|
# Ref field: not implemented yet.
|
||||||
|
if fieldName == '_ref': continue
|
||||||
# Make the correspondance between the name of the field and the
|
# Make the correspondance between the name of the field and the
|
||||||
# name of the corresponding index.
|
# name of the corresponding index.
|
||||||
attrName = Search.getIndexName(fieldName)
|
attrName = Search.getIndexName(fieldName)
|
||||||
|
@ -306,7 +322,9 @@ class ToolMixin(BaseMixin):
|
||||||
# Return brains only.
|
# Return brains only.
|
||||||
if not maxResults: return brains
|
if not maxResults: return brains
|
||||||
else: return brains[:maxResults]
|
else: return brains[:maxResults]
|
||||||
if not maxResults: maxResults = self.appy().numberOfResultsPerPage
|
if not maxResults:
|
||||||
|
if refField: maxResults = refField.maxPerPage
|
||||||
|
else: maxResults = self.appy().numberOfResultsPerPage
|
||||||
elif maxResults == 'NO_LIMIT': maxResults = None
|
elif maxResults == 'NO_LIMIT': maxResults = None
|
||||||
res = SomeObjects(brains, maxResults, startNumber,noSecurity=noSecurity)
|
res = SomeObjects(brains, maxResults, startNumber,noSecurity=noSecurity)
|
||||||
res.brainsToObjects()
|
res.brainsToObjects()
|
||||||
|
@ -327,13 +345,16 @@ class ToolMixin(BaseMixin):
|
||||||
s['search_%s' % searchName] = uids
|
s['search_%s' % searchName] = uids
|
||||||
return res.__dict__
|
return res.__dict__
|
||||||
|
|
||||||
def getResultColumnsNames(self, contentType):
|
def getResultColumnsNames(self, contentType, refField):
|
||||||
contentTypes = contentType.strip(',').split(',')
|
contentTypes = contentType.strip(',').split(',')
|
||||||
resSet = None # Temporary set for computing intersections.
|
resSet = None # Temporary set for computing intersections.
|
||||||
res = [] # Final, sorted result.
|
res = [] # Final, sorted result.
|
||||||
fieldNames = None
|
fieldNames = None
|
||||||
appyTool = self.appy()
|
appyTool = self.appy()
|
||||||
for cType in contentTypes:
|
for cType in contentTypes:
|
||||||
|
if refField:
|
||||||
|
fieldNames = refField.shownInfo
|
||||||
|
else:
|
||||||
fieldNames = getattr(appyTool, 'resultColumnsFor%s' % cType)
|
fieldNames = getattr(appyTool, 'resultColumnsFor%s' % cType)
|
||||||
if not resSet:
|
if not resSet:
|
||||||
resSet = set(fieldNames)
|
resSet = set(fieldNames)
|
||||||
|
@ -346,27 +367,6 @@ class ToolMixin(BaseMixin):
|
||||||
res.append(fieldName)
|
res.append(fieldName)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getResultColumns(self, anObject, contentType):
|
|
||||||
'''What columns must I show when displaying a list of root class
|
|
||||||
instances? Result is a list of tuples containing the name of the
|
|
||||||
column (=name of the field) and the corresponding appyType (dict
|
|
||||||
version).'''
|
|
||||||
res = []
|
|
||||||
for fieldName in self.getResultColumnsNames(contentType):
|
|
||||||
if fieldName == 'workflowState':
|
|
||||||
# We do not return a appyType if the attribute is not a *real*
|
|
||||||
# attribute, but the workfow state.
|
|
||||||
res.append(fieldName)
|
|
||||||
else:
|
|
||||||
appyType = anObject.getAppyType(fieldName, asDict=True)
|
|
||||||
if not appyType:
|
|
||||||
res.append({'name': fieldName, '_wrong': True})
|
|
||||||
# The field name is wrong.
|
|
||||||
# We return it so we can show it in an error message.
|
|
||||||
else:
|
|
||||||
res.append(appyType)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def truncateValue(self, value, appyType):
|
def truncateValue(self, value, appyType):
|
||||||
'''Truncates the p_value according to p_appyType width.'''
|
'''Truncates the p_value according to p_appyType width.'''
|
||||||
maxWidth = appyType['width']
|
maxWidth = appyType['width']
|
||||||
|
@ -452,14 +452,13 @@ class ToolMixin(BaseMixin):
|
||||||
return pythonClass.maySearch(self.appy())
|
return pythonClass.maySearch(self.appy())
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def userMayNavigate(self, someClass):
|
def userMayNavigate(self, obj):
|
||||||
'''This method checks if the currently logged user can display the
|
'''This method checks if the currently logged user can display the
|
||||||
navigation panel within the portlet. This is done by calling method
|
navigation panel within the portlet. This is done by calling method
|
||||||
"mayNavigate" on the class whose currently shown object is an
|
"mayNavigate" on the currently shown object. If no such method
|
||||||
instance of. If no such method exists, we return True.'''
|
exists, we return True.'''
|
||||||
pythonClass = self.getAppyClass(someClass)
|
appyObj = obj.appy()
|
||||||
if 'mayNavigate' in pythonClass.__dict__:
|
if hasattr(appyObj, 'mayNavigate'): return appyObj.mayNavigate()
|
||||||
return pythonClass.mayNavigate(self.appy())
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def onImportObjects(self):
|
def onImportObjects(self):
|
||||||
|
@ -485,8 +484,9 @@ class ToolMixin(BaseMixin):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def isSortable(self, name, className, usage):
|
def isSortable(self, name, className, usage):
|
||||||
'''Is field p_name defined on p_metaType sortable for p_usage purposes
|
'''Is field p_name defined on p_className sortable for p_usage purposes
|
||||||
(p_usage can be "ref" or "search")?'''
|
(p_usage can be "ref" or "search")?'''
|
||||||
|
if (',' in className) or (name == 'workflowState'): return False
|
||||||
appyType = self.getAppyType(name, className=className)
|
appyType = self.getAppyType(name, className=className)
|
||||||
return appyType.isSortable(usage=usage)
|
return appyType.isSortable(usage=usage)
|
||||||
|
|
||||||
|
@ -591,10 +591,14 @@ class ToolMixin(BaseMixin):
|
||||||
oper = ' %s ' % rq.form.get(operKey, 'or').upper()
|
oper = ' %s ' % rq.form.get(operKey, 'or').upper()
|
||||||
attrValue = oper.join(attrValue)
|
attrValue = oper.join(attrValue)
|
||||||
criteria[attrName[2:]] = attrValue
|
criteria[attrName[2:]] = attrValue
|
||||||
|
# Complete criteria with Ref info if the search is restricted to
|
||||||
|
# referenced objects of a Ref field.
|
||||||
|
refInfo = rq.get('ref', None)
|
||||||
|
if refInfo: criteria['_ref'] = refInfo
|
||||||
rq.SESSION['searchCriteria'] = criteria
|
rq.SESSION['searchCriteria'] = criteria
|
||||||
# Go to the screen that displays search results
|
# Go to the screen that displays search results
|
||||||
backUrl = '%s/query?type_name=%s&&search=_advanced' % \
|
backUrl = '%s/query?type_name=%s&&search=_advanced' % \
|
||||||
(os.path.dirname(rq['URL']), rq['type_name'])
|
(os.path.dirname(rq['URL']),rq['type_name'])
|
||||||
return self.goto(backUrl)
|
return self.goto(backUrl)
|
||||||
|
|
||||||
def getJavascriptMessages(self):
|
def getJavascriptMessages(self):
|
||||||
|
@ -605,6 +609,18 @@ class ToolMixin(BaseMixin):
|
||||||
res += 'var %s = "%s";\n' % (msg, self.translate(msg))
|
res += 'var %s = "%s";\n' % (msg, self.translate(msg))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def getRefInfo(self, refInfo=None):
|
||||||
|
'''When a search is restricted to objects referenced through a Ref
|
||||||
|
field, this method returns information about this reference: the
|
||||||
|
source content type and the Ref field (Appy type). If p_refInfo is
|
||||||
|
not given, we search it among search criteria in the session.'''
|
||||||
|
if not refInfo:
|
||||||
|
criteria = self.REQUEST.SESSION.get('searchCriteria', None)
|
||||||
|
if criteria and criteria.has_key('_ref'): refInfo = criteria['_ref']
|
||||||
|
if not refInfo: return ('', None)
|
||||||
|
sourceContentType, refField = refInfo.split(':')
|
||||||
|
return refInfo, self.getAppyType(refField, className=sourceContentType)
|
||||||
|
|
||||||
def getSearches(self, contentType):
|
def getSearches(self, contentType):
|
||||||
'''Returns the list of searches that are defined for p_contentType.
|
'''Returns the list of searches that are defined for p_contentType.
|
||||||
Every list item is a dict that contains info about a search or about
|
Every list item is a dict that contains info about a search or about
|
||||||
|
@ -650,8 +666,9 @@ class ToolMixin(BaseMixin):
|
||||||
on p_contentType.'''
|
on p_contentType.'''
|
||||||
baseUrl = self.getAppFolder().absolute_url() + '/skyn'
|
baseUrl = self.getAppFolder().absolute_url() + '/skyn'
|
||||||
baseParams = 'type_name=%s' % contentType
|
baseParams = 'type_name=%s' % contentType
|
||||||
# Manage start number
|
|
||||||
rq = self.REQUEST
|
rq = self.REQUEST
|
||||||
|
if rq.get('ref'): baseParams += '&ref=%s' % rq.get('ref')
|
||||||
|
# Manage start number
|
||||||
if startNumber != None:
|
if startNumber != None:
|
||||||
baseParams += '&startNumber=%s' % startNumber
|
baseParams += '&startNumber=%s' % startNumber
|
||||||
elif rq.has_key('startNumber'):
|
elif rq.has_key('startNumber'):
|
||||||
|
|
|
@ -490,9 +490,25 @@ class BaseMixin:
|
||||||
if tjs not in js: js.append(tjs)
|
if tjs not in js: js.append(tjs)
|
||||||
return css, js
|
return css, js
|
||||||
|
|
||||||
def getAppyTypesFromNames(self, fieldNames, asDict=True):
|
def getAppyTypesFromNames(self, fieldNames, asDict=True, addTitle=True):
|
||||||
'''Gets the Appy types names p_fieldNames.'''
|
'''Gets the Appy types named p_fieldNames. If 'title' is not among
|
||||||
return [self.getAppyType(name, asDict) for name in fieldNames]
|
p_fieldNames and p_addTitle is True, field 'title' is prepended to
|
||||||
|
the result.'''
|
||||||
|
res = []
|
||||||
|
for name in fieldNames:
|
||||||
|
appyType = self.getAppyType(name, asDict)
|
||||||
|
if appyType: res.append(appyType)
|
||||||
|
elif name == 'workflowState':
|
||||||
|
# We do not return a appyType if the attribute is not a *real*
|
||||||
|
# attribute, but the workfow state.
|
||||||
|
res.append({'name': name, 'labelId': 'workflow_state',
|
||||||
|
'filterable': False})
|
||||||
|
else:
|
||||||
|
self.appy().log('Field "%s", used as shownInfo in a Ref, ' \
|
||||||
|
'was not found.' % name, type='warning')
|
||||||
|
if addTitle and ('title' not in fieldNames):
|
||||||
|
res.insert(0, self.getAppyType('title', asDict))
|
||||||
|
return res
|
||||||
|
|
||||||
def getAppyStates(self, phase, currentOnly=False):
|
def getAppyStates(self, phase, currentOnly=False):
|
||||||
'''Returns information about the states that are related to p_phase.
|
'''Returns information about the states that are related to p_phase.
|
||||||
|
|
|
@ -71,7 +71,7 @@ class User(ModelClass):
|
||||||
_appy_attributes = ['title', 'name', 'firstName', 'login', 'password1',
|
_appy_attributes = ['title', 'name', 'firstName', 'login', 'password1',
|
||||||
'password2', 'roles']
|
'password2', 'roles']
|
||||||
# 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 = String(show=False)
|
title = String(show=False, indexed=True)
|
||||||
gm = {'group': 'main', 'multiplicity': (1,1)}
|
gm = {'group': 'main', 'multiplicity': (1,1)}
|
||||||
name = String(**gm)
|
name = String(**gm)
|
||||||
firstName = String(**gm)
|
firstName = String(**gm)
|
||||||
|
@ -109,8 +109,9 @@ class Tool(ModelClass):
|
||||||
# link to the predefined User class or a custom class defined in the
|
# link to the predefined User class or a custom class defined in the
|
||||||
# application.
|
# application.
|
||||||
users = Ref(None, multiplicity=(0,None), add=True, link=False,
|
users = Ref(None, multiplicity=(0,None), add=True, link=False,
|
||||||
back=Ref(attribute='toTool'), page='users',
|
back=Ref(attribute='toTool'), page='users', queryable=True,
|
||||||
shownInfo=('login', 'title', 'roles'), showHeaders=True)
|
queryFields=('login',), showHeaders=True,
|
||||||
|
shownInfo=('login', 'title', 'roles'))
|
||||||
enableNotifications = Boolean(default=True, page='notifications')
|
enableNotifications = Boolean(default=True, page='notifications')
|
||||||
def validPythonWithUno(self, value): pass # Real method in the wrapper
|
def validPythonWithUno(self, value): pass # Real method in the wrapper
|
||||||
unoEnabledPython = String(group="connectionToOpenOffice",
|
unoEnabledPython = String(group="connectionToOpenOffice",
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<metal:queryResults define-macro="queryResult"
|
<metal:queryResults define-macro="queryResult"
|
||||||
tal:define="tool python: contextObj;
|
tal:define="tool python: contextObj;
|
||||||
contentType request/type_name;
|
contentType request/type_name;
|
||||||
|
refInfo tool/getRefInfo;
|
||||||
|
refField python: refInfo[1];
|
||||||
|
refInfo python: refInfo[0];
|
||||||
startNumber request/startNumber|python:'0';
|
startNumber request/startNumber|python:'0';
|
||||||
startNumber python: int(startNumber);
|
startNumber python: int(startNumber);
|
||||||
searchName request/search;
|
searchName request/search;
|
||||||
|
@ -11,13 +14,13 @@
|
||||||
sortOrder request/sortOrder| python:'asc';
|
sortOrder request/sortOrder| python:'asc';
|
||||||
filterKey request/filterKey| python:'';
|
filterKey request/filterKey| python:'';
|
||||||
filterValue request/filterValue | python:'';
|
filterValue request/filterValue | python:'';
|
||||||
queryResult python: tool.executeQuery(contentType, searchName, startNumber, remember=True, sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey, filterValue=filterValue);
|
queryResult python: tool.executeQuery(contentType, searchName, startNumber, remember=True, sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey, filterValue=filterValue, refField=refField);
|
||||||
objs queryResult/objects;
|
objs queryResult/objects;
|
||||||
totalNumber queryResult/totalNumber;
|
totalNumber queryResult/totalNumber;
|
||||||
batchSize queryResult/batchSize;
|
batchSize queryResult/batchSize;
|
||||||
ajaxHookId python:'queryResult';
|
ajaxHookId python:'queryResult';
|
||||||
navBaseCall python: 'askQueryResult(\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, tool.absolute_url(), contentType, searchName);
|
navBaseCall python: 'askQueryResult(\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, tool.absolute_url(), contentType, searchName);
|
||||||
newSearchUrl python: '%s/skyn/search?type_name=%s&' % (tool.getAppFolder().absolute_url(), contentType);">
|
newSearchUrl python: '%s/skyn/search?type_name=%s&ref=%s' % (tool.getAppFolder().absolute_url(), contentType, refInfo);">
|
||||||
|
|
||||||
<tal:result condition="objs">
|
<tal:result condition="objs">
|
||||||
|
|
||||||
|
@ -42,44 +45,23 @@
|
||||||
</td>
|
</td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
|
|
||||||
<table tal:define="fieldDescrs python: tool.getResultColumns(objs[0], contentType)"
|
<table tal:define="fieldNames python: tool.getResultColumnsNames(contentType, refField);
|
||||||
|
widgets python: objs[0].getAppyTypesFromNames(fieldNames);"
|
||||||
class="listing nosort" width="100%" cellpadding="0" cellspacing="0">
|
class="listing nosort" width="100%" cellpadding="0" cellspacing="0">
|
||||||
<tal:comment replace="nothing">Every item in fieldDescrs is an Appy type (dict version),
|
|
||||||
excepted for workflow state (which is not a field): in this case it is simply the
|
|
||||||
string "workflow_state".</tal:comment>
|
|
||||||
|
|
||||||
<tal:comment replace="nothing">Headers, with filters and sort arrows</tal:comment>
|
<tal:comment replace="nothing">Headers, with filters and sort arrows</tal:comment>
|
||||||
<tr>
|
<tr>
|
||||||
<tal:comment replace="nothing">Mandatory column "Title"/"Name"</tal:comment>
|
<tal:header repeat="widget widgets">
|
||||||
|
<th tal:define="sortable python: tool.isSortable(widget['name'], contentType, 'search');
|
||||||
<th tal:define="fieldName python:'title'; sortable python:True; filterable python:True">
|
filterable widget/filterable|nothing;">
|
||||||
<span tal:replace="structure python: tool.truncateText(tool.translate('ref_name'))"/>
|
<span tal:replace="structure python: tool.truncateText(tool.translate(widget['labelId']))"/>
|
||||||
<metal:sortAndFilter use-macro="here/skyn/navigate/macros/sortAndFilter"/>
|
<metal:icons use-macro="here/skyn/navigate/macros/sortAndFilter"/>
|
||||||
</th>
|
</th>
|
||||||
|
</tal:header>
|
||||||
<tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
|
<tal:comment replace="nothing">Object type, shown if instances of several types are shown</tal:comment>
|
||||||
<tal:columnHeader repeat="fieldDescr fieldDescrs">
|
|
||||||
<th tal:define="fieldName fieldDescr/name|string:workflow_state;
|
|
||||||
sortable python: tool.isSortable(fieldName, contentType, 'search');
|
|
||||||
filterable fieldDescr/filterable|nothing;">
|
|
||||||
<tal:comment replace="nothing">Display header for a "standard" field</tal:comment>
|
|
||||||
<tal:standardField condition="python: fieldName != 'workflow_state'">
|
|
||||||
<span tal:replace="structure python: tool.truncateText(tool.translate(fieldDescr['labelId']))"/>
|
|
||||||
</tal:standardField>
|
|
||||||
<tal:comment replace="nothing">Display header for the workflow state</tal:comment>
|
|
||||||
<tal:workflowState condition="python: fieldName == 'workflow_state'">
|
|
||||||
<span tal:replace="python: tool.translate('workflow_state')"/>
|
|
||||||
</tal:workflowState>
|
|
||||||
<metal:sortAndFilter use-macro="here/skyn/navigate/macros/sortAndFilter"/>
|
|
||||||
</th>
|
|
||||||
</tal:columnHeader>
|
|
||||||
|
|
||||||
<tal:comment replace="nothing">Column "Object type", shown if instances of several types are shown</tal:comment>
|
|
||||||
<th tal:condition="severalTypes">
|
<th tal:condition="severalTypes">
|
||||||
<span tal:replace="python: tool.translate('root_type')"/>
|
<span tal:replace="python: tool.translate('root_type')"></span>
|
||||||
</th>
|
</th>
|
||||||
|
<tal:comment replace="nothing">Actions</tal:comment>
|
||||||
<tal:comment replace="nothing">Column "Actions"</tal:comment>
|
|
||||||
<th tal:content="python: tool.translate('ref_actions')"></th>
|
<th tal:content="python: tool.translate('ref_actions')"></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@ -88,15 +70,22 @@
|
||||||
<tr id="query_row" tal:define="odd repeat/obj/odd"
|
<tr id="query_row" tal:define="odd repeat/obj/odd"
|
||||||
tal:attributes="class python:test(odd, 'even', 'odd')">
|
tal:attributes="class python:test(odd, 'even', 'odd')">
|
||||||
|
|
||||||
<tal:comment replace="nothing">Mandatory column "Title"/"Name"</tal:comment>
|
<tal:fields repeat="widget widgets">
|
||||||
<td id="field_title"><a
|
<tal:comment replace="nothing">Title</tal:comment>
|
||||||
tal:define="navInfo python:'search.%s.%s.%d.%d' % (contentType, searchName, repeat['obj'].number()+startNumber, totalNumber);"
|
<td id="field_title"
|
||||||
tal:content="obj/Title" tal:attributes="href python: obj.getUrl(nav=navInfo, page='main')"></a></td>
|
tal:condition="python: widget['name'] == 'title'">
|
||||||
|
<a tal:define="navInfo python:'search.%s.%s.%d.%d' % (contentType, searchName, repeat['obj'].number()+startNumber, totalNumber);"
|
||||||
|
tal:content="obj/Title" tal:attributes="href python: obj.getUrl(nav=navInfo, page='main')"></a>
|
||||||
|
</td>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
|
<tal:comment replace="nothing">Workflow state</tal:comment>
|
||||||
<tal:otherFields repeat="widget fieldDescrs">
|
<td id="field_workflow_state"
|
||||||
<tal:standardField condition="python: widget != 'workflowState'">
|
tal:condition="python: widget['name'] == 'workflowState'"
|
||||||
<td tal:condition="python: '_wrong' not in widget"
|
tal:content="python: tool.translate(obj.getWorkflowLabel())">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<tal:comment replace="nothing">Any other field</tal:comment>
|
||||||
|
<td tal:condition="python: widget['name'] not in ('title', 'workflowState')"
|
||||||
tal:attributes="id python:'field_%s' % widget['name']">
|
tal:attributes="id python:'field_%s' % widget['name']">
|
||||||
<tal:field define="contextObj python:obj;
|
<tal:field define="contextObj python:obj;
|
||||||
layoutType python:'cell';
|
layoutType python:'cell';
|
||||||
|
@ -105,14 +94,7 @@
|
||||||
<metal:field use-macro="here/skyn/widgets/show/macros/field"/>
|
<metal:field use-macro="here/skyn/widgets/show/macros/field"/>
|
||||||
</tal:field>
|
</tal:field>
|
||||||
</td>
|
</td>
|
||||||
<td tal:condition="python: '_wrong' in widget" style="color:red">Field
|
</tal:fields>
|
||||||
<span tal:replace="widget/name"/> not found.
|
|
||||||
</td>
|
|
||||||
</tal:standardField>
|
|
||||||
<tal:workflowState condition="python: widget == 'workflowState'">
|
|
||||||
<td id="field_workflow_state" tal:content="python: tool.translate(obj.getWorkflowLabel())"></td>
|
|
||||||
</tal:workflowState>
|
|
||||||
</tal:otherFields>
|
|
||||||
|
|
||||||
<tal:comment replace="nothing">Column "Object type", shown if instances of several types are shown</tal:comment>
|
<tal:comment replace="nothing">Column "Object type", shown if instances of several types are shown</tal:comment>
|
||||||
<td tal:condition="severalTypes" id="field_root_type"
|
<td tal:condition="severalTypes" id="field_root_type"
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
This macro displays up/down arrows in a table header column for sorting a given column.
|
This macro displays up/down arrows in a table header column for sorting a given column.
|
||||||
It requires variables "sortable", 'filterable' and 'fieldName'.
|
It requires variables "sortable", 'filterable' and 'fieldName'.
|
||||||
</tal:comment>
|
</tal:comment>
|
||||||
<metal:sortAndFilter define-macro="sortAndFilter">
|
<metal:sortAndFilter define-macro="sortAndFilter" tal:define="fieldName widget/name">
|
||||||
<tal:sort condition="sortable">
|
<tal:sort condition="sortable">
|
||||||
<img tal:attributes="src string: $portal_url/skyn/sortDown.gif;
|
<img tal:attributes="src string: $portal_url/skyn/sortDown.gif;
|
||||||
onClick python: navBaseCall.replace('**v**', '0,\'%s\',\'asc\',\'%s\'' % (fieldName, filterKey))"
|
onClick python: navBaseCall.replace('**v**', '0,\'%s\',\'asc\',\'%s\'' % (fieldName, filterKey))"
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
</td>
|
</td>
|
||||||
</dt>
|
</dt>
|
||||||
|
|
||||||
<tal:publishedObject condition="python: contextObj and tool.userMayNavigate(contextObj.meta_type)">
|
<tal:publishedObject condition="python: contextObj and tool.userMayNavigate(contextObj)">
|
||||||
<dt class="portletAppyItem portletCurrent"><b tal:content="contextObj/Title"></b></dt>
|
<dt class="portletAppyItem portletCurrent"><b tal:content="contextObj/Title"></b></dt>
|
||||||
<dt class="portletAppyItem"><metal:phases use-macro="here/skyn/portlet/macros/phases"/></dt>
|
<dt class="portletAppyItem"><metal:phases use-macro="here/skyn/portlet/macros/phases"/></dt>
|
||||||
</tal:publishedObject>
|
</tal:publishedObject>
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
tal:define="appFolder context/getParentNode;
|
tal:define="appFolder context/getParentNode;
|
||||||
appName appFolder/id;
|
appName appFolder/id;
|
||||||
tool python: portal.get('portal_%s' % appName.lower());
|
tool python: portal.get('portal_%s' % appName.lower());
|
||||||
contentType python:context.REQUEST.get('type_name');
|
contentType request/type_name;
|
||||||
searchName python:context.REQUEST.get('search', '')">
|
searchName request/search|python:'';">
|
||||||
|
|
||||||
<div metal:use-macro="here/skyn/page/macros/prologue"/>
|
<div metal:use-macro="here/skyn/page/macros/prologue"/>
|
||||||
<tal:comment replace="nothing">Query result</tal:comment>
|
<tal:comment replace="nothing">Query result</tal:comment>
|
||||||
|
|
|
@ -15,8 +15,11 @@
|
||||||
<metal:fill fill-slot="main"
|
<metal:fill fill-slot="main"
|
||||||
tal:define="appFolder context/getParentNode;
|
tal:define="appFolder context/getParentNode;
|
||||||
contentType request/type_name;
|
contentType request/type_name;
|
||||||
|
refInfo request/ref|nothing;
|
||||||
tool python: portal.get('portal_%s' % appFolder.id.lower());
|
tool python: portal.get('portal_%s' % appFolder.id.lower());
|
||||||
searchableFields python: tool.getSearchableFields(contentType)">
|
searchInfo python: tool.getSearchInfo(contentType, refInfo);
|
||||||
|
searchableFields python: searchInfo[0];
|
||||||
|
numberOfColumns python: searchInfo[1]">
|
||||||
|
|
||||||
<tal:comment replace="nothing">Search title</tal:comment>
|
<tal:comment replace="nothing">Search title</tal:comment>
|
||||||
<h1><span tal:replace="python: tool.translate('%s_plural' % contentType)"/> —
|
<h1><span tal:replace="python: tool.translate('%s_plural' % contentType)"/> —
|
||||||
|
@ -26,9 +29,9 @@
|
||||||
<form name="search" tal:attributes="action python: appFolder.absolute_url()+'/skyn/do'" method="post">
|
<form name="search" tal:attributes="action python: appFolder.absolute_url()+'/skyn/do'" method="post">
|
||||||
<input type="hidden" name="action" value="SearchObjects"/>
|
<input type="hidden" name="action" value="SearchObjects"/>
|
||||||
<input type="hidden" name="type_name" tal:attributes="value contentType"/>
|
<input type="hidden" name="type_name" tal:attributes="value contentType"/>
|
||||||
|
<input tal:condition="refInfo" type="hidden" name="ref" tal:attributes="value refInfo"/>
|
||||||
|
|
||||||
<table class="no-style-table" cellpadding="0" cellspacing="0" width="100%"
|
<table class="no-style-table" cellpadding="0" cellspacing="0" width="100%">
|
||||||
tal:define="numberOfColumns python: tool.getAttr('numberOfSearchColumnsFor%s' % contentType)">
|
|
||||||
<tr tal:repeat="searchRow python: tool.tabularize(searchableFields, numberOfColumns)" valign="top">
|
<tr tal:repeat="searchRow python: tool.tabularize(searchableFields, numberOfColumns)" valign="top">
|
||||||
<td tal:repeat="widget searchRow" tal:attributes="width python:'%d%%' % (100/numberOfColumns)">
|
<td tal:repeat="widget searchRow" tal:attributes="width python:'%d%%' % (100/numberOfColumns)">
|
||||||
<tal:field condition="widget">
|
<tal:field condition="widget">
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
ref field according to the field that corresponds to this column.
|
ref field according to the field that corresponds to this column.
|
||||||
</tal:comment>
|
</tal:comment>
|
||||||
<metal:sortIcons define-macro="sortIcons"
|
<metal:sortIcons define-macro="sortIcons"
|
||||||
tal:define="ajaxBaseCall python: navBaseCall.replace('**v**', '\'%s\',\'SortReference\', {\'sortKey\':\'%s\', \'reverse\':\'**v**\'}' % (startNumber, shownField))" tal:condition="python: canWrite and tool.isSortable(shownField, objs[0].meta_type, 'ref')">
|
tal:define="ajaxBaseCall python: navBaseCall.replace('**v**', '\'%s\',\'SortReference\', {\'sortKey\':\'%s\', \'reverse\':\'**v**\'}' % (startNumber, widget['name']))" tal:condition="python: canWrite and tool.isSortable(widget['name'], objs[0].meta_type, 'ref')">
|
||||||
<img style="cursor:pointer"
|
<img style="cursor:pointer"
|
||||||
tal:attributes="src string:$portal_url/skyn/sortAsc.png;
|
tal:attributes="src string:$portal_url/skyn/sortAsc.png;
|
||||||
onClick python: ajaxBaseCall.replace('**v**', 'False')"/>
|
onClick python: ajaxBaseCall.replace('**v**', 'False')"/>
|
||||||
|
@ -159,6 +159,10 @@
|
||||||
<span tal:condition="not: innerRef" tal:content="label"/>
|
<span tal:condition="not: innerRef" tal:content="label"/>
|
||||||
(<span tal:replace="totalNumber"/>)
|
(<span tal:replace="totalNumber"/>)
|
||||||
<metal:plusIcon use-macro="portal/skyn/widgets/ref/macros/plusIcon"/>
|
<metal:plusIcon use-macro="portal/skyn/widgets/ref/macros/plusIcon"/>
|
||||||
|
<tal:comment replace="nothing">The search icon if field is queryable</tal:comment>
|
||||||
|
<a tal:condition="appyType/queryable"
|
||||||
|
tal:attributes="href python: '%s/skyn/search?type_name=%s&ref=%s:%s' % (tool.getAppFolder().absolute_url(), linkedPortalType, contextObj.meta_type, appyType['name'])">
|
||||||
|
<img src="search.gif" tal:attributes="title python: tool.translate('search_objects')"/></a>
|
||||||
</legend>
|
</legend>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Object description</tal:comment>
|
<tal:comment replace="nothing">Object description</tal:comment>
|
||||||
|
@ -185,44 +189,34 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Show forward reference(s)</tal:comment>
|
<tal:comment replace="nothing">Show forward reference(s)</tal:comment>
|
||||||
|
|
||||||
<table tal:attributes="class python:test(innerRef, '', 'listing nosort');
|
<table tal:attributes="class python:test(innerRef, '', 'listing nosort');
|
||||||
width python:test(innerRef, '100%', appyType['layouts']['view']['width']);"
|
width python:test(innerRef, '100%', appyType['layouts']['view']['width']);"
|
||||||
align="right" tal:condition="python: not appyType['isBack'] and objs" cellpadding="0" cellspacing="0">
|
align="right" tal:condition="python: not appyType['isBack'] and objs" cellpadding="0" cellspacing="0">
|
||||||
<tal:widgets define="widgets python: objs[0].getAppyTypesFromNames(appyType['shownInfo'])">
|
<tal:widgets define="widgets python: objs[0].getAppyTypesFromNames(appyType['shownInfo'])">
|
||||||
<tr tal:condition="appyType/showHeaders">
|
<tr tal:condition="appyType/showHeaders">
|
||||||
<th tal:condition="python: 'title' not in appyType['shownInfo']"
|
|
||||||
tal:define="shownField python:'title'">
|
|
||||||
<span tal:content="python: tool.translate('ref_name')"></span>
|
|
||||||
<metal:sortIcons use-macro="portal/skyn/widgets/ref/macros/sortIcons" />
|
|
||||||
</th>
|
|
||||||
<th tal:repeat="widget widgets">
|
<th tal:repeat="widget widgets">
|
||||||
<tal:header define="shownField widget/name">
|
|
||||||
<span tal:content="python: tool.translate(widget['labelId'])"></span>
|
<span tal:content="python: tool.translate(widget['labelId'])"></span>
|
||||||
<metal:sortIcons use-macro="portal/skyn/widgets/ref/macros/sortIcons" />
|
<metal:sortIcons use-macro="portal/skyn/widgets/ref/macros/sortIcons" />
|
||||||
</tal:header>
|
|
||||||
</th>
|
</th>
|
||||||
<th tal:content="python: tool.translate('ref_actions')"></th>
|
<th tal:content="python: tool.translate('ref_actions')"></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tal:row repeat="obj objs">
|
<tal:row repeat="obj objs">
|
||||||
<tr valign="top" tal:define="odd repeat/obj/odd"
|
<tr valign="top" tal:define="odd repeat/obj/odd"
|
||||||
tal:attributes="class python:test(odd, 'even', 'odd')">
|
tal:attributes="class python:test(odd, 'even', 'odd')">
|
||||||
<tal:comment replace="nothing">Object title, shown here if not specified somewhere
|
|
||||||
else in appyType.shownInfo.</tal:comment>
|
|
||||||
<td tal:condition="python: 'title' not in appyType['shownInfo']"><metal:showObjectTitle
|
|
||||||
use-macro="portal/skyn/widgets/ref/macros/objectTitle"/>
|
|
||||||
</td>
|
|
||||||
<tal:comment replace="nothing">Additional fields that must be shown</tal:comment>
|
|
||||||
<td tal:repeat="widget widgets">
|
<td tal:repeat="widget widgets">
|
||||||
<tal:showTitle condition="python: widget['name'] == 'title'">
|
<tal:title condition="python: widget['name'] == 'title'">
|
||||||
<metal:showObjectTitle use-macro="portal/skyn/widgets/ref/macros/objectTitle"/>
|
<metal:showObjectTitle use-macro="portal/skyn/widgets/ref/macros/objectTitle"/>
|
||||||
</tal:showTitle>
|
</tal:title>
|
||||||
<tal:showOtherField define="contextObj python:obj;
|
<tal:state condition="python: widget['name'] == 'workflowState'"
|
||||||
|
content="python: tool.translate(obj.getWorkflowLabel())">
|
||||||
|
</tal:state>
|
||||||
|
<tal:other condition="python: widget['name'] not in ('title', 'workflowState')">
|
||||||
|
<tal:field define="contextObj python:obj;
|
||||||
layoutType python: 'cell';
|
layoutType python: 'cell';
|
||||||
innerRef python:True"
|
innerRef python:True">
|
||||||
condition="python: widget['name'] != 'title'">
|
<metal:field use-macro="portal/skyn/widgets/show/macros/field" />
|
||||||
<metal:showField use-macro="portal/skyn/widgets/show/macros/field" />
|
</tal:field>
|
||||||
</tal:showOtherField>
|
</tal:other>
|
||||||
</td>
|
</td>
|
||||||
<tal:comment replace="nothing">Actions</tal:comment>
|
<tal:comment replace="nothing">Actions</tal:comment>
|
||||||
<td align="right">
|
<td align="right">
|
||||||
|
@ -232,7 +226,6 @@
|
||||||
</tal:row>
|
</tal:row>
|
||||||
</tal:widgets>
|
</tal:widgets>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,9 @@
|
||||||
<table metal:define-macro="groupContent"
|
<table metal:define-macro="groupContent"
|
||||||
tal:attributes="width python: test(widget['wide'], '100%', '');
|
tal:attributes="width python: test(widget['wide'], '100%', '');
|
||||||
align widget/align;
|
align widget/align;
|
||||||
class widget/css_class">
|
class widget/css_class;
|
||||||
|
cellspacing widget/cellspacing;
|
||||||
|
cellpadding widget/cellpadding">
|
||||||
<tal:comment replace="nothing">Display the title of the group if it is not rendered a fieldset.</tal:comment>
|
<tal:comment replace="nothing">Display the title of the group if it is not rendered a fieldset.</tal:comment>
|
||||||
<tr tal:condition="python: (widget['style'] != 'fieldset') and widget['hasLabel']">
|
<tr tal:condition="python: (widget['style'] != 'fieldset') and widget['hasLabel']">
|
||||||
<td tal:attributes="colspan python: len(widget['columnsWidths']);
|
<td tal:attributes="colspan python: len(widget['columnsWidths']);
|
||||||
|
|
|
@ -46,7 +46,6 @@ class PoMessage:
|
||||||
POD_ASKACTION = 'Trigger related action'
|
POD_ASKACTION = 'Trigger related action'
|
||||||
REF_NO = 'No object.'
|
REF_NO = 'No object.'
|
||||||
REF_ADD = 'Add a new one'
|
REF_ADD = 'Add a new one'
|
||||||
REF_NAME = 'Name'
|
|
||||||
REF_ACTIONS = 'Actions'
|
REF_ACTIONS = 'Actions'
|
||||||
REF_MOVE_UP = 'Move up'
|
REF_MOVE_UP = 'Move up'
|
||||||
REF_MOVE_DOWN = 'Move down'
|
REF_MOVE_DOWN = 'Move down'
|
||||||
|
|
Loading…
Reference in a new issue