Added a new feature allowing to create objects by importing them from external sources instead of from filling a web form.
This commit is contained in:
parent
cbc7d257d4
commit
4c4b2d0f87
|
@ -8,11 +8,25 @@ r, w, d = ('read', 'write', 'delete')
|
||||||
# Descriptor classes used for refining descriptions of elements in types
|
# Descriptor classes used for refining descriptions of elements in types
|
||||||
# (pages, groups,...) ----------------------------------------------------------
|
# (pages, groups,...) ----------------------------------------------------------
|
||||||
class Page:
|
class Page:
|
||||||
|
'''Used for describing a page, its related phase, show condition, etc.'''
|
||||||
def __init__(self, name, phase='main', show=True):
|
def __init__(self, name, phase='main', show=True):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.phase = phase
|
self.phase = phase
|
||||||
self.show = show
|
self.show = show
|
||||||
|
|
||||||
|
class Import:
|
||||||
|
'''Used for describing the place where to find the data to use for creating
|
||||||
|
an object.'''
|
||||||
|
def __init__(self, path, columnMethod=None, columnHeaders=(),
|
||||||
|
sortMethod=None):
|
||||||
|
self.id = 'import'
|
||||||
|
self.path = path
|
||||||
|
self.columnMethod = columnMethod
|
||||||
|
# This method allows to split every element into subElements that can
|
||||||
|
# be shown as column values in a table.
|
||||||
|
self.columnHeaders = columnHeaders
|
||||||
|
self.sortMethod = sortMethod
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
class Type:
|
class Type:
|
||||||
'''Basic abstract class for defining any appy type.'''
|
'''Basic abstract class for defining any appy type.'''
|
||||||
|
|
|
@ -102,14 +102,24 @@ class Generator(AbstractGenerator):
|
||||||
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),
|
||||||
msg('query_create', '', msg.QUERY_CREATE),
|
msg('query_create', '', msg.QUERY_CREATE),
|
||||||
|
msg('query_import', '', msg.QUERY_IMPORT),
|
||||||
msg('query_no_result', '', msg.QUERY_NO_RESULT),
|
msg('query_no_result', '', msg.QUERY_NO_RESULT),
|
||||||
msg('query_consult_all', '', msg.QUERY_CONSULT_ALL),
|
msg('query_consult_all', '', msg.QUERY_CONSULT_ALL),
|
||||||
|
msg('import_title', '', msg.IMPORT_TITLE),
|
||||||
|
msg('import_show_hide', '', msg.IMPORT_SHOW_HIDE),
|
||||||
|
msg('import_already', '', msg.IMPORT_ALREADY),
|
||||||
|
msg('import_many', '', msg.IMPORT_MANY),
|
||||||
|
msg('import_done', '', msg.IMPORT_DONE),
|
||||||
msg('ref_invalid_index', '', msg.REF_INVALID_INDEX),
|
msg('ref_invalid_index', '', msg.REF_INVALID_INDEX),
|
||||||
msg('bad_int', '', msg.BAD_INT),
|
msg('bad_int', '', msg.BAD_INT),
|
||||||
msg('bad_float', '', msg.BAD_FLOAT),
|
msg('bad_float', '', msg.BAD_FLOAT),
|
||||||
msg('bad_email', '', msg.BAD_EMAIL),
|
msg('bad_email', '', msg.BAD_EMAIL),
|
||||||
msg('bad_url', '', msg.BAD_URL),
|
msg('bad_url', '', msg.BAD_URL),
|
||||||
msg('bad_alphanumeric', '', msg.BAD_ALPHANUMERIC),
|
msg('bad_alphanumeric', '', msg.BAD_ALPHANUMERIC),
|
||||||
|
msg('select_delesect', '', msg.SELECT_DESELECT),
|
||||||
|
msg('no_elem_selected', '', msg.NO_SELECTION),
|
||||||
|
msg('delete_confirm', '', msg.DELETE_CONFIRM),
|
||||||
|
msg('delete_done', '', msg.DELETE_DONE),
|
||||||
]
|
]
|
||||||
# Create basic files (config.py, Install.py, etc)
|
# Create basic files (config.py, Install.py, etc)
|
||||||
self.generateTool()
|
self.generateTool()
|
||||||
|
|
|
@ -133,7 +133,7 @@ class PloneInstaller:
|
||||||
updateRolesForPermission('Add portal content', tuple(allCreators),
|
updateRolesForPermission('Add portal content', tuple(allCreators),
|
||||||
appFolder)
|
appFolder)
|
||||||
# Creates the "appy" Directory view
|
# Creates the "appy" Directory view
|
||||||
if not hasattr(site.aq_base, 'appy'):
|
if not hasattr(site.aq_base, 'skyn'):
|
||||||
addDirView = self.ploneStuff['manage_addDirectoryView']
|
addDirView = self.ploneStuff['manage_addDirectoryView']
|
||||||
addDirView(site, appy.getPath() + '/gen/plone25/skin',id='skyn')
|
addDirView(site, appy.getPath() + '/gen/plone25/skin',id='skyn')
|
||||||
|
|
||||||
|
@ -266,18 +266,15 @@ class PloneInstaller:
|
||||||
current.append(self.toolInstanceName)
|
current.append(self.toolInstanceName)
|
||||||
nvProps.manage_changeProperties(**{'idsNotToList': current})
|
nvProps.manage_changeProperties(**{'idsNotToList': current})
|
||||||
|
|
||||||
# Remove workflow for the tool
|
|
||||||
#wfTool = self.ploneSite.portal_workflow
|
|
||||||
#wfTool.setChainForPortalTypes([self.toolName], '')
|
|
||||||
|
|
||||||
# Create the default flavour
|
|
||||||
self.tool = getattr(self.ploneSite, self.toolInstanceName)
|
self.tool = getattr(self.ploneSite, self.toolInstanceName)
|
||||||
self.appyTool = self.tool._appy_getWrapper(force=True)
|
self.appyTool = self.tool._appy_getWrapper(force=True)
|
||||||
if self.reinstall:
|
if self.reinstall:
|
||||||
self.tool.at_post_edit_script()
|
self.tool.createOrUpdate(False)
|
||||||
else:
|
else:
|
||||||
self.tool.at_post_create_script()
|
self.tool.createOrUpdate(True)
|
||||||
|
|
||||||
if not self.appyTool.flavours:
|
if not self.appyTool.flavours:
|
||||||
|
# Create the default flavour
|
||||||
self.appyTool.create('flavours', title=self.productName, number=1)
|
self.appyTool.create('flavours', title=self.productName, number=1)
|
||||||
self.updatePodTemplates()
|
self.updatePodTemplates()
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ NOT_UNO_ENABLED_PYTHON = '"%s" is not a UNO-enabled Python interpreter. ' \
|
||||||
'To check if a Python interpreter is UNO-enabled, ' \
|
'To check if a Python interpreter is UNO-enabled, ' \
|
||||||
'launch it and type "import uno". If you have no ' \
|
'launch it and type "import uno". If you have no ' \
|
||||||
'ImportError exception it is ok.'
|
'ImportError exception it is ok.'
|
||||||
|
jsMessages = ('no_elem_selected', 'delete_confirm')
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
class ToolMixin(AbstractMixin):
|
class ToolMixin(AbstractMixin):
|
||||||
|
@ -206,4 +207,91 @@ class ToolMixin(AbstractMixin):
|
||||||
parent = obj.getParentNode()
|
parent = obj.getParentNode()
|
||||||
if parent.id == 'skyn': return parent.getParentNode()
|
if parent.id == 'skyn': return parent.getParentNode()
|
||||||
return rq['PUBLISHED']
|
return rq['PUBLISHED']
|
||||||
|
|
||||||
|
def getAppyClass(self, contentType):
|
||||||
|
'''Gets the Appy Python class that is related to p_contentType.'''
|
||||||
|
# Retrieve first the Archetypes class corresponding to p_ContentType
|
||||||
|
portalType = self.portal_types.get(contentType)
|
||||||
|
atClassName = portalType.getProperty('content_meta_type')
|
||||||
|
appName = self.getProductConfig().PROJECTNAME
|
||||||
|
exec 'from Products.%s.%s import %s as atClass' % \
|
||||||
|
(appName, atClassName, atClassName)
|
||||||
|
# Get then the Appy Python class
|
||||||
|
return atClass.wrapperClass.__bases__[-1]
|
||||||
|
|
||||||
|
def getCreateMeans(self, contentTypeOrAppyClass):
|
||||||
|
'''Gets the different ways objects of p_contentTypeOrAppyClass (which
|
||||||
|
can be a Plone content type or a Appy class) can be created
|
||||||
|
(via a web form, by importing external data, etc). Result is a
|
||||||
|
dict whose keys are strings (ie "form", "import"...) and whose
|
||||||
|
values are additional data bout the particular mean.'''
|
||||||
|
pythonClass = contentTypeOrAppyClass
|
||||||
|
if isinstance(contentTypeOrAppyClass, basestring):
|
||||||
|
pythonClass = self.getAppyClass(pythonClass)
|
||||||
|
res = {}
|
||||||
|
if not pythonClass.__dict__.has_key('create'):
|
||||||
|
res['form'] = None
|
||||||
|
# No additional data for this means, which is the default one.
|
||||||
|
else:
|
||||||
|
means = pythonClass.create
|
||||||
|
if means:
|
||||||
|
if isinstance(means, basestring): res[means] = None
|
||||||
|
elif isinstance(means, list) or isinstance(means, tuple):
|
||||||
|
for mean in means:
|
||||||
|
if isinstance(mean, basestring):
|
||||||
|
res[mean] = None
|
||||||
|
else:
|
||||||
|
res[mean.id] = mean.__dict__
|
||||||
|
else:
|
||||||
|
res[means.id] = means.__dict__
|
||||||
|
return res
|
||||||
|
|
||||||
|
def getImportElements(self, contentType):
|
||||||
|
'''Returns the list of elements that can be imported from p_path for
|
||||||
|
p_contentType.'''
|
||||||
|
appyClass = self.getAppyClass(contentType)
|
||||||
|
importParams = self.getCreateMeans(appyClass)['import']
|
||||||
|
columnMethod = importParams['columnMethod'].__get__('')
|
||||||
|
sortMethod = importParams['sortMethod']
|
||||||
|
if sortMethod: sortMethod = sortMethod.__get__('')
|
||||||
|
elems = []
|
||||||
|
for elem in os.listdir(importParams['path']):
|
||||||
|
elemFullPath = os.path.join(importParams['path'], elem)
|
||||||
|
niceElem = columnMethod(elemFullPath)
|
||||||
|
niceElem.insert(0, elemFullPath) # To the result, I add the full
|
||||||
|
# path of the elem, which will not be shown.
|
||||||
|
elems.append(niceElem)
|
||||||
|
if sortMethod:
|
||||||
|
elems = sortMethod(elems)
|
||||||
|
return [importParams['columnHeaders'], elems]
|
||||||
|
|
||||||
|
def onImportObjects(self):
|
||||||
|
'''This method is called when the user wants to create objects from
|
||||||
|
external data.'''
|
||||||
|
rq = self.REQUEST
|
||||||
|
appyClass = self.getAppyClass(rq.get('type_name'))
|
||||||
|
importPaths = rq.get('importPath').split('|')
|
||||||
|
appFolder = self.getAppFolder()
|
||||||
|
for importPath in importPaths:
|
||||||
|
if not importPath: continue
|
||||||
|
objectId = os.path.basename(importPath)
|
||||||
|
self.appy().create(appyClass, id=objectId)
|
||||||
|
self.plone_utils.addPortalMessage(self.translate('import_done'))
|
||||||
|
return rq.RESPONSE.redirect(rq['HTTP_REFERER'])
|
||||||
|
|
||||||
|
def isAlreadyImported(self, contentType, importPath):
|
||||||
|
appFolder = self.getAppFolder()
|
||||||
|
objectId = os.path.basename(importPath)
|
||||||
|
if hasattr(appFolder.aq_base, objectId):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def getJavascriptMessages(self):
|
||||||
|
'''Returns the translated version of messages that must be shown in
|
||||||
|
Javascript popups.'''
|
||||||
|
res = ''
|
||||||
|
for msg in jsMessages:
|
||||||
|
res += 'var %s = "%s";\n' % (msg, self.translate(msg))
|
||||||
|
return res
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -20,6 +20,10 @@ class AbstractMixin:
|
||||||
inherits from this class. It contains basic functions allowing to
|
inherits from this class. It contains basic functions allowing to
|
||||||
minimize the amount of generated code.'''
|
minimize the amount of generated code.'''
|
||||||
|
|
||||||
|
def getAppyAttribute(self, name):
|
||||||
|
'''Returns method or attribute value corresponding to p_name.'''
|
||||||
|
return eval('self.%s' % name)
|
||||||
|
|
||||||
def createOrUpdate(self, created):
|
def createOrUpdate(self, created):
|
||||||
'''This method creates (if p_created is True) or updates an object.
|
'''This method creates (if p_created is True) or updates an object.
|
||||||
In the case of an object creation, p_self is a temporary object
|
In the case of an object creation, p_self is a temporary object
|
||||||
|
@ -54,6 +58,30 @@ class AbstractMixin:
|
||||||
else: obj.reindexObject()
|
else: obj.reindexObject()
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
'''This methods is self's suicide.'''
|
||||||
|
self.getParentNode().manage_delObjects([self.id])
|
||||||
|
|
||||||
|
def onCreate(self):
|
||||||
|
'''This method is called when a user wants to create a root object in
|
||||||
|
the application folder or an object through a reference field.'''
|
||||||
|
rq = self.REQUEST
|
||||||
|
if rq.get('initiator', None):
|
||||||
|
# The object to create will be linked to an initiator object through
|
||||||
|
# a ref field.
|
||||||
|
initiatorRes=self.uid_catalog.searchResults(UID=rq.get('initiator'))
|
||||||
|
rq.SESSION['initiator'] = rq.get('initiator')
|
||||||
|
rq.SESSION['initiatorField'] = rq.get('field')
|
||||||
|
rq.SESSION['initiatorTarget'] = rq.get('type_name')
|
||||||
|
if self._appy_meta_type == 'tool':
|
||||||
|
baseUrl = self.getAppFolder().absolute_url()
|
||||||
|
else:
|
||||||
|
baseUrl = self.absolute_url()
|
||||||
|
objId = self.generateUniqueId(rq.get('type_name'))
|
||||||
|
urlBack = '%s/portal_factory/%s/%s/skyn/edit' % \
|
||||||
|
(baseUrl, rq.get('type_name'), objId)
|
||||||
|
return rq.RESPONSE.redirect(urlBack)
|
||||||
|
|
||||||
def onUpdate(self):
|
def onUpdate(self):
|
||||||
'''This method is executed when a user wants to update an object.
|
'''This method is executed when a user wants to update an object.
|
||||||
The object may be a temporary object created by portal_factory in
|
The object may be a temporary object created by portal_factory in
|
||||||
|
@ -106,6 +134,13 @@ class AbstractMixin:
|
||||||
rq.set('fieldset', rq.get('nextPage'))
|
rq.set('fieldset', rq.get('nextPage'))
|
||||||
return obj.skyn.edit(obj)
|
return obj.skyn.edit(obj)
|
||||||
|
|
||||||
|
def onDelete(self):
|
||||||
|
rq = self.REQUEST
|
||||||
|
msg = self.translate('delete_done')
|
||||||
|
self.delete()
|
||||||
|
self.plone_utils.addPortalMessage(msg)
|
||||||
|
rq.RESPONSE.redirect(rq['HTTP_REFERER'])
|
||||||
|
|
||||||
def getAppyType(self, fieldName):
|
def getAppyType(self, fieldName):
|
||||||
'''Returns the Appy type corresponding to p_fieldName.'''
|
'''Returns the Appy type corresponding to p_fieldName.'''
|
||||||
res = None
|
res = None
|
||||||
|
@ -407,7 +442,7 @@ class AbstractMixin:
|
||||||
else:
|
else:
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def changeAppyRefOrder(self, fieldName, objectUid, newIndex, isDelta):
|
def changeRefOrder(self, fieldName, objectUid, newIndex, isDelta):
|
||||||
'''This method changes the position of object with uid p_objectUid in
|
'''This method changes the position of object with uid p_objectUid in
|
||||||
reference field p_fieldName to p_newIndex i p_isDelta is False, or
|
reference field p_fieldName to p_newIndex i p_isDelta is False, or
|
||||||
to actualIndex+p_newIndex if p_isDelta is True.'''
|
to actualIndex+p_newIndex if p_isDelta is True.'''
|
||||||
|
@ -421,6 +456,27 @@ class AbstractMixin:
|
||||||
pass # To implement later on
|
pass # To implement later on
|
||||||
sortedObjectsUids.insert(newIndex, objectUid)
|
sortedObjectsUids.insert(newIndex, objectUid)
|
||||||
|
|
||||||
|
def onChangeRefOrder(self):
|
||||||
|
'''This method is called when the user wants to change order of an
|
||||||
|
item in a reference field.'''
|
||||||
|
rq = self.REQUEST
|
||||||
|
# Move the item up (-1), down (+1) or at a given position ?
|
||||||
|
move = -1 # Move up
|
||||||
|
isDelta = True
|
||||||
|
if rq.get('moveDown.x', None) != None:
|
||||||
|
move = 1 # Move down
|
||||||
|
elif rq.get('moveSeveral.x', None) != None:
|
||||||
|
try:
|
||||||
|
move = int(rq.get('moveValue'))
|
||||||
|
# In this case, it is not a delta value; it is the new position
|
||||||
|
# where the item must be moved.
|
||||||
|
isDelta = False
|
||||||
|
except ValueError:
|
||||||
|
self.plone_utils.addPortalMessage(
|
||||||
|
self.translate('ref_invalid_index'))
|
||||||
|
self.changeRefOrder(rq['fieldName'], rq['refObjectUid'], move, isDelta)
|
||||||
|
return rq.RESPONSE.redirect(rq['HTTP_REFERER'])
|
||||||
|
|
||||||
def getWorkflow(self, appy=True):
|
def getWorkflow(self, appy=True):
|
||||||
'''Returns the Appy workflow instance that is relevant for this
|
'''Returns the Appy workflow instance that is relevant for this
|
||||||
object. If p_appy is False, it returns the DC workflow.'''
|
object. If p_appy is False, it returns the DC workflow.'''
|
||||||
|
@ -511,6 +567,38 @@ class AbstractMixin:
|
||||||
self.reindexObject()
|
self.reindexObject()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def onExecuteAppyAction(self):
|
||||||
|
'''This method is called every time a user wants to execute an Appy
|
||||||
|
action on an object.'''
|
||||||
|
rq = self.REQUEST
|
||||||
|
res, msg = self.executeAppyAction(rq['fieldName'])
|
||||||
|
if not msg:
|
||||||
|
# Use the default i18n messages
|
||||||
|
suffix = 'ko'
|
||||||
|
if res:
|
||||||
|
suffix = 'ok'
|
||||||
|
label='%s_action_%s' % (self.getLabelPrefix(rq['fieldName']),suffix)
|
||||||
|
msg = self.translate(label)
|
||||||
|
self.plone_utils.addPortalMessage(msg)
|
||||||
|
return rq.RESPONSE.redirect(rq['HTTP_REFERER'])
|
||||||
|
|
||||||
|
def onTriggerTransition(self):
|
||||||
|
'''This method is called whenever a user wants to trigger a workflow
|
||||||
|
transition on an object.'''
|
||||||
|
rq = self.REQUEST
|
||||||
|
self.portal_workflow.doActionFor(self, rq['workflow_action'],
|
||||||
|
comment = rq.get('comment', ''))
|
||||||
|
# Where to redirect the user back ?
|
||||||
|
urlBack = rq['HTTP_REFERER']
|
||||||
|
if urlBack.find('?') != -1:
|
||||||
|
# Remove params; this way, the user may be redirected to correct
|
||||||
|
# phase when relevant.
|
||||||
|
urlBack = urlBack[:urlBack.find('?')]
|
||||||
|
msg = self.translate(u'Your content\'s status has been modified.',
|
||||||
|
domain='plone')
|
||||||
|
self.plone_utils.addPortalMessage(msg)
|
||||||
|
return rq.RESPONSE.redirect(urlBack)
|
||||||
|
|
||||||
def callAppySelect(self, selectMethod, brains):
|
def callAppySelect(self, selectMethod, brains):
|
||||||
'''Selects objects from a Reference field.'''
|
'''Selects objects from a Reference field.'''
|
||||||
if selectMethod:
|
if selectMethod:
|
||||||
|
|
|
@ -2,63 +2,14 @@
|
||||||
##bind context=context
|
##bind context=context
|
||||||
##parameters=action
|
##parameters=action
|
||||||
rq = context.REQUEST
|
rq = context.REQUEST
|
||||||
urlBack = rq['HTTP_REFERER']
|
|
||||||
|
|
||||||
if action == 'create':
|
# Get the object impacted by the action.
|
||||||
# A user wants to create an object.
|
if rq.get('objectUid', None):
|
||||||
if rq.get('initiator', None):
|
|
||||||
# The object to create will be linked to an initiator object through a
|
|
||||||
# ref field.
|
|
||||||
initiatorRes= context.uid_catalog.searchResults(UID=rq.get('initiator'))
|
|
||||||
rq.SESSION['initiator'] = rq.get('initiator')
|
|
||||||
rq.SESSION['initiatorField'] = rq.get('field')
|
|
||||||
rq.SESSION['initiatorTarget'] = rq.get('type_name')
|
|
||||||
objId = context.generateUniqueId(rq.get('type_name'))
|
|
||||||
urlBack = '%s/portal_factory/%s/%s/skyn/edit' % \
|
|
||||||
(context.getParentNode().absolute_url(), rq.get('type_name'), objId)
|
|
||||||
|
|
||||||
elif action == 'edit': return context.getParentNode().onUpdate()
|
|
||||||
|
|
||||||
elif action == 'appyAction':
|
|
||||||
obj = context.uid_catalog(UID=rq['objectUid'])[0].getObject()
|
obj = context.uid_catalog(UID=rq['objectUid'])[0].getObject()
|
||||||
res, msg = obj.executeAppyAction(rq['fieldName'])
|
else:
|
||||||
if not msg:
|
obj = context.getParentNode() # An appy obj or in some cases the app folder.
|
||||||
# Use the default i18n messages
|
if obj.portal_type == 'AppyFolder':
|
||||||
suffix = 'ko'
|
from Products.CMFCore.utils import getToolByName
|
||||||
if res:
|
portal = getToolByName(obj, 'portal_url').getPortalObject()
|
||||||
suffix = 'ok'
|
obj = portal.get('portal_%s' % obj.id.lower()) # The tool
|
||||||
label = '%s_action_%s' % (obj.getLabelPrefix(rq['fieldName']), suffix)
|
return obj.getAppyAttribute('on'+action)()
|
||||||
msg = obj.translate(label)
|
|
||||||
context.plone_utils.addPortalMessage(msg)
|
|
||||||
|
|
||||||
elif action == 'changeRefOrder':
|
|
||||||
# Move the item up (-1), down (+1) or at a given position ?
|
|
||||||
obj = context.getParentNode()
|
|
||||||
move = -1 # Move up
|
|
||||||
isDelta = True
|
|
||||||
if rq.get('moveDown.x', None) != None:
|
|
||||||
move = 1 # Move down
|
|
||||||
elif rq.get('moveSeveral.x', None) != None:
|
|
||||||
try:
|
|
||||||
move = int(rq.get('moveValue'))
|
|
||||||
# In this case, it is not a delta value; it is the new position where
|
|
||||||
# the item must be moved.
|
|
||||||
isDelta = False
|
|
||||||
except ValueError:
|
|
||||||
context.plone_utils.addPortalMessage(
|
|
||||||
obj.translate('ref_invalid_index'))
|
|
||||||
obj.changeAppyRefOrder(rq['fieldName'], rq['objectUid'], move, isDelta)
|
|
||||||
|
|
||||||
elif action == 'triggerTransition':
|
|
||||||
obj = context.getParentNode()
|
|
||||||
from Products.CMFPlone import PloneMessageFactory as _
|
|
||||||
context.portal_workflow.doActionFor(obj, rq['workflow_action'],
|
|
||||||
comment=rq.get('comment', ''))
|
|
||||||
if urlBack.find('?') != -1:
|
|
||||||
# Remove params; this way, the user may be redirected to correct phase
|
|
||||||
# when relevant.
|
|
||||||
urlBack = urlBack[:urlBack.find('?')]
|
|
||||||
context.plone_utils.addPortalMessage(
|
|
||||||
_(u'Your content\'s status has been modified.'))
|
|
||||||
|
|
||||||
return rq.RESPONSE.redirect(urlBack)
|
|
||||||
|
|
|
@ -68,14 +68,14 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<metal:fill fill-slot="main">
|
<metal:fill fill-slot="main">
|
||||||
<div metal:use-macro="here/skyn/macros/macros/showPagePrologue"/>
|
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
|
||||||
<div metal:use-macro="here/skyn/macros/macros/showPageHeader"/>
|
<div metal:use-macro="here/skyn/macros/macros/showPageHeader"/>
|
||||||
|
|
||||||
<form name="edit_form" method="post" enctype="multipart/form-data"
|
<form name="edit_form" method="post" enctype="multipart/form-data"
|
||||||
class="enableUnloadProtection atBaseEditForm"
|
class="enableUnloadProtection atBaseEditForm"
|
||||||
tal:attributes="action python: contextObj.absolute_url()+'/skyn/do'">
|
tal:attributes="action python: contextObj.absolute_url()+'/skyn/do'">
|
||||||
<div metal:use-macro="here/skyn/macros/macros/listFields" />
|
<div metal:use-macro="here/skyn/macros/macros/listFields" />
|
||||||
<input type="hidden" name="action" value="edit"/>
|
<input type="hidden" name="action" value="Update"/>
|
||||||
<input type="hidden" name="fieldset" tal:attributes="value fieldset"/>
|
<input type="hidden" name="fieldset" tal:attributes="value fieldset"/>
|
||||||
<input type="hidden" name="pageName" tal:attributes="value pageName"/>
|
<input type="hidden" name="pageName" tal:attributes="value pageName"/>
|
||||||
<input type="hidden" name="phase" tal:attributes="value phase"/>
|
<input type="hidden" name="phase" tal:attributes="value phase"/>
|
||||||
|
|
BIN
gen/plone25/skin/eye.png
Normal file
BIN
gen/plone25/skin/eye.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 372 B |
BIN
gen/plone25/skin/import.png
Normal file
BIN
gen/plone25/skin/import.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 705 B |
123
gen/plone25/skin/import.pt
Normal file
123
gen/plone25/skin/import.pt
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
|
||||||
|
lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal"
|
||||||
|
xmlns:metal="http://xml.zope.org/namespaces/metal"
|
||||||
|
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
|
||||||
|
metal:use-macro="here/main_template/macros/master">
|
||||||
|
|
||||||
|
<tal:comment replace="nothing">Disable standard Plone green tabs</tal:comment>
|
||||||
|
<div metal:fill-slot="top_slot">
|
||||||
|
<metal:block metal:use-macro="here/global_defines/macros/defines" />
|
||||||
|
<div tal:define="dummy python:request.set('disable_border', 1)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<tal:comment replace="nothing">Fill main slot of Plone main_template</tal:comment>
|
||||||
|
<body>
|
||||||
|
<metal:fill fill-slot="main"
|
||||||
|
tal:define="appFolder context/getParentNode;
|
||||||
|
contentType request/type_name;
|
||||||
|
tool python: portal.get('portal_%s' % appFolder.id.lower());
|
||||||
|
importElems python: tool.getImportElements(contentType);
|
||||||
|
global allAreImported python:True">
|
||||||
|
|
||||||
|
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
|
||||||
|
<script language="javascript">
|
||||||
|
<!--
|
||||||
|
var importedElemsShown = false;
|
||||||
|
function toggleViewableElements() {
|
||||||
|
var rows = cssQuery('#importedElem');
|
||||||
|
var newDisplay = 'table-row';
|
||||||
|
if (importedElemsShown) newDisplay = 'none';
|
||||||
|
for (var i=0; i<rows.length; i++) {
|
||||||
|
rows[i].style.display = newDisplay;
|
||||||
|
}
|
||||||
|
importedElemsShown = !importedElemsShown;
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkBoxesChecked = true;
|
||||||
|
function toggleCheckboxes() {
|
||||||
|
var checkBoxes = cssQuery('#cbElem');
|
||||||
|
var newCheckValue = true;
|
||||||
|
if (checkBoxesChecked) newCheckValue = false;
|
||||||
|
for (var i=0; i<checkBoxes.length; i++) {
|
||||||
|
checkBoxes[i].checked = newCheckValue;
|
||||||
|
}
|
||||||
|
checkBoxesChecked = newCheckValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function importSingleElement(importPath) {
|
||||||
|
var f = document.forms['importElements'];
|
||||||
|
f.importPath.value = importPath;
|
||||||
|
f.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
function importManyElements() {
|
||||||
|
var f = document.forms['importElements'];
|
||||||
|
var importPaths = '';
|
||||||
|
// Get the values of the checkboxes
|
||||||
|
var checkBoxes = cssQuery('#cbElem');
|
||||||
|
for (var i=0; i<checkBoxes.length; i++) {
|
||||||
|
if (checkBoxes[i].checked) {
|
||||||
|
importPaths += checkBoxes[i].value + '|';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! importPaths) alert(no_elem_selected);
|
||||||
|
else {
|
||||||
|
f.importPath.value = importPaths;
|
||||||
|
f.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-->
|
||||||
|
</script>
|
||||||
|
<tal:comment replace="nothing">Form for importing several meetings at once.</tal:comment>
|
||||||
|
<form name="importElements"
|
||||||
|
tal:attributes="action python: appFolder.absolute_url()+'/skyn/do'" method="post">
|
||||||
|
<input type="hidden" name="action" value="ImportObjects"/>
|
||||||
|
<input type="hidden" name="type_name" tal:attributes="value contentType"/>
|
||||||
|
<input type="hidden" name="importPath" value=""/>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h1 tal:content="python: tool.translate('import_title')"></h1><br/>
|
||||||
|
<table cellpadding="0" cellspacing="0" class="vertical listing" width="100%">
|
||||||
|
<tr>
|
||||||
|
<th tal:repeat="columnHeader python: importElems[0]">
|
||||||
|
<img tal:condition="python: repeat['columnHeader'].number() == 1"
|
||||||
|
tal:attributes="src string:$portal_url/skyn/eye.png;
|
||||||
|
title python: tool.translate('import_show_hide')"
|
||||||
|
style="cursor:pointer" onClick="javascript:toggleViewableElements()" align="left" />
|
||||||
|
<span tal:replace="columnHeader"/>
|
||||||
|
</th>
|
||||||
|
<th tal:content="python: tool.translate('ref_actions')"></th>
|
||||||
|
<th width="20px"><img
|
||||||
|
tal:attributes="src string: $portal_url/skyn/select_elems.png;
|
||||||
|
title python: tool.translate('select_delesect')"
|
||||||
|
onClick="javascript:toggleCheckboxes()" style="cursor:pointer"/>
|
||||||
|
</tr>
|
||||||
|
<tal:row repeat="row python: importElems[1]">
|
||||||
|
<tr tal:define="alreadyImported python: tool.isAlreadyImported(contentType, row[0]);
|
||||||
|
global allAreImported python: allAreImported and alreadyImported"
|
||||||
|
tal:attributes="id python:test(alreadyImported, 'importedElem', 'notImportedElem');
|
||||||
|
style python:test(alreadyImported, 'display:none', 'display:table-row')">
|
||||||
|
<td tal:repeat="elem python: row[1:]" tal:content="elem">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="button" tal:condition="not: alreadyImported"
|
||||||
|
tal:attributes="onClick python: 'javascript:importSingleElement(\'%s\')' % row[0];
|
||||||
|
value python: tool.translate('query_import')"/>
|
||||||
|
<span tal:condition="alreadyImported" tal:replace="python: tool.translate('import_already')"/>
|
||||||
|
</td>
|
||||||
|
<td align="center"><input type="checkbox" checked="checked" class="noborder" id="cbElem"
|
||||||
|
tal:attributes="value python: row[0]" tal:condition="not: alreadyImported"/></td>
|
||||||
|
</tr>
|
||||||
|
</tal:row>
|
||||||
|
<tr tal:condition="python: not importElems[1] or allAreImported"><td colspan="15" tal:content="python: tool.translate('query_no_result')"></td></tr>
|
||||||
|
</table>
|
||||||
|
<tal:comment replace="nothing">Button for importing several elements at once.</tal:comment>
|
||||||
|
<p align="right"><br/>
|
||||||
|
<input type="button" onClick="javascript:importManyElements()"
|
||||||
|
tal:condition="python: importElems[1] and not allAreImported"
|
||||||
|
tal:attributes="value python:tool.translate('import_many')"/>
|
||||||
|
</p>
|
||||||
|
</metal:fill>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -104,7 +104,7 @@
|
||||||
|
|
||||||
<div metal:define-macro="showActionField">
|
<div metal:define-macro="showActionField">
|
||||||
<form name="executeAppyAction" action="skyn/do" method="POST">
|
<form name="executeAppyAction" action="skyn/do" method="POST">
|
||||||
<input type="hidden" name="actionType" value="appyAction"/>
|
<input type="hidden" name="action" value="ExecuteAppyAction"/>
|
||||||
<input type="hidden" name="objectUid" tal:attributes="value contextObj/UID"/>
|
<input type="hidden" name="objectUid" tal:attributes="value contextObj/UID"/>
|
||||||
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
|
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
|
||||||
<input type="submit" name="do" tal:attributes="value label"/>
|
<input type="submit" name="do" tal:attributes="value label"/>
|
||||||
|
@ -300,56 +300,72 @@
|
||||||
</dl>
|
</dl>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div metal:define-macro="showPagePrologue">
|
<div metal:define-macro="pagePrologue">
|
||||||
<tal:comment replace="nothing">Global Javascript functions, used in edit and
|
<tal:comment replace="nothing">Global elements used in every page.</tal:comment>
|
||||||
consult views, are defined gere.</tal:comment>
|
|
||||||
|
|
||||||
|
<tal:comment replace="nothing">Javascript messages</tal:comment>
|
||||||
|
<script language="javascript" tal:content="tool/getJavascriptMessages"></script>
|
||||||
|
|
||||||
|
<tal:comment replace="nothing">"Static" javascripts</tal:comment>
|
||||||
<script language="javascript">
|
<script language="javascript">
|
||||||
<!--
|
<!--
|
||||||
// This function turns a checkbox into a radio button... sort of
|
// Function used by checkbox widgets for having radio-button-like behaviour
|
||||||
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
|
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
|
||||||
vis = document.getElementById(visibleCheckbox);
|
vis = document.getElementById(visibleCheckbox);
|
||||||
hidden = document.getElementById(hiddenBoolean);
|
hidden = document.getElementById(hiddenBoolean);
|
||||||
if (vis.checked) hidden.value = 'True';
|
if (vis.checked) hidden.value = 'True';
|
||||||
else hidden.value = 'False';
|
else hidden.value = 'False';
|
||||||
|
}
|
||||||
|
// Functions used for master/slave relationships between widgets
|
||||||
|
function getMasterValue(widget) {
|
||||||
|
// Returns an array of selected options in a select widget
|
||||||
|
res = new Array();
|
||||||
|
if (widget.type == 'checkbox') {
|
||||||
|
var mv = widget.checked + '';
|
||||||
|
mv = mv.charAt(0).toUpperCase() + mv.substr(1);
|
||||||
|
res.push(mv);
|
||||||
|
}
|
||||||
|
else { // SELECT widget
|
||||||
|
for (var i=0; i < widget.options.length; i++) {
|
||||||
|
if (widget.options[i].selected) res.push(widget.options[i].value);
|
||||||
}
|
}
|
||||||
// Returns an array of selected options in a select widget
|
}
|
||||||
function getMasterValue(widget) {
|
return res;
|
||||||
res = new Array();
|
}
|
||||||
if (widget.type == 'checkbox') {
|
function updateSlaves(masterValues, appyTypeId) {
|
||||||
var mv = widget.checked + '';
|
// Given the value(s) selected in a master field, this function updates the
|
||||||
mv = mv.charAt(0).toUpperCase() + mv.substr(1);
|
// state of all corresponding slaves.
|
||||||
res.push(mv);
|
var slaves = cssQuery('div.slave_' + appyTypeId);
|
||||||
}
|
for (var i=0; i< slaves.length; i++){
|
||||||
else { // SELECT widget
|
slaves[i].style.display = "none";
|
||||||
for (var i=0; i < widget.options.length; i++) {
|
}
|
||||||
if (widget.options[i].selected) res.push(widget.options[i].value);
|
for (var i=0; i < masterValues.length; i++) {
|
||||||
}
|
var activeSlaves = cssQuery('div.slaveValue_' + appyTypeId + '_' + masterValues[i]);
|
||||||
}
|
for (var j=0; j < activeSlaves.length; j++){
|
||||||
return res;
|
activeSlaves[j].style.display = "";
|
||||||
}
|
}
|
||||||
// Given the value(s) selected in a master field, this function updates the
|
}
|
||||||
// state of all corresponding slaves.
|
}
|
||||||
function updateSlaves(masterValues, appyTypeId) {
|
// Function used for triggering a workflow transition
|
||||||
var slaves = cssQuery('div.slave_' + appyTypeId);
|
function triggerTransition(transitionId) {
|
||||||
for (var i=0; i< slaves.length; i++){
|
var theForm = document.getElementById('triggerTransitionForm');
|
||||||
slaves[i].style.display = "none";
|
theForm.workflow_action.value = transitionId;
|
||||||
}
|
theForm.submit();
|
||||||
for (var i=0; i < masterValues.length; i++) {
|
}
|
||||||
var activeSlaves = cssQuery('div.slaveValue_' + appyTypeId + '_' + masterValues[i]);
|
function onDeleteObject(objectUid) {
|
||||||
for (var j=0; j < activeSlaves.length; j++){
|
if (confirm(delete_confirm)) {
|
||||||
activeSlaves[j].style.display = "";
|
f = document.getElementById('deleteForm');
|
||||||
}
|
f.objectUid.value = objectUid;
|
||||||
}
|
f.submit();
|
||||||
}
|
}
|
||||||
// Triggers a workflow transition
|
}
|
||||||
function triggerTransition(transitionId) {
|
-->
|
||||||
var theForm = document.getElementById('triggerTransitionForm');
|
</script>
|
||||||
theForm.workflow_action.value = transitionId;
|
<tal:comment replace="nothing">Global form for deleting an object</tal:comment>
|
||||||
theForm.submit();
|
<form id="deleteForm" method="post" action="skyn/do">
|
||||||
}
|
<input type="hidden" name="action" value="Delete"/>
|
||||||
-->
|
<input type="hidden" name="objectUid"/>
|
||||||
</script>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div metal:define-macro="showPageHeader"
|
<div metal:define-macro="showPageHeader"
|
||||||
|
@ -681,10 +697,11 @@
|
||||||
<img src="edit.gif" title="Edit" i18n:domain="plone" i18n:attributes="title" />
|
<img src="edit.gif" title="Edit" i18n:domain="plone" i18n:attributes="title" />
|
||||||
</a></td>
|
</a></td>
|
||||||
<tal:comment replace="nothing">Delete the element</tal:comment>
|
<tal:comment replace="nothing">Delete the element</tal:comment>
|
||||||
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/delete_confirmation'"
|
<td class="noPadding">
|
||||||
tal:condition="python: member.has_permission('Delete objects', obj)">
|
<img tal:condition="python: member.has_permission('Delete objects', obj)"
|
||||||
<img src="delete_icon.gif" title="Delete" i18n:domain="plone" i18n:attributes="title" />
|
src="delete_icon.gif" title="Delete" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
|
||||||
</a></td>
|
tal:attributes="onClick python:'javascript:onDeleteObject(\'%s\')' % obj.UID()"/>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
|
@ -740,7 +757,7 @@
|
||||||
tal:condition="transitions">
|
tal:condition="transitions">
|
||||||
<form id="triggerTransitionForm" method="post"
|
<form id="triggerTransitionForm" method="post"
|
||||||
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'">
|
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'">
|
||||||
<input type="hidden" name="actionType" value="triggerTransition"/>
|
<input type="hidden" name="action" value="TriggerTransition"/>
|
||||||
<input type="hidden" name="workflow_action"/>
|
<input type="hidden" name="workflow_action"/>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -3,62 +3,74 @@
|
||||||
|
|
||||||
<tal:comment replace="nothing">This page presents results of queries</tal:comment>
|
<tal:comment replace="nothing">This page presents results of queries</tal:comment>
|
||||||
<body>
|
<body>
|
||||||
<div metal:fill-slot="top_slot">
|
|
||||||
<metal:block metal:use-macro="here/global_defines/macros/defines" />
|
|
||||||
<div tal:define="dummy python:request.set('disable_border', 1)" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<tal:comment replace="nothing">We suppose we are in the app folder here.</tal:comment>
|
<tal:comment replace="nothing">Disable standard Plone green tabs</tal:comment>
|
||||||
<div metal:fill-slot="main"
|
<div metal:fill-slot="top_slot">
|
||||||
tal:define="appFolder context/getParentNode;
|
<metal:block metal:use-macro="here/global_defines/macros/defines" />
|
||||||
appName appFolder/id;
|
<div tal:define="dummy python:request.set('disable_border', 1)" />
|
||||||
tool python: portal.get('portal_%s' % appName.lower());
|
</div>
|
||||||
queryName python:context.REQUEST.get('query');
|
|
||||||
flavourNumber python:context.REQUEST.get('flavourNumber');
|
|
||||||
rootClasses tool/getRootClasses;
|
|
||||||
rootTypes python: test(flavourNumber=='1', rootClasses, ['%s_%s' % (rc, flavourNumber) for rc in rootClasses]);
|
|
||||||
rootClassesQuery python:','.join(rootClasses);
|
|
||||||
mainTabSelected python: queryName.find(',') != -1">
|
|
||||||
|
|
||||||
<span tal:condition="python: queryName and (queryName != 'none')">
|
<tal:comment replace="nothing">We suppose we are in the app folder here.</tal:comment>
|
||||||
<span tal:define="queryResult python: tool.executeQuery(queryName, int(flavourNumber));
|
<div metal:fill-slot="main"
|
||||||
batch queryResult">
|
tal:define="appFolder context/getParentNode;
|
||||||
|
appName appFolder/id;
|
||||||
|
tool python: portal.get('portal_%s' % appName.lower());
|
||||||
|
queryName python:context.REQUEST.get('query');
|
||||||
|
flavourNumber python:context.REQUEST.get('flavourNumber');
|
||||||
|
rootClasses tool/getRootClasses;
|
||||||
|
rootTypes python: test(flavourNumber=='1', rootClasses, ['%s_%s' % (rc, flavourNumber) for rc in rootClasses]);
|
||||||
|
rootClassesQuery python:','.join(rootClasses);
|
||||||
|
mainTabSelected python: queryName.find(',') != -1">
|
||||||
|
|
||||||
<tal:comment replace="nothing">Tabs</tal:comment>
|
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
|
||||||
<ul class="contentViews appyTabs">
|
<span tal:condition="python: queryName and (queryName != 'none')">
|
||||||
<tal:comment replace="nothing">Tab "All objects"</tal:comment>
|
<span tal:define="queryResult python: tool.executeQuery(queryName, int(flavourNumber));
|
||||||
<li tal:define="selected python:mainTabSelected"
|
batch queryResult">
|
||||||
tal:attributes="class python:test(selected, 'selected', 'plain')"
|
|
||||||
tal:condition="python: len(rootClasses)>1">
|
|
||||||
|
|
||||||
<a tal:content="python: tool.translate('query_consult_all')"
|
<tal:comment replace="nothing">Tabs</tal:comment>
|
||||||
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootClassesQuery, flavourNumber)"></a>
|
<ul class="contentViews appyTabs">
|
||||||
</li>
|
<tal:comment replace="nothing">Tab "All objects"</tal:comment>
|
||||||
<tal:comment replace="nothing">One tab for each root content type</tal:comment>
|
<li tal:define="selected python:mainTabSelected"
|
||||||
<tal:tab repeat="rootContentType rootTypes">
|
tal:attributes="class python:test(selected, 'selected', 'plain')"
|
||||||
<li tal:define="selected python:queryName == rootContentType"
|
tal:condition="python: len(rootClasses)>1">
|
||||||
tal:attributes="class python:test(selected, 'selected', 'plain')">
|
|
||||||
<a tal:content="python: tool.translate(rootContentType)"
|
|
||||||
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootContentType, flavourNumber)"/>
|
|
||||||
<img style="cursor:pointer" class="appyPlusImg"
|
|
||||||
tal:define="addPermission python: '%s: Add %s' % (appName, rootContentType)"
|
|
||||||
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/do?action=create&type_name=%s\'' % (appFolder.absolute_url(), rootContentType);
|
|
||||||
src string: $portal_url/skyn/plus.png;
|
|
||||||
title python: tool.translate('query_create')"
|
|
||||||
tal:condition="python: member.has_permission(addPermission, appFolder)"/>
|
|
||||||
</li>
|
|
||||||
</tal:tab>
|
|
||||||
</ul>
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<tal:comment replace="nothing">Query result</tal:comment>
|
<a tal:content="python: tool.translate('query_consult_all')"
|
||||||
<span tal:condition="queryResult">
|
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootClassesQuery, flavourNumber)"></a>
|
||||||
<span metal:use-macro="here/skyn/macros/macros/queryResult"></span>
|
</li>
|
||||||
</span>
|
<tal:comment replace="nothing">One tab for each root content type</tal:comment>
|
||||||
<span tal:condition="not: queryResult"
|
<tal:tab repeat="rootContentType rootTypes">
|
||||||
tal:content="python: tool.translate('query_no_result')">No result.</span>
|
<li tal:define="selected python:queryName == rootContentType;
|
||||||
</span>
|
addPermission python: '%s: Add %s' % (appName, rootContentType);
|
||||||
</span>
|
userMayAdd python: member.has_permission(addPermission, appFolder);
|
||||||
</div>
|
createMeans python: tool.getCreateMeans(rootContentType)"
|
||||||
|
tal:attributes="class python:test(selected, 'selected', 'plain')">
|
||||||
|
<a tal:content="python: tool.translate(rootContentType)"
|
||||||
|
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootContentType, flavourNumber)"/>
|
||||||
|
<tal:comment replace="nothing">Create a new object from a web form</tal:comment>
|
||||||
|
<img style="cursor:pointer" class="appyPlusImg"
|
||||||
|
tal:condition="python: ('form' in createMeans) and userMayAdd"
|
||||||
|
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/do?action=Create&type_name=%s\'' % (appFolder.absolute_url(), rootContentType);
|
||||||
|
src string: $portal_url/skyn/plus.png;
|
||||||
|
title python: tool.translate('query_create')"/>
|
||||||
|
<tal:comment replace="nothing">Create (a) new object(s) by importing data</tal:comment>
|
||||||
|
<img style="cursor:pointer" class="appyPlusImg"
|
||||||
|
tal:condition="python: ('import' in createMeans) and userMayAdd"
|
||||||
|
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/import?type_name=%s\'' % (appFolder.absolute_url(), rootContentType);
|
||||||
|
src string: $portal_url/skyn/import.png;
|
||||||
|
title python: tool.translate('query_import')"/>
|
||||||
|
</li>
|
||||||
|
</tal:tab>
|
||||||
|
</ul>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<tal:comment replace="nothing">Query result</tal:comment>
|
||||||
|
<span tal:condition="queryResult">
|
||||||
|
<span metal:use-macro="here/skyn/macros/macros/queryResult"></span>
|
||||||
|
</span>
|
||||||
|
<span tal:condition="not: queryResult"
|
||||||
|
tal:content="python: tool.translate('query_no_result')">No result.</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -26,13 +26,13 @@
|
||||||
<img src="delete_icon.gif" title="label_remove" i18n:domain="plone" i18n:attributes="title" />
|
<img src="delete_icon.gif" title="label_remove" i18n:domain="plone" i18n:attributes="title" />
|
||||||
</a></td>
|
</a></td>
|
||||||
<tal:comment replace="nothing">Arrows for moving objects up or down</tal:comment>
|
<tal:comment replace="nothing">Arrows for moving objects up or down</tal:comment>
|
||||||
<td class="noPadding" tal:condition="python: len(objs)>1">
|
<td class="noPadding" tal:condition="python: len(objs)>1">
|
||||||
<form tal:condition="python: member.has_permission('Modify portal content', obj)"
|
<form tal:condition="python: member.has_permission('Modify portal content', obj)"
|
||||||
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'"
|
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'"
|
||||||
tal:define="objectIndex python:contextObj.getAppyRefIndex(field.getName(), obj)">
|
tal:define="objectIndex python:contextObj.getAppyRefIndex(field.getName(), obj)">
|
||||||
<input type="hidden" name="actionType" value="changeRefOrder"/>
|
<input type="hidden" name="action" value="ChangeRefOrder"/>
|
||||||
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
|
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
|
||||||
<input type="hidden" name="objectUid" tal:attributes="value obj/UID"/>
|
<input type="hidden" name="refObjectUid" tal:attributes="value obj/UID"/>
|
||||||
<tal:comment replace="nothing">Arrow up</tal:comment>
|
<tal:comment replace="nothing">Arrow up</tal:comment>
|
||||||
<span tal:condition="python: objectIndex > 0">
|
<span tal:condition="python: objectIndex > 0">
|
||||||
<input type="image" name="moveUp" class="imageInput"
|
<input type="image" name="moveUp" class="imageInput"
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
<img style="cursor:pointer" tal:condition="showPlusIcon"
|
<img style="cursor:pointer" tal:condition="showPlusIcon"
|
||||||
tal:attributes="src string:$portal_url/skyn/plus.png;
|
tal:attributes="src string:$portal_url/skyn/plus.png;
|
||||||
title python: tool.translate('add_ref');
|
title python: tool.translate('add_ref');
|
||||||
onClick python: 'href: window.location=\'%s/skyn/do?action=create&initiator=%s&field=%s&type_name=%s\'' % (folder.absolute_url(), contextObj.UID(), field.getName(), linkedPortalType)"/>
|
onClick python: 'href: window.location=\'%s/skyn/do?action=Create&initiator=%s&field=%s&type_name=%s\'' % (folder.absolute_url(), contextObj.UID(), field.getName(), linkedPortalType)"/>
|
||||||
</metal:plusIcon>
|
</metal:plusIcon>
|
||||||
|
|
||||||
<div metal:define-macro="showReference"
|
<div metal:define-macro="showReference"
|
||||||
|
|
BIN
gen/plone25/skin/select_elems.png
Normal file
BIN
gen/plone25/skin/select_elems.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 235 B |
|
@ -27,7 +27,7 @@
|
||||||
phase request/phase|phaseInfo/name;
|
phase request/phase|phaseInfo/name;
|
||||||
pageName python: contextObj.getAppyPage(isEdit, phaseInfo);
|
pageName python: contextObj.getAppyPage(isEdit, phaseInfo);
|
||||||
showWorkflow python: flavour.getAttr('showWorkflowFor' + contextObj.meta_type)">
|
showWorkflow python: flavour.getAttr('showWorkflowFor' + contextObj.meta_type)">
|
||||||
<div metal:use-macro="here/skyn/macros/macros/showPagePrologue"/>
|
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
|
||||||
<div metal:use-macro="here/skyn/macros/macros/showPageHeader"/>
|
<div metal:use-macro="here/skyn/macros/macros/showPageHeader"/>
|
||||||
<div metal:use-macro="here/skyn/macros/macros/listFields" />
|
<div metal:use-macro="here/skyn/macros/macros/listFields" />
|
||||||
<div metal:use-macro="here/skyn/macros/macros/showPageFooter"/>
|
<div metal:use-macro="here/skyn/macros/macros/showPageFooter"/>
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
float:right;
|
float:right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#importedElem {
|
||||||
|
color: grey;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.appyTabs {
|
.appyTabs {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
@ -126,10 +131,13 @@ dl.expandedInlineCollapsible dt.collapsibleHeader, dl.expandedBlockCollapsible d
|
||||||
|
|
||||||
/* Minor layout changes in fieldsets and tables */
|
/* Minor layout changes in fieldsets and tables */
|
||||||
fieldset {
|
fieldset {
|
||||||
margin: 0em 0em;
|
margin: 0 0 0 0;
|
||||||
line-height: 1.0em;
|
line-height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fieldset {
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
/* Group fieldsets */
|
/* Group fieldsets */
|
||||||
.appyGroup {
|
.appyGroup {
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
|
@ -192,6 +200,9 @@ fieldset {
|
||||||
line-height: 1.0em;
|
line-height: 1.0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
margin: 0 0.2em 0.2em 0;
|
||||||
|
}
|
||||||
/* Portlet elements */
|
/* Portlet elements */
|
||||||
.portletAppyItem {
|
.portletAppyItem {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
10
gen/po.py
10
gen/po.py
|
@ -49,8 +49,14 @@ class PoMessage:
|
||||||
REF_MOVE_DOWN = 'Move down'
|
REF_MOVE_DOWN = 'Move down'
|
||||||
REF_INVALID_INDEX = 'No move occurred: please specify a valid number.'
|
REF_INVALID_INDEX = 'No move occurred: please specify a valid number.'
|
||||||
QUERY_CREATE = 'create'
|
QUERY_CREATE = 'create'
|
||||||
|
QUERY_IMPORT = 'import'
|
||||||
QUERY_CONSULT_ALL = 'consult all'
|
QUERY_CONSULT_ALL = 'consult all'
|
||||||
QUERY_NO_RESULT = 'Nothing to see for the moment.'
|
QUERY_NO_RESULT = 'Nothing to see for the moment.'
|
||||||
|
IMPORT_TITLE = 'Importing data into your application'
|
||||||
|
IMPORT_SHOW_HIDE = 'Show / hide alreadly imported elements.'
|
||||||
|
IMPORT_ALREADY = 'Already imported.'
|
||||||
|
IMPORT_MANY = 'Import selected elements'
|
||||||
|
IMPORT_DONE = 'Import terminated successfully.'
|
||||||
WORKFLOW_COMMENT = 'Optional comment'
|
WORKFLOW_COMMENT = 'Optional comment'
|
||||||
WORKFLOW_STATE = 'state'
|
WORKFLOW_STATE = 'state'
|
||||||
PHASE = 'phase'
|
PHASE = 'phase'
|
||||||
|
@ -71,6 +77,10 @@ class PoMessage:
|
||||||
EMAIL_SUBJECT = '${siteTitle} - Action \\"${transitionName}\\" has been ' \
|
EMAIL_SUBJECT = '${siteTitle} - Action \\"${transitionName}\\" has been ' \
|
||||||
'performed on element entitled \\"${objectTitle}\\".'
|
'performed on element entitled \\"${objectTitle}\\".'
|
||||||
EMAIL_BODY = 'You can consult this element at ${objectUrl}.'
|
EMAIL_BODY = 'You can consult this element at ${objectUrl}.'
|
||||||
|
SELECT_DESELECT = '(Un)select all'
|
||||||
|
NO_SELECTION = 'You must select at least one element.'
|
||||||
|
DELETE_CONFIRM = 'Are you sure you want to delete this element?'
|
||||||
|
DELETE_DONE = 'The element has been deleted.'
|
||||||
|
|
||||||
def __init__(self, id, msg, default, fuzzy=False, comments=[]):
|
def __init__(self, id, msg, default, fuzzy=False, comments=[]):
|
||||||
self.id = id
|
self.id = id
|
||||||
|
|
Loading…
Reference in a new issue