appy.pod: bugfix when importing images under Windows (https://answers.launchpad.net/appy/+question/171611); appy.gen: bugfix while validating file fields which are mandatory; stopped using uid_catalog and added index 'UID' in portal_catalog; bugfix while searching objects in the limits of a Ref field; display user info in the main template (name, id, roles); when creating an object from a reference, after creation, appy brings the user back to the view page where the Ref field was.
This commit is contained in:
parent
7ff56a6520
commit
96a592f125
|
@ -1 +1 @@
|
||||||
0.7.0
|
0.7.1
|
||||||
|
|
|
@ -1412,7 +1412,7 @@ class Boolean(Type):
|
||||||
self.pythonType = bool
|
self.pythonType = bool
|
||||||
|
|
||||||
def getDefaultLayouts(self):
|
def getDefaultLayouts(self):
|
||||||
return {'view': 'l;f!_', 'edit': Table('f;lrv;=', width=None)}
|
return {'view': 'l;f!-', 'edit': Table('f;lrv;=', width=None)}
|
||||||
|
|
||||||
def getValue(self, obj):
|
def getValue(self, obj):
|
||||||
'''Never returns "None". Returns always "True" or "False", even if
|
'''Never returns "None". Returns always "True" or "False", even if
|
||||||
|
@ -1566,7 +1566,7 @@ class File(Type):
|
||||||
def isEmptyValue(self, value, obj=None):
|
def isEmptyValue(self, value, obj=None):
|
||||||
'''Must p_value be considered as empty?'''
|
'''Must p_value be considered as empty?'''
|
||||||
if not obj: return Type.isEmptyValue(self, value)
|
if not obj: return Type.isEmptyValue(self, value)
|
||||||
if value is not None: return False
|
if value: return False
|
||||||
# If "nochange", the value must not be considered as empty
|
# If "nochange", the value must not be considered as empty
|
||||||
return obj.REQUEST.get('%s_delete' % self.name) != 'nochange'
|
return obj.REQUEST.get('%s_delete' % self.name) != 'nochange'
|
||||||
|
|
||||||
|
@ -1795,14 +1795,14 @@ class Ref(Type):
|
||||||
# Get the needed referred objects
|
# Get the needed referred objects
|
||||||
i = res.startNumber
|
i = res.startNumber
|
||||||
# Is it possible and more efficient to perform a single query in
|
# Is it possible and more efficient to perform a single query in
|
||||||
# uid_catalog and get the result in the order of specified uids?
|
# portal_catalog and get the result in the order of specified uids?
|
||||||
while i < (res.startNumber + res.batchSize):
|
while i < (res.startNumber + res.batchSize):
|
||||||
if i >= res.totalNumber: break
|
if i >= res.totalNumber: break
|
||||||
# Retrieve every reference in the correct format according to p_type
|
# Retrieve every reference in the correct format according to p_type
|
||||||
if type == 'uids':
|
if type == 'uids':
|
||||||
ref = uids[i]
|
ref = uids[i]
|
||||||
else:
|
else:
|
||||||
ref = obj.uid_catalog(UID=uids[i])[0].getObject()
|
ref = obj.portal_catalog(UID=uids[i])[0].getObject()
|
||||||
if type == 'objects':
|
if type == 'objects':
|
||||||
ref = ref.appy()
|
ref = ref.appy()
|
||||||
res.objects.append(ref)
|
res.objects.append(ref)
|
||||||
|
@ -1859,7 +1859,7 @@ class Ref(Type):
|
||||||
for i in range(len(refs)):
|
for i in range(len(refs)):
|
||||||
if isinstance(refs[i], basestring):
|
if isinstance(refs[i], basestring):
|
||||||
# Get the Zope object from the UID
|
# Get the Zope object from the UID
|
||||||
refs[i] = obj.uid_catalog(UID=refs[i])[0].getObject()
|
refs[i] = obj.portal_catalog(UID=refs[i])[0].getObject()
|
||||||
else:
|
else:
|
||||||
refs[i] = refs[i].o # Now we are sure to have a Zope object.
|
refs[i] = refs[i].o # Now we are sure to have a Zope object.
|
||||||
# Update the field storing on p_obj the ordered list of UIDs
|
# Update the field storing on p_obj the ordered list of UIDs
|
||||||
|
|
|
@ -168,8 +168,6 @@ class Generator(AbstractGenerator):
|
||||||
self.copyFile('ProfileInit.py', self.repls, destFolder='profiles',
|
self.copyFile('ProfileInit.py', self.repls, destFolder='profiles',
|
||||||
destName='__init__.py')
|
destName='__init__.py')
|
||||||
self.copyFile('tool.gif', {})
|
self.copyFile('tool.gif', {})
|
||||||
self.copyFile('Styles.css.dtml',self.repls, destFolder=self.skinsFolder,
|
|
||||||
destName = '%s.css.dtml' % self.applicationName)
|
|
||||||
# Create version.txt
|
# Create version.txt
|
||||||
f = open(os.path.join(self.outputFolder, 'version.txt'), 'w')
|
f = open(os.path.join(self.outputFolder, 'version.txt'), 'w')
|
||||||
f.write(self.version)
|
f.write(self.version)
|
||||||
|
@ -352,14 +350,6 @@ class Generator(AbstractGenerator):
|
||||||
for c in classes])
|
for c in classes])
|
||||||
repls['allClassNames'] = ','.join(['"%s"' % c.name \
|
repls['allClassNames'] = ','.join(['"%s"' % c.name \
|
||||||
for c in classesButTool])
|
for c in classesButTool])
|
||||||
# Compute classes whose instances must not be catalogued.
|
|
||||||
catalogMap = ''
|
|
||||||
blackClasses = [self.tool.name]
|
|
||||||
for blackClass in blackClasses:
|
|
||||||
catalogMap += "catalogMap['%s'] = {}\n" % blackClass
|
|
||||||
catalogMap += "catalogMap['%s']['black'] = " \
|
|
||||||
"['portal_catalog']\n" % blackClass
|
|
||||||
repls['catalogMap'] = catalogMap
|
|
||||||
# Compute the list of ordered attributes (forward and backward,
|
# Compute the list of ordered attributes (forward and backward,
|
||||||
# inherited included) for every Appy class.
|
# inherited included) for every Appy class.
|
||||||
attributes = []
|
attributes = []
|
||||||
|
|
|
@ -30,7 +30,6 @@ class PloneInstaller:
|
||||||
self.appClasses = cfg.appClasses
|
self.appClasses = cfg.appClasses
|
||||||
self.appClassNames = cfg.appClassNames
|
self.appClassNames = cfg.appClassNames
|
||||||
self.allClassNames = cfg.allClassNames
|
self.allClassNames = cfg.allClassNames
|
||||||
self.catalogMap = cfg.catalogMap
|
|
||||||
self.applicationRoles = cfg.applicationRoles # Roles defined in the app
|
self.applicationRoles = cfg.applicationRoles # Roles defined in the app
|
||||||
self.defaultAddRoles = cfg.defaultAddRoles
|
self.defaultAddRoles = cfg.defaultAddRoles
|
||||||
self.appFrontPage = cfg.appFrontPage
|
self.appFrontPage = cfg.appFrontPage
|
||||||
|
@ -197,20 +196,9 @@ class PloneInstaller:
|
||||||
factoryTypes = self.allClassNames + factoryTool.getFactoryTypes().keys()
|
factoryTypes = self.allClassNames + factoryTool.getFactoryTypes().keys()
|
||||||
factoryTool.manage_setPortalFactoryTypes(listOfTypeIds=factoryTypes)
|
factoryTool.manage_setPortalFactoryTypes(listOfTypeIds=factoryTypes)
|
||||||
|
|
||||||
# Configure CatalogMultiplex: tell what types will be catalogued or not.
|
# Whitelist tool in Archetypes, because now UID is in portal_catalog
|
||||||
atTool = getattr(site, self.config.ARCHETYPETOOLNAME)
|
atTool = getattr(site, self.config.ARCHETYPETOOLNAME)
|
||||||
for meta_type in self.catalogMap:
|
atTool.setCatalogsByType(self.toolName, ['portal_catalog'])
|
||||||
submap = self.catalogMap[meta_type]
|
|
||||||
current_catalogs = Set(
|
|
||||||
[c.id for c in atTool.getCatalogsByType(meta_type)])
|
|
||||||
if 'white' in submap:
|
|
||||||
for catalog in submap['white']:
|
|
||||||
current_catalogs.update([catalog])
|
|
||||||
if 'black' in submap:
|
|
||||||
for catalog in submap['black']:
|
|
||||||
if catalog in current_catalogs:
|
|
||||||
current_catalogs.remove(catalog)
|
|
||||||
atTool.setCatalogsByType(meta_type, list(current_catalogs))
|
|
||||||
|
|
||||||
def updatePodTemplates(self):
|
def updatePodTemplates(self):
|
||||||
'''Creates or updates the POD templates in the tool according to pod
|
'''Creates or updates the POD templates in the tool according to pod
|
||||||
|
@ -259,7 +247,6 @@ class PloneInstaller:
|
||||||
else:
|
else:
|
||||||
self.tool.createOrUpdate(True, None)
|
self.tool.createOrUpdate(True, None)
|
||||||
self.updatePodTemplates()
|
self.updatePodTemplates()
|
||||||
self.tool.unindexObject()
|
|
||||||
|
|
||||||
def installTranslations(self):
|
def installTranslations(self):
|
||||||
'''Creates or updates the translation objects within the tool.'''
|
'''Creates or updates the translation objects within the tool.'''
|
||||||
|
@ -336,7 +323,7 @@ class PloneInstaller:
|
||||||
corresponding index if it does not exist yet.'''
|
corresponding index if it does not exist yet.'''
|
||||||
# Create a special index for object state, that does not correspond to
|
# Create a special index for object state, that does not correspond to
|
||||||
# a field.
|
# a field.
|
||||||
indexInfo = {'getState': 'FieldIndex'}
|
indexInfo = {'getState': 'FieldIndex', 'UID': 'FieldIndex'}
|
||||||
for className in self.attributes.iterkeys():
|
for className in self.attributes.iterkeys():
|
||||||
wrapperClass = self.tool.getAppyClass(className, wrapper=True)
|
wrapperClass = self.tool.getAppyClass(className, wrapper=True)
|
||||||
for appyType in wrapperClass.__fields__:
|
for appyType in wrapperClass.__fields__:
|
||||||
|
|
|
@ -87,7 +87,7 @@ class ToolMixin(BaseMixin):
|
||||||
if appyType.name == 'title': continue # Will be included by default.
|
if appyType.name == 'title': continue # Will be included by default.
|
||||||
res.append((appyType.name, self.translate(appyType.labelId)))
|
res.append((appyType.name, self.translate(appyType.labelId)))
|
||||||
# Add object state
|
# Add object state
|
||||||
res.append(('workflowState', self.translate('workflow_state')))
|
res.append(('state', self.translate('workflow_state')))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def _appy_getSearchableFields(self, contentType):
|
def _appy_getSearchableFields(self, contentType):
|
||||||
|
@ -108,7 +108,8 @@ class ToolMixin(BaseMixin):
|
||||||
fieldDicts = []
|
fieldDicts = []
|
||||||
if refInfo:
|
if refInfo:
|
||||||
# The search is triggered from a Ref field.
|
# The search is triggered from a Ref field.
|
||||||
refField = self.getRefInfo(refInfo)[1]
|
refObject, fieldName = self.getRefInfo(refInfo)
|
||||||
|
refField = refObject.getAppyType(fieldName)
|
||||||
fieldNames = refField.queryFields or ()
|
fieldNames = refField.queryFields or ()
|
||||||
nbOfColumns = refField.queryNbCols
|
nbOfColumns = refField.queryNbCols
|
||||||
else:
|
else:
|
||||||
|
@ -172,7 +173,7 @@ class ToolMixin(BaseMixin):
|
||||||
|
|
||||||
def getObject(self, uid, appy=False):
|
def getObject(self, uid, appy=False):
|
||||||
'''Allows to retrieve an object from its p_uid.'''
|
'''Allows to retrieve an object from its p_uid.'''
|
||||||
res = self.uid_catalog(UID=uid)
|
res = self.portal_catalog(UID=uid)
|
||||||
if res:
|
if res:
|
||||||
res = res[0].getObject()
|
res = res[0].getObject()
|
||||||
if appy:
|
if appy:
|
||||||
|
@ -183,10 +184,10 @@ class ToolMixin(BaseMixin):
|
||||||
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):
|
refObject=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 portal_catalog. If p_searchName is specified, it
|
||||||
it corresponds to:
|
corresponds to:
|
||||||
1) a search defined on p_contentType: additional search criteria
|
1) a search defined on p_contentType: additional search criteria
|
||||||
will be added to the query, or;
|
will be added to the query, or;
|
||||||
2) "_advanced": in this case, additional search criteria will also
|
2) "_advanced": in this case, additional search criteria will also
|
||||||
|
@ -221,8 +222,8 @@ class ToolMixin(BaseMixin):
|
||||||
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
|
If p_refObject and p_refField are given, the query is limited to the
|
||||||
referenced through it.'''
|
objects that are referenced from p_refObject through p_refField.'''
|
||||||
# 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(',')
|
||||||
|
@ -267,6 +268,9 @@ class ToolMixin(BaseMixin):
|
||||||
# TODO This value needs to be merged with an existing one if already
|
# TODO This value needs to be merged with an existing one if already
|
||||||
# in params, or, in a first step, we should avoid to display the
|
# in params, or, in a first step, we should avoid to display the
|
||||||
# corresponding filter widget on the screen.
|
# corresponding filter widget on the screen.
|
||||||
|
if refObject:
|
||||||
|
refField = refObject.getAppyType(refField)
|
||||||
|
params['UID'] = refObject._appy_getSortedField(refField.name).data
|
||||||
# Determine what method to call on the portal catalog
|
# Determine what method to call on the portal catalog
|
||||||
if noSecurity: catalogMethod = 'unrestrictedSearchResults'
|
if noSecurity: catalogMethod = 'unrestrictedSearchResults'
|
||||||
else: catalogMethod = 'searchResults'
|
else: catalogMethod = 'searchResults'
|
||||||
|
@ -297,12 +301,14 @@ class ToolMixin(BaseMixin):
|
||||||
self.REQUEST.SESSION['search_%s' % searchName] = uids
|
self.REQUEST.SESSION['search_%s' % searchName] = uids
|
||||||
return res.__dict__
|
return res.__dict__
|
||||||
|
|
||||||
def getResultColumnsNames(self, contentType, refField):
|
def getResultColumnsNames(self, contentType, refInfo):
|
||||||
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()
|
||||||
|
refField = None
|
||||||
|
if refInfo[0]: refField = refInfo[0].getAppyType(refInfo[1])
|
||||||
for cType in contentTypes:
|
for cType in contentTypes:
|
||||||
if refField:
|
if refField:
|
||||||
fieldNames = refField.shownInfo
|
fieldNames = refField.shownInfo
|
||||||
|
@ -432,7 +438,7 @@ class ToolMixin(BaseMixin):
|
||||||
def isSortable(self, name, className, usage):
|
def isSortable(self, name, className, usage):
|
||||||
'''Is field p_name defined on p_className 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
|
if (',' in className) or (name == 'state'): return False
|
||||||
appyType = self.getAppyType(name, className=className)
|
appyType = self.getAppyType(name, className=className)
|
||||||
if appyType: return appyType.isSortable(usage=usage)
|
if appyType: return appyType.isSortable(usage=usage)
|
||||||
|
|
||||||
|
@ -567,9 +573,10 @@ class ToolMixin(BaseMixin):
|
||||||
if not refInfo and (self.REQUEST.get('search', None) == '_advanced'):
|
if not refInfo and (self.REQUEST.get('search', None) == '_advanced'):
|
||||||
criteria = self.REQUEST.SESSION.get('searchCriteria', None)
|
criteria = self.REQUEST.SESSION.get('searchCriteria', None)
|
||||||
if criteria and criteria.has_key('_ref'): refInfo = criteria['_ref']
|
if criteria and criteria.has_key('_ref'): refInfo = criteria['_ref']
|
||||||
if not refInfo: return ('', None)
|
if not refInfo: return (None, None)
|
||||||
sourceContentType, refField = refInfo.split(':')
|
objectUid, fieldName = refInfo.split(':')
|
||||||
return refInfo, self.getAppyType(refField, className=sourceContentType)
|
obj = self.getObject(objectUid)
|
||||||
|
return obj, fieldName
|
||||||
|
|
||||||
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.
|
||||||
|
@ -663,7 +670,7 @@ class ToolMixin(BaseMixin):
|
||||||
res['backText'] = self.translate(label)
|
res['backText'] = self.translate(label)
|
||||||
else:
|
else:
|
||||||
fieldName, pageName = d2.split(':')
|
fieldName, pageName = d2.split(':')
|
||||||
sourceObj = self.uid_catalog(UID=d1)[0].getObject()
|
sourceObj = self.portal_catalog(UID=d1)[0].getObject()
|
||||||
label = '%s_%s' % (sourceObj.meta_type, fieldName)
|
label = '%s_%s' % (sourceObj.meta_type, fieldName)
|
||||||
res['backText'] = '%s : %s' % (sourceObj.Title(),
|
res['backText'] = '%s : %s' % (sourceObj.Title(),
|
||||||
self.translate(label))
|
self.translate(label))
|
||||||
|
@ -739,7 +746,7 @@ class ToolMixin(BaseMixin):
|
||||||
except KeyError: pass
|
except KeyError: pass
|
||||||
except IndexError: pass
|
except IndexError: pass
|
||||||
if uid:
|
if uid:
|
||||||
brain = self.uid_catalog(UID=uid)
|
brain = self.portal_catalog(UID=uid)
|
||||||
if brain:
|
if brain:
|
||||||
sibling = brain[0].getObject()
|
sibling = brain[0].getObject()
|
||||||
res[urlKey] = sibling.getUrl(nav=newNav % (index + 1),
|
res[urlKey] = sibling.getUrl(nav=newNav % (index + 1),
|
||||||
|
@ -860,4 +867,15 @@ class ToolMixin(BaseMixin):
|
||||||
if ',' in contentType: return ()
|
if ',' in contentType: return ()
|
||||||
return [f.__dict__ for f in self.getAllAppyTypes(contentType) \
|
return [f.__dict__ for f in self.getAllAppyTypes(contentType) \
|
||||||
if (f.type == 'Pod') and (f.show == 'result')]
|
if (f.type == 'Pod') and (f.show == 'result')]
|
||||||
|
|
||||||
|
def getUserLine(self, user):
|
||||||
|
'''Returns a one-line user info as shown on every page.'''
|
||||||
|
res = [user.getId()]
|
||||||
|
name = user.getProperty('fullname')
|
||||||
|
if name: res.insert(0, name)
|
||||||
|
rolesToShow = [r for r in user.getRoles() \
|
||||||
|
if r not in ('Authenticated', 'Member')]
|
||||||
|
if rolesToShow:
|
||||||
|
res.append(', '.join([self.translate(r) for r in rolesToShow]))
|
||||||
|
return ' | '.join(res)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -37,8 +37,8 @@ class BaseMixin:
|
||||||
rq = self.REQUEST
|
rq = self.REQUEST
|
||||||
obj = self
|
obj = self
|
||||||
if created:
|
if created:
|
||||||
obj = self.portal_factory.doCreate(self, self.id) # portal_factory
|
# portal_factory creates the final object from the temp object.
|
||||||
# creates the final object from the temp object.
|
obj = self.portal_factory.doCreate(self, self.id)
|
||||||
previousData = None
|
previousData = None
|
||||||
if not created: previousData = self.rememberPreviousData()
|
if not created: previousData = self.rememberPreviousData()
|
||||||
# Perform the change on the object, unless self is a tool being created.
|
# Perform the change on the object, unless self is a tool being created.
|
||||||
|
@ -61,7 +61,7 @@ class BaseMixin:
|
||||||
# Get the initiator
|
# Get the initiator
|
||||||
splitted = rq['nav'].split('.')
|
splitted = rq['nav'].split('.')
|
||||||
if splitted[0] == 'search': return # Not an initiator but a search.
|
if splitted[0] == 'search': return # Not an initiator but a search.
|
||||||
initiator = self.uid_catalog(UID=splitted[1])[0].getObject()
|
initiator = self.getTool().getObject(splitted[1])
|
||||||
fieldName = splitted[2].split(':')[0]
|
fieldName = splitted[2].split(':')[0]
|
||||||
initiator.appy().link(fieldName, obj)
|
initiator.appy().link(fieldName, obj)
|
||||||
|
|
||||||
|
@ -174,20 +174,24 @@ class BaseMixin:
|
||||||
errorMessage = self.translate(
|
errorMessage = self.translate(
|
||||||
'Please correct the indicated errors.', domain='plone')
|
'Please correct the indicated errors.', domain='plone')
|
||||||
isNew = rq.get('is_new') == 'True'
|
isNew = rq.get('is_new') == 'True'
|
||||||
# Go back to the consult view if the user clicked on 'Cancel'
|
# If this object is created from an initiator, get info about him.
|
||||||
|
initiator = None
|
||||||
|
initiatorPage = None
|
||||||
|
if rq.get('nav', '').startswith('ref.'):
|
||||||
|
splitted = rq['nav'].split('.')
|
||||||
|
initiator = tool.getObject(splitted[1])
|
||||||
|
initiatorPage = splitted[2].split(':')[1]
|
||||||
|
# If the user clicked on 'Cancel', go back to the previous page.
|
||||||
if rq.get('buttonCancel.x', None):
|
if rq.get('buttonCancel.x', None):
|
||||||
if isNew:
|
if initiator:
|
||||||
if rq.get('nav', ''):
|
# Go back to the initiator page.
|
||||||
# We can go back to the initiator page.
|
urlBack = initiator.getUrl(page=initiatorPage, nav='')
|
||||||
splitted = rq['nav'].split('.')
|
|
||||||
initiator = tool.getObject(splitted[1])
|
|
||||||
initiatorPage = splitted[2].split(':')[1]
|
|
||||||
urlBack = initiator.getUrl(page=initiatorPage, nav='')
|
|
||||||
else:
|
|
||||||
# Go back to the root of the site.
|
|
||||||
urlBack = tool.getSiteUrl()
|
|
||||||
else:
|
else:
|
||||||
urlBack = self.getUrl()
|
if isNew:
|
||||||
|
# Go back to the root of the site.
|
||||||
|
urlBack = tool.getSiteUrl()
|
||||||
|
else:
|
||||||
|
urlBack = self.getUrl()
|
||||||
self.say(self.translate('Changes canceled.', domain='plone'))
|
self.say(self.translate('Changes canceled.', domain='plone'))
|
||||||
return self.goto(urlBack)
|
return self.goto(urlBack)
|
||||||
|
|
||||||
|
@ -236,9 +240,11 @@ class BaseMixin:
|
||||||
if not obj.allows('View'):
|
if not obj.allows('View'):
|
||||||
return self.goto(tool.getSiteUrl(), msg)
|
return self.goto(tool.getSiteUrl(), msg)
|
||||||
if rq.get('buttonOk.x', None) or saveConfirmed:
|
if rq.get('buttonOk.x', None) or saveConfirmed:
|
||||||
# Go to the consult view for this object
|
|
||||||
obj.say(msg)
|
obj.say(msg)
|
||||||
return self.goto(obj.getUrl())
|
if isNew and initiator:
|
||||||
|
return self.goto(initiator.getUrl(page=initiatorPage, nav=''))
|
||||||
|
else:
|
||||||
|
return self.goto(obj.getUrl())
|
||||||
if rq.get('buttonPrevious.x', None):
|
if rq.get('buttonPrevious.x', None):
|
||||||
# Go to the previous page for this object.
|
# Go to the previous page for this object.
|
||||||
# We recompute the list of phases and pages because things
|
# We recompute the list of phases and pages because things
|
||||||
|
|
|
@ -8,12 +8,17 @@ table { font-size: 100%; border-spacing: 0px; border-collapse:collapse;}
|
||||||
form { margin: 0; padding: 0;}
|
form { margin: 0; padding: 0;}
|
||||||
p { margin: 0;}
|
p { margin: 0;}
|
||||||
acronym {cursor: help;}
|
acronym {cursor: help;}
|
||||||
input { border: 1px solid #a79e9e;
|
input { border: 1px solid #a79e9e; background-color: #f8f8f8;
|
||||||
font-family: Lucida,Helvetica,Arial,sans-serif; }
|
font-family: Lucida,Helvetica,Arial,sans-serif; margin-bottom: 1px}
|
||||||
input[type=image] { border-width: 0px; background: none; }
|
input[type=image] { border-width: 0px; background: none; }
|
||||||
textarea { width: 99%; font: 100% Lucida,Helvetica,Arial,sans-serif;
|
textarea { width: 99%; font: 100% Lucida,Helvetica,Arial,sans-serif;
|
||||||
border: 1px solid #a79e9e;}
|
border: 1px solid #a79e9e; background-color: #f8f8f8;}
|
||||||
label { font-weight: 600; font-style: italic; line-height: 1.4em;}
|
label { font-weight: 600; font-style: italic; line-height: 1.4em;}
|
||||||
|
legend { padding-bottom: 2px; padding-right: 3px;}
|
||||||
|
ul { line-height: 1.2em; margin: 0 0 0.2em 0.6em; padding: 0;
|
||||||
|
list-style: none outside none;}
|
||||||
|
li { margin: 0; background-image: url("skyn/li.gif"); padding-left: 10px;
|
||||||
|
background-repeat: no-repeat; background-position: 0 0.5em;}
|
||||||
|
|
||||||
.main { width: 900px; background-color: white; box-shadow: 3px 3px 3px #A9A9A9;
|
.main { width: 900px; background-color: white; box-shadow: 3px 3px 3px #A9A9A9;
|
||||||
border-style: solid; border-width: 1px; border-color: grey; }
|
border-style: solid; border-width: 1px; border-color: grey; }
|
||||||
|
@ -22,7 +27,7 @@ label { font-weight: 600; font-style: italic; line-height: 1.4em;}
|
||||||
.userStrip { background-color: #a2a2a2; height: 30px;
|
.userStrip { background-color: #a2a2a2; height: 30px;
|
||||||
border-top: 3px solid #525252; border-bottom: 2px solid #9b0000; }
|
border-top: 3px solid #525252; border-bottom: 2px solid #9b0000; }
|
||||||
.login { margin-top: 2px; margin-bottom: 2px; color: white;}
|
.login { margin-top: 2px; margin-bottom: 2px; color: white;}
|
||||||
.buttons { margin-left: 4px; }
|
.buttons { margin-left: 4px;}
|
||||||
.message { color: #9b0000; font-style: italic;
|
.message { color: #9b0000; font-style: italic;
|
||||||
position: absolute; top: -15px; right: 5px}
|
position: absolute; top: -15px; right: 5px}
|
||||||
.discreet { font-size: 90%; }
|
.discreet { font-size: 90%; }
|
||||||
|
@ -41,7 +46,7 @@ label { font-weight: 600; font-style: italic; line-height: 1.4em;}
|
||||||
border: 1px solid grey; }
|
border: 1px solid grey; }
|
||||||
.list { border: 1px solid grey; margin-bottom: 3px;}
|
.list { border: 1px solid grey; margin-bottom: 3px;}
|
||||||
.list td, .list th { border: 1px solid grey;
|
.list td, .list th { border: 1px solid grey;
|
||||||
padding-left: 3px; padding-right: 3px;}
|
padding-left: 5px; padding-right: 5px; padding-top: 3px;}
|
||||||
.list th { background-color: #cbcbcb; font-style: italic; font-weight: normal;}
|
.list th { background-color: #cbcbcb; font-style: italic; font-weight: normal;}
|
||||||
.noStyle { border: 0 !important; padding: 0 !important; margin: 0 !important; }
|
.noStyle { border: 0 !important; padding: 0 !important; margin: 0 !important; }
|
||||||
.noStyle td { border:0 !important; padding:0 !important; margin:0 !important; }
|
.noStyle td { border:0 !important; padding:0 !important; margin:0 !important; }
|
||||||
|
@ -62,3 +67,4 @@ label { font-weight: 600; font-style: italic; line-height: 1.4em;}
|
||||||
.by { background-color: #ededed; font-style: italic; padding-top: 3px;}
|
.by { background-color: #ededed; font-style: italic; padding-top: 3px;}
|
||||||
.workflow { background-color: #ededed; text-align: center;}
|
.workflow { background-color: #ededed; text-align: center;}
|
||||||
.objectNavigate { margin-top: 3px;}
|
.objectNavigate { margin-top: 3px;}
|
||||||
|
.underline {border-bottom: 1px dotted grey;}
|
||||||
|
|
|
@ -232,6 +232,42 @@ function updateSlaves(masterValues, appyTypeId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initSlaves() {
|
||||||
|
// When the current page is loaded, we must set the correct state for all
|
||||||
|
// slave fields.
|
||||||
|
var masters = cssQuery('.appyMaster');
|
||||||
|
for (var i=0; i < masters.length; i++) {
|
||||||
|
var cssClasses = masters[i].className.split(' ');
|
||||||
|
for (var j=0; j < cssClasses.length; j++) {
|
||||||
|
if (cssClasses[j].indexOf('master_') == 0) {
|
||||||
|
var appyId = cssClasses[j].split('_')[1];
|
||||||
|
var masterValue = [];
|
||||||
|
if (masters[i].nodeName == 'SPAN'){
|
||||||
|
var idField = masters[i].id;
|
||||||
|
if (idField == '') {
|
||||||
|
masterValue.push(idField);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ((idField[0] == '(') || (idField[0] == '[')) {
|
||||||
|
// There are multiple values, split it
|
||||||
|
var subValues = idField.substring(1, idField.length-1).split(',');
|
||||||
|
for (var k=0; k < subValues.length; k++){
|
||||||
|
var subValue = subValues[k].replace(' ','');
|
||||||
|
masterValue.push(subValue.substring(1, subValue.length-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { masterValue.push(masters[i].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { masterValue = getMasterValue(masters[i]);
|
||||||
|
}
|
||||||
|
updateSlaves(masterValue, appyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function used for triggering a workflow transition
|
// Function used for triggering a workflow transition
|
||||||
function triggerTransition(transitionId, msg) {
|
function triggerTransition(transitionId, msg) {
|
||||||
var theForm = document.getElementById('triggerTransitionForm');
|
var theForm = document.getElementById('triggerTransitionForm');
|
||||||
|
|
|
@ -5,7 +5,7 @@ rq = context.REQUEST
|
||||||
|
|
||||||
# Get the object impacted by the action.
|
# Get the object impacted by the action.
|
||||||
if rq.get('objectUid', None):
|
if rq.get('objectUid', None):
|
||||||
obj = context.uid_catalog(UID=rq['objectUid'])[0].getObject()
|
obj = context.portal_catalog(UID=rq['objectUid'])[0].getObject()
|
||||||
else:
|
else:
|
||||||
obj = context.getParentNode() # An appy obj or in some cases the app folder.
|
obj = context.getParentNode() # An appy obj or in some cases the app folder.
|
||||||
if obj.portal_type == 'AppyFolder':
|
if obj.portal_type == 'AppyFolder':
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<tal:main define="tool context/getTool">
|
<tal:main define="tool context/getTool">
|
||||||
<html metal:use-macro="context/skyn/template/macros/main">
|
<html metal:use-macro="context/skyn/template/macros/main">
|
||||||
<metal:fill fill-slot="content"
|
<metal:fill fill-slot="content"
|
||||||
tal:define="contextObj python:context.getParentNode();
|
tal:define="contextObj context/getParentNode;
|
||||||
errors request/errors | python:{};
|
errors request/errors | python:{};
|
||||||
layoutType python:'edit';
|
layoutType python:'edit';
|
||||||
layout python: contextObj.getPageLayout(layoutType);
|
layout python: contextObj.getPageLayout(layoutType);
|
||||||
|
|
|
@ -249,45 +249,12 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<tal:comment replace="nothing">
|
<tal:comment replace="nothing">The page footer.</tal:comment>
|
||||||
The page footer.
|
|
||||||
</tal:comment>
|
|
||||||
<metal:footer define-macro="footer">
|
<metal:footer define-macro="footer">
|
||||||
<tal:dummy define="messages app/plone_utils/showPortalMessages"/>
|
<tal:dummy define="messages app/plone_utils/showPortalMessages"/>
|
||||||
<script language="javascript">
|
<script language="javascript">
|
||||||
<!--
|
<!--
|
||||||
// When the current page is loaded, we must set the correct state for all slave fields.
|
initSlaves();
|
||||||
var masters = cssQuery('.appyMaster');
|
|
||||||
for (var i=0; i < masters.length; i++) {
|
|
||||||
var cssClasses = masters[i].className.split(' ');
|
|
||||||
for (var j=0; j < cssClasses.length; j++) {
|
|
||||||
if (cssClasses[j].indexOf('master_') == 0) {
|
|
||||||
var appyId = cssClasses[j].split('_')[1];
|
|
||||||
var masterValue = [];
|
|
||||||
if (masters[i].nodeName == 'SPAN'){
|
|
||||||
var idField = masters[i].id;
|
|
||||||
if (idField == '') {
|
|
||||||
masterValue.push(idField);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ((idField[0] == '(') || (idField[0] == '[')) {
|
|
||||||
// There are multiple values, split it
|
|
||||||
var subValues = idField.substring(1, idField.length-1).split(',');
|
|
||||||
for (var k=0; k < subValues.length; k++){
|
|
||||||
var subValue = subValues[k].replace(' ','');
|
|
||||||
masterValue.push(subValue.substring(1, subValue.length-1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { masterValue.push(masters[i].id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { masterValue = getMasterValue(masters[i]);
|
|
||||||
}
|
|
||||||
updateSlaves(masterValue, appyId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-->
|
-->
|
||||||
</script>
|
</script>
|
||||||
</metal:footer>
|
</metal:footer>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<metal:queryResults define-macro="queryResult"
|
<metal:queryResults define-macro="queryResult"
|
||||||
tal:define="contentType request/type_name;
|
tal:define="contentType request/type_name;
|
||||||
refInfo tool/getRefInfo;
|
refInfo tool/getRefInfo;
|
||||||
|
refObject python: refInfo[0];
|
||||||
refField python: refInfo[1];
|
refField python: refInfo[1];
|
||||||
refInfo python: refInfo[0];
|
refUrlPart python: refObject and ('&ref=%s:%s' % (refObject.UID(), refField)) or '';
|
||||||
startNumber request/startNumber|python:'0';
|
startNumber request/startNumber|python:'0';
|
||||||
startNumber python: int(startNumber);
|
startNumber python: int(startNumber);
|
||||||
searchName request/search;
|
searchName request/search;
|
||||||
|
@ -14,13 +15,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, refField=refField);
|
queryResult python: tool.executeQuery(contentType, searchName, startNumber, remember=True, sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey, filterValue=filterValue, refObject=refObject, 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&ref=%s' % (tool.absolute_url(), contentType, refInfo);">
|
newSearchUrl python: '%s/skyn/search?type_name=%s%s' % (tool.absolute_url(), contentType, refUrlPart)">
|
||||||
|
|
||||||
<tal:result condition="objs">
|
<tal:result condition="objs">
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@
|
||||||
<span tal:replace="structure python: test(searchName, searchLabel, test(severalTypes, tool.translate(tool.getAppName()), tool.translate('%s_plural' % contentType)))"/>
|
<span tal:replace="structure python: test(searchName, searchLabel, test(severalTypes, tool.translate(tool.getAppName()), tool.translate('%s_plural' % contentType)))"/>
|
||||||
(<span tal:replace="totalNumber"/>)
|
(<span tal:replace="totalNumber"/>)
|
||||||
<tal:newSearch condition="python: searchName == '_advanced'">
|
<tal:newSearch condition="python: searchName == '_advanced'">
|
||||||
— <i><a tal:attributes="href newSearchUrl"
|
— <i><a tal:attributes="href newSearchUrl"
|
||||||
tal:content="python: tool.translate('search_new')"></a></i>
|
tal:content="python: tool.translate('search_new')"></a></i>
|
||||||
</tal:newSearch>
|
</tal:newSearch>
|
||||||
</legend>
|
</legend>
|
||||||
|
@ -60,7 +61,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<table tal:define="fieldNames python: tool.getResultColumnsNames(contentType, refField);
|
<table tal:define="fieldNames python: tool.getResultColumnsNames(contentType, refInfo);
|
||||||
widgets python: objs[0].getAppyTypesFromNames(fieldNames);"
|
widgets python: objs[0].getAppyTypesFromNames(fieldNames);"
|
||||||
class="list" width="100%">
|
class="list" width="100%">
|
||||||
<tal:comment replace="nothing">Headers, with filters and sort arrows</tal:comment>
|
<tal:comment replace="nothing">Headers, with filters and sort arrows</tal:comment>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 367 B |
|
@ -110,7 +110,7 @@
|
||||||
</td></tr>
|
</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<tal:comment replace="nothing">User info and controls for authenticated users</tal:comment>
|
<tal:comment replace="nothing">User info and controls for authenticated users</tal:comment>
|
||||||
<table tal:condition="not: isAnon" class="buttons">
|
<table tal:condition="not: isAnon" class="buttons" width="99%">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<!-- Go home -->
|
<!-- Go home -->
|
||||||
|
@ -128,6 +128,7 @@
|
||||||
<img tal:attributes="src string: $appUrl/skyn/logout.gif"/>
|
<img tal:attributes="src string: $appUrl/skyn/logout.gif"/>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td align="right" tal:content="python: tool.getUserLine(user)"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<tal:comment replace="nothing">Edit macro for an File.</tal:comment>
|
<tal:comment replace="nothing">Edit macro for an File.</tal:comment>
|
||||||
<metal:edit define-macro="edit">
|
<metal:edit define-macro="edit">
|
||||||
<tal:showFile condition="python: value and value.size">
|
<tal:showFile condition="python: value and value.size">
|
||||||
<metal:call use-macro="portal/skyn/widgets/file/macros/view"/><br/>
|
<metal:call use-macro="app/skyn/widgets/file/macros/view"/><br/>
|
||||||
</tal:showFile>
|
</tal:showFile>
|
||||||
<tal:editButtons condition="python: value and value.size">
|
<tal:editButtons condition="python: value and value.size">
|
||||||
<tal:comment replace="nothing">Keep the file untouched.</tal:comment>
|
<tal:comment replace="nothing">Keep the file untouched.</tal:comment>
|
||||||
|
@ -29,8 +29,7 @@
|
||||||
id string:${name}_nochange;
|
id string:${name}_nochange;
|
||||||
onclick string:document.getElementById('${name}_file').disabled=true;"/>
|
onclick string:document.getElementById('${name}_file').disabled=true;"/>
|
||||||
<label tal:attributes="for string:${name}_nochange"
|
<label tal:attributes="for string:${name}_nochange"
|
||||||
i18n:translate="nochange_file" i18n:domain="plone">
|
i18n:translate="nochange_file" i18n:domain="plone">Keep the file unchanged</label>
|
||||||
</label>
|
|
||||||
<br/>
|
<br/>
|
||||||
<tal:comment replace="nothing">Delete the file.</tal:comment>
|
<tal:comment replace="nothing">Delete the file.</tal:comment>
|
||||||
<tal:delete condition="not: widget/required">
|
<tal:delete condition="not: widget/required">
|
||||||
|
@ -39,8 +38,7 @@
|
||||||
id string:${name}_delete;
|
id string:${name}_delete;
|
||||||
onclick string:document.getElementById('${name}_file').disabled=true;"/>
|
onclick string:document.getElementById('${name}_file').disabled=true;"/>
|
||||||
<label tal:attributes="for string:${name}_delete"
|
<label tal:attributes="for string:${name}_delete"
|
||||||
i18n:translate="delete_file" i18n:domain="plone">
|
i18n:translate="delete_file" i18n:domain="plone">Delete the file</label>
|
||||||
</label>
|
|
||||||
<br/>
|
<br/>
|
||||||
</tal:delete>
|
</tal:delete>
|
||||||
<tal:comment replace="nothing">Replace with a new file.</tal:comment>
|
<tal:comment replace="nothing">Replace with a new file.</tal:comment>
|
||||||
|
@ -50,8 +48,7 @@
|
||||||
id string:${name}_upload;
|
id string:${name}_upload;
|
||||||
onclick string:document.getElementById('${name}_file').disabled=false"/>
|
onclick string:document.getElementById('${name}_file').disabled=false"/>
|
||||||
<label tal:attributes="for string:${name}_upload;"
|
<label tal:attributes="for string:${name}_upload;"
|
||||||
i18n:translate="upload_file" i18n:domain="plone">
|
i18n:translate="upload_file" i18n:domain="plone">Replace it with a new file</label>
|
||||||
</label>
|
|
||||||
<br/>
|
<br/>
|
||||||
</tal:editButtons>
|
</tal:editButtons>
|
||||||
<tal:comment replace="nothing">The upload field.</tal:comment>
|
<tal:comment replace="nothing">The upload field.</tal:comment>
|
||||||
|
@ -66,7 +63,7 @@
|
||||||
|
|
||||||
<tal:comment replace="nothing">Cell macro for an File.</tal:comment>
|
<tal:comment replace="nothing">Cell macro for an File.</tal:comment>
|
||||||
<metal:cell define-macro="cell">
|
<metal:cell define-macro="cell">
|
||||||
<metal:call use-macro="portal/skyn/widgets/file/macros/view"/>
|
<metal:call use-macro="app/skyn/widgets/file/macros/view"/>
|
||||||
</metal:cell>
|
</metal:cell>
|
||||||
|
|
||||||
<tal:comment replace="nothing">Search macro for an File.</tal:comment>
|
<tal:comment replace="nothing">Search macro for an File.</tal:comment>
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
<metal:plusIcon use-macro="app/skyn/widgets/ref/macros/plusIcon"/>
|
<metal:plusIcon use-macro="app/skyn/widgets/ref/macros/plusIcon"/>
|
||||||
<tal:comment replace="nothing">The search icon if field is queryable</tal:comment>
|
<tal:comment replace="nothing">The search icon if field is queryable</tal:comment>
|
||||||
<a tal:condition="appyType/queryable"
|
<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'])">
|
tal:attributes="href python: '%s/skyn/search?type_name=%s&ref=%s:%s' % (tool.absolute_url(), linkedPortalType, contextObj.UID(), appyType['name'])">
|
||||||
<img src="search.gif" tal:attributes="title python: tool.translate('search_objects')"/></a>
|
<img src="search.gif" tal:attributes="title python: tool.translate('search_objects')"/></a>
|
||||||
</legend>
|
</legend>
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
tal:define="fmt widget/format">
|
tal:define="fmt widget/format">
|
||||||
<span tal:condition="python: fmt in (0, 3)"
|
<span tal:condition="python: fmt in (0, 3)"
|
||||||
tal:attributes="class widget/master_css; id rawValue">
|
tal:attributes="class widget/master_css; id rawValue">
|
||||||
<ul class="appyList" tal:condition="python: value and isMultiple">
|
<ul tal:condition="python: value and isMultiple">
|
||||||
<li class="appyBullet" tal:repeat="sv value"><i tal:content="structure sv"></i></li>
|
<li tal:repeat="sv value"><i tal:content="structure sv"></i></li>
|
||||||
</ul>
|
</ul>
|
||||||
<tal:singleValue condition="python: value and not isMultiple">
|
<tal:singleValue condition="python: value and not isMultiple">
|
||||||
<span tal:condition="python: fmt != 3" tal:replace="structure value"/>
|
<span tal:condition="python: fmt != 3" tal:replace="structure value"/>
|
||||||
|
|
|
@ -1,19 +1,7 @@
|
||||||
textarea { width: 99%; }
|
|
||||||
|
|
||||||
#importedElem { color: grey; font-style: italic; }
|
#importedElem { color: grey; font-style: italic; }
|
||||||
label { font-weight: bold; font-style: italic; line-height: 1.4em; font-size: 92%;}
|
|
||||||
.appyList { line-height: 1.1em; margin: 0 0 0.5em 1.2em; padding: 0; }
|
|
||||||
.appyBullet { margin: 0; }
|
|
||||||
.appyPod { float:right; }
|
.appyPod { float:right; }
|
||||||
.appyFocus { color: #900101; }
|
.appyFocus { color: #900101; }
|
||||||
|
|
||||||
.appyPlusImg {
|
|
||||||
vertical-align: top;
|
|
||||||
position: relative;
|
|
||||||
left: -1.4em;
|
|
||||||
top: -0.55em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.appyState {
|
.appyState {
|
||||||
font-size: 85%;
|
font-size: 85%;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
@ -91,38 +79,6 @@ fieldset {
|
||||||
padding: 3px 4px 3px 12px;
|
padding: 3px 4px 3px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listing { margin: 0em 0em; }
|
|
||||||
.listing td, .stx table td {
|
|
||||||
padding : 0.1em 0.3em 0.1em 0.3em;
|
|
||||||
border-top : 1px solid #8CACBB;
|
|
||||||
}
|
|
||||||
.listing th, .stx table th { padding: 0.25em 0.3em; }
|
|
||||||
.vertical td { padding-left: 0.3em; }
|
|
||||||
|
|
||||||
.innerAppyTable {
|
|
||||||
border-width: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.innerAppyTable td {
|
|
||||||
border-top: 0px;
|
|
||||||
border-bottom: 1px solid #8CACBB;
|
|
||||||
border-right: 0px;
|
|
||||||
padding: 0.4em 0em 0em 0em;
|
|
||||||
border-collapse: separate;
|
|
||||||
}
|
|
||||||
|
|
||||||
.innerAppyTable th {
|
|
||||||
border-right: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.innerAppyFieldset {
|
|
||||||
margin: 0em 1em;
|
|
||||||
line-height: 1.0em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field {
|
|
||||||
margin: 0 0.2em 0.2em 0;
|
|
||||||
}
|
|
||||||
/* Portlet elements */
|
/* Portlet elements */
|
||||||
.portletHeader {
|
.portletHeader {
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
|
@ -149,5 +105,3 @@ fieldset {
|
||||||
float:right;
|
float:right;
|
||||||
margin:0.5em;
|
margin:0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,9 +52,6 @@ rootClasses = [<!rootClasses!>]
|
||||||
appClasses = [<!appClasses!>]
|
appClasses = [<!appClasses!>]
|
||||||
appClassNames = [<!appClassNames!>]
|
appClassNames = [<!appClassNames!>]
|
||||||
allClassNames = [<!allClassNames!>]
|
allClassNames = [<!allClassNames!>]
|
||||||
# List of classes that must be hidden from the catalog
|
|
||||||
catalogMap = {}
|
|
||||||
<!catalogMap!>
|
|
||||||
|
|
||||||
# In the following dict, we store, for every Appy class, the ordered list of
|
# In the following dict, we store, for every Appy class, the ordered list of
|
||||||
# appy types (included inherited ones).
|
# appy types (included inherited ones).
|
||||||
|
|
|
@ -42,7 +42,7 @@ class ToolWrapper(AbstractWrapper):
|
||||||
rq = self.o.REQUEST
|
rq = self.o.REQUEST
|
||||||
if rq.get('nav', ''):
|
if rq.get('nav', ''):
|
||||||
initiatorUid = rq['nav'].split('.')[1]
|
initiatorUid = rq['nav'].split('.')[1]
|
||||||
res = self.o.uid_catalog(UID=initiatorUid)[0].getObject().appy()
|
res = self.o.portal_catalog(UID=initiatorUid)[0].getObject().appy()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getObject(self, uid):
|
def getObject(self, uid):
|
||||||
|
|
|
@ -139,7 +139,7 @@ class AbstractWrapper(object):
|
||||||
to a given p_sortKey which must be an attribute set on referred
|
to a given p_sortKey which must be an attribute set on referred
|
||||||
objects ("title", by default).'''
|
objects ("title", by default).'''
|
||||||
sortedUids = getattr(self.o, '_appy_%s' % fieldName)
|
sortedUids = getattr(self.o, '_appy_%s' % fieldName)
|
||||||
c = self.o.uid_catalog
|
c = self.o.portal_catalog
|
||||||
sortedUids.sort(lambda x,y: \
|
sortedUids.sort(lambda x,y: \
|
||||||
cmp(getattr(c(UID=x)[0].getObject().appy(), sortKey),
|
cmp(getattr(c(UID=x)[0].getObject().appy(), sortKey),
|
||||||
getattr(c(UID=y)[0].getObject().appy(), sortKey)))
|
getattr(c(UID=y)[0].getObject().appy(), sortKey)))
|
||||||
|
|
|
@ -64,7 +64,7 @@ class DocImporter:
|
||||||
fileContent = self.content.read()
|
fileContent = self.content.read()
|
||||||
else:
|
else:
|
||||||
fileContent = self.content
|
fileContent = self.content
|
||||||
f = file(self.importPath, 'w')
|
f = file(self.importPath, 'wb')
|
||||||
f.write(fileContent)
|
f.write(fileContent)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
@ -181,7 +181,9 @@ class ImageImporter(DocImporter):
|
||||||
externally.'''
|
externally.'''
|
||||||
anchorTypes = ('page', 'paragraph', 'char', 'as-char')
|
anchorTypes = ('page', 'paragraph', 'char', 'as-char')
|
||||||
WRONG_ANCHOR = 'Wrong anchor. Valid values for anchors are: %s.'
|
WRONG_ANCHOR = 'Wrong anchor. Valid values for anchors are: %s.'
|
||||||
def getImportFolder(self): return '%s/unzip/Pictures' % self.tempFolder
|
pictFolder = '%sPictures%s' % (os.sep, os.sep)
|
||||||
|
def getImportFolder(self):
|
||||||
|
return os.path.join(self.tempFolder, 'unzip', 'Pictures')
|
||||||
|
|
||||||
def moveFile(self, at, importPath):
|
def moveFile(self, at, importPath):
|
||||||
'''Copies file at p_at into the ODT file at p_importPath.'''
|
'''Copies file at p_at into the ODT file at p_importPath.'''
|
||||||
|
@ -189,7 +191,7 @@ class ImageImporter(DocImporter):
|
||||||
for imagePath, imageAt in self.fileNames.iteritems():
|
for imagePath, imageAt in self.fileNames.iteritems():
|
||||||
if imageAt == at:
|
if imageAt == at:
|
||||||
# Yes!
|
# Yes!
|
||||||
i = importPath.rfind('/Pictures/') + 1
|
i = importPath.rfind(self.pictFolder) + 1
|
||||||
return importPath[:i] + imagePath
|
return importPath[:i] + imagePath
|
||||||
# If I am here, the image has not already been imported: copy it.
|
# If I am here, the image has not already been imported: copy it.
|
||||||
shutil.copy(at, importPath)
|
shutil.copy(at, importPath)
|
||||||
|
@ -208,8 +210,8 @@ class ImageImporter(DocImporter):
|
||||||
s = self.svgNs
|
s = self.svgNs
|
||||||
imageName = 'Image%f' % time.time()
|
imageName = 'Image%f' % time.time()
|
||||||
# Compute path to image
|
# Compute path to image
|
||||||
i = self.importPath.rfind('/Pictures/')
|
i = self.importPath.rfind(self.pictFolder)
|
||||||
imagePath = self.importPath[i+1:]
|
imagePath = self.importPath[i+1:].replace('\\', '/')
|
||||||
self.fileNames[imagePath] = self.at
|
self.fileNames[imagePath] = self.at
|
||||||
# Compute image size
|
# Compute image size
|
||||||
width, height = getSize(self.importPath, self.format)
|
width, height = getSize(self.importPath, self.format)
|
||||||
|
|
Loading…
Reference in a new issue