Fixed bug #394258 and added a new skin directly within Appy, such that every generated product does not need to include copies of Appy images and web pages.

This commit is contained in:
Gaetan Delannay 2009-10-18 14:52:27 +02:00
parent 280c5fe0c0
commit cbc7d257d4
50 changed files with 1317 additions and 1189 deletions

View file

@ -1 +1,3 @@
import os.path
def getPath(): return os.path.dirname(__file__)

0
gen/plone25/__init__.py Executable file → Normal file
View file

0
gen/plone25/descriptors.py Executable file → Normal file
View file

55
gen/plone25/generator.py Executable file → Normal file
View file

@ -15,10 +15,6 @@ from descriptors import ArchetypeFieldDescriptor, ArchetypesClassDescriptor, \
# Common methods that need to be defined on every Archetype class --------------
COMMON_METHODS = '''
def at_post_create_script(self): self._appy_onEdit(True)
def at_post_edit_script(self): self._appy_onEdit(False)
def post_validate(self, REQUEST=None, errors=None):
if not errors: self._appy_validateAllFields(REQUEST, errors)
def getTool(self): return self.%s
def getProductConfig(self): return Products.%s.config
'''
@ -50,7 +46,6 @@ class Generator(AbstractGenerator):
'portletName': self.portletName, 'queryName': self.queryName,
'toolInstanceName': self.toolInstanceName,
'podTemplateName': self.podTemplateName,
'macros': '%s_macros' % self.applicationName.lower(),
'commonMethods': commonMethods})
# Predefined class descriptors
self.toolDescr = ToolClassDescriptor(Tool, self)
@ -117,14 +112,12 @@ class Generator(AbstractGenerator):
msg('bad_alphanumeric', '', msg.BAD_ALPHANUMERIC),
]
# Create basic files (config.py, Install.py, etc)
self.generateAppyReference()
self.generateTool()
self.generateConfig()
self.generateInit()
self.generateInstall()
self.generateWorkflows()
self.generateWrappers()
self.generatePortlet()
if self.config.frontPage == True:
self.labels.append(msg('front_page_text', '', msg.FRONT_PAGE_TEXT))
self.copyFile('frontPage.pt', self.repls,
@ -135,20 +128,11 @@ class Generator(AbstractGenerator):
destFolder='profiles/default')
self.copyFile('ProfileInit.py', self.repls, destFolder='profiles',
destName='__init__.py')
self.copyFile('Portlet.pt', self.repls,
destName='%s.pt' % self.portletName, destFolder=self.skinsFolder)
self.copyFile('tool.gif', {})
self.copyFile('Macros.pt', self.repls, destFolder=self.skinsFolder,
destName='%s_macros.pt' % self.applicationName.lower())
self.copyFile('appy_view.pt', self.repls, destFolder=self.skinsFolder,
destName='%s_appy_view.pt' % self.applicationName)
self.copyFile('appy_edit.cpt', self.repls, destFolder=self.skinsFolder,
destName='%s_appy_edit.cpt' % self.applicationName)
self.copyFile('appy_edit.cpt.metadata', self.repls,
destFolder=self.skinsFolder,
destName='%s_appy_edit.cpt.metadata'%self.applicationName)
self.copyFile('Styles.css.dtml', self.repls, destFolder=self.skinsFolder,
destName = '%s.css.dtml' % self.applicationName)
self.copyFile('do.py', self.repls, destFolder=self.skinsFolder,
destName='%s_do.py' % self.applicationName)
if self.config.minimalistPlone:
self.copyFile('colophon.pt', self.repls,destFolder=self.skinsFolder)
self.copyFile('footer.pt', self.repls, destFolder=self.skinsFolder)
@ -241,18 +225,6 @@ class Generator(AbstractGenerator):
self.referers[refClassName] = []
self.referers[refClassName].append( (fieldDescr, relationship))
def generatePortlet(self):
rootClasses = ''
for classDescr in self.classes:
if classDescr.isRoot():
rootClasses += "'%s'," % classDescr.name
repls = self.repls.copy()
repls['rootClasses'] = rootClasses
self.copyFile('Portlet.pt', repls, destName='%s.pt' % self.portletName,
destFolder=self.skinsFolder)
self.copyFile('Query.pt', repls, destName='%s.pt' % self.queryName,
destFolder=self.skinsFolder)
def generateConfig(self):
# Compute referers
referers = ''
@ -299,6 +271,11 @@ class Generator(AbstractGenerator):
theImport = 'import %s' % classDescr.klass.__module__
if theImport not in imports:
imports.append(theImport)
# Compute root classes
rootClasses = ''
for classDescr in self.classes:
if classDescr.isRoot():
rootClasses += "'%s'," % classDescr.name
# Compute list of add permissions
addPermissions = ''
for classDescr in self.classes:
@ -308,6 +285,7 @@ class Generator(AbstractGenerator):
# Compute list of used roles for registering them if needed
repls['roles'] = ','.join(['"%s"' % r for r in \
self.getAllUsedRoles(appOnly=True)])
repls['rootClasses'] = rootClasses
repls['referers'] = referers
repls['workflowInstancesInit'] = wfInit
repls['imports'] = '\n'.join(imports)
@ -615,23 +593,6 @@ class Generator(AbstractGenerator):
repls['wrapperClass'] = '%s_Wrapper' % self.podTemplateDescr.name
self.copyFile('PodTemplate.py', repls,
destName='%s.py' % self.podTemplateName)
for imgName in PodTemplate.podFormat.validator:
self.copyFile('%s.png' % imgName, {},
destFolder=self.skinsFolder)
refFiles = ('createAppyObject.cpy', 'createAppyObject.cpy.metadata',
'arrowUp.png', 'arrowDown.png', 'plus.png', 'appyConfig.gif',
'nextPhase.png', 'nextState.png', 'done.png', 'current.png')
prefixedRefFiles = ('AppyReference.pt',)
def generateAppyReference(self):
'''Generates what is needed to use Appy-specific references.'''
# Some i18n messages
Msg = PoMessage
for refFile in self.prefixedRefFiles:
self.copyFile(refFile, self.repls, destFolder=self.skinsFolder,
destName='%s%s' % (self.applicationName, refFile))
for refFile in self.refFiles:
self.copyFile(refFile, self.repls, destFolder=self.skinsFolder)
def generateClass(self, classDescr):
'''Is called each time an Appy class is found in the application, for

View file

@ -5,6 +5,7 @@
import os, os.path
from StringIO import StringIO
from sets import Set
import appy
from appy.gen.utils import produceNiceMessage
from appy.gen.plone25.utils import updateRolesForPermission
@ -36,8 +37,7 @@ class PloneInstaller:
self.ploneStuff = ploneStuff # A dict of some Plone functions or vars
self.toLog = StringIO()
self.typeAliases = {'sharing': '', 'gethtml': '',
'(Default)': '%s_appy_view' % self.productName,
'edit': '%s_appy_edit' % self.productName,
'(Default)': 'skyn/view', 'edit': 'skyn/edit',
'index.html': '', 'properties': '', 'view': ''}
self.tool = None # The Plone version of the application tool
self.appyTool = None # The Appy version of the application tool
@ -96,7 +96,9 @@ class PloneInstaller:
def installRootFolder(self):
'''Creates and/or configures, at the root of the Plone site and if
needed, the folder where the application will store instances of
root classes.'''
root classes. Creates also the 'appy' folder (more precisely,
a Filesystem Directory View) at the root of the site, for storing
appy-wide ZPTs an images.'''
# Register first our own Appy folder type if needed.
site = self.ploneSite
if not hasattr(site.portal_types, self.appyFolderType):
@ -130,6 +132,10 @@ class PloneInstaller:
# have the main permission "Add portal content".
updateRolesForPermission('Add portal content', tuple(allCreators),
appFolder)
# Creates the "appy" Directory view
if not hasattr(site.aq_base, 'appy'):
addDirView = self.ploneStuff['manage_addDirectoryView']
addDirView(site, appy.getPath() + '/gen/plone25/skin',id='skyn')
def installTypes(self):
'''Registers and configures the Plone content types that correspond to
@ -154,10 +160,10 @@ class PloneInstaller:
typeActions = typeInfo.listActions()
for action in typeActions:
if action.id == 'view':
page = '%s_appy_view' % self.productName
page = 'skyn/view'
action.edit(action='string:${object_url}/%s' % page)
elif action.id == 'edit':
page = '%s_appy_edit' % self.productName
page = 'skyn/edit'
action.edit(action='string:${object_url}/%s' % page)
# Configure types for instance creation through portal_factory
@ -459,8 +465,10 @@ class ZopeInstaller:
def installApplication(self):
'''Performs some application-wide installation steps.'''
self.ploneStuff['DirectoryView'].registerDirectory('skins',
self.ploneStuff['product_globals'])
register = self.ploneStuff['DirectoryView'].registerDirectory
register('skins', self.ploneStuff['product_globals'])
# Register the appy skin folder among DirectoryView'able folders
register('skin', appy.getPath() + '/gen/plone25')
def installTool(self):
'''Installs the tool.'''

View file

@ -86,6 +86,10 @@ class ToolMixin(AbstractMixin):
appName = self.getProductConfig().PROJECTNAME
return getattr(portal, appName)
def getRootClasses(self):
'''Returns the list of root classes for this application.'''
return self.getProductConfig().rootClasses
def showPortlet(self):
return not self.portal_membership.isAnonymousUser()
@ -194,4 +198,12 @@ class ToolMixin(AbstractMixin):
self.portal_url.getPortalPath()
appName = self.getProductConfig().PROJECTNAME
return self.utranslate(label, self.translationMapping, domain=appName)
def getPublishedObject(self):
'''Gets the currently published object.'''
rq = self.REQUEST
obj = rq['PUBLISHED']
parent = obj.getParentNode()
if parent.id == 'skyn': return parent.getParentNode()
return rq['PUBLISHED']
# ------------------------------------------------------------------------------

View file

@ -20,38 +20,91 @@ class AbstractMixin:
inherits from this class. It contains basic functions allowing to
minimize the amount of generated code.'''
def content_edit_impl(self, state, id):
'''This method is called by the Plone machinery every time an object
must be created or edited through the edit view.'''
def createOrUpdate(self, created):
'''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
created in the request by portal_factory, and this method creates
the corresponding final object. In the case of an update, this
method simply updates fields of p_self.'''
rq = self.REQUEST
newSelf = self.portal_factory.doCreate(self, id)
newSelf.processForm()
obj = self
if created:
obj = self.portal_factory.doCreate(self, self.id) # portal_factory
# creates the final object from the temp object.
obj.processForm()
# Get the current language and put it in the request
if rq.form.has_key('current_lang'):
rq.form['language'] = rq.form.get('current_lang')
# Generate the message returned to the user after creation/edition
portal_status_message = self.translate(
msgid='message_content_changes_saved',
default='Content changes saved.')
portal_status_message = rq.get(
'portal_status_message', portal_status_message)
# Manage references
obj._appy_manageRefs(created)
if obj.wrapperClass:
# Get the wrapper first
appyWrapper = obj._appy_getWrapper(force=True)
# Call the custom "onEdit" if available
try:
appyWrapper.onEdit(created)
except AttributeError, ae:
pass
# Manage "add" permissions
obj._appy_managePermissions()
# Re/unindex object
if obj._appy_meta_type == 'tool': self.unindexObject()
else: obj.reindexObject()
return obj
# What page must I display next ?
previousClicked = rq.get('form_previous', None)
nextClicked = rq.get('form_next', None)
if previousClicked or nextClicked:
# We must redirect the user to the previous or next page
targetPage = rq.get('nextPage', None)
if previousClicked:
targetPage = rq.get('previousPage', None)
return state.set(status='next_schemata', context=newSelf,
fieldset=targetPage,
portal_status_message=portal_status_message)
def onUpdate(self):
'''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 request. In this case, the update consists in the creation of
the "final" object in the database. If the object is not a temporary
one, this method updates its fields in the database.'''
rq = self.REQUEST
errors = {}
errorMessage = self.translate(
'Please correct the indicated errors.', domain='plone')
# Go back to the consult view if the user clicked on 'Cancel'
if rq.get('buttonCancel', None):
urlBack = '%s/skyn/view?phase=%s&pageName=%s' % (
self.absolute_url(), rq.get('phase'), rq.get('pageName'))
self.plone_utils.addPortalMessage(
self.translate('Changes canceled.', domain='plone'))
return rq.RESPONSE.redirect(urlBack)
# Trigger field-specific validation
self.validate(REQUEST=rq, errors=errors, data=1, metadata=0)
if errors:
rq.set('errors', errors)
self.plone_utils.addPortalMessage(errorMessage)
return self.skyn.edit(self)
else:
return state.set(status='success', context=newSelf,
portal_status_message=portal_status_message)
# Trigger inter-field validation
self.validateAllFields(rq, errors)
if errors:
rq.set('errors', errors)
self.plone_utils.addPortalMessage(errorMessage)
return self.skyn.edit(self)
else:
# Create or update the object in the database
obj = self.createOrUpdate(rq.get('is_new') == 'True')
# Redirect the user to the appropriate page
if rq.get('buttonOk', None):
# Go to the consult view for this object
obj.plone_utils.addPortalMessage(
obj.translate('Changes saved.', domain='plone'))
urlBack = '%s/skyn/view?phase=%s&pageName=%s' % (
obj.absolute_url(), rq.get('phase'), rq.get('pageName'))
return rq.RESPONSE.redirect(urlBack)
elif rq.get('buttonPrevious', None):
# Go to the edit view (previous page) for this object
rq.set('fieldset', rq.get('previousPage'))
return obj.skyn.edit(obj)
elif rq.get('buttonNext', None):
# Go to the edit view (next page) for this object
rq.set('fieldset', rq.get('nextPage'))
return obj.skyn.edit(obj)
def getAppyType(self, fieldName):
'''Returns the Appy type corresponding to p_fieldName.'''
@ -653,24 +706,6 @@ class AbstractMixin:
updateRolesForPermission('Add portal content', tuple(allCreators),
folder)
def _appy_onEdit(self, created):
'''What happens when an object is created (p_created=True) or edited?'''
# Manage references
self._appy_manageRefs(created)
if self.wrapperClass:
# Get the wrapper first
appyWrapper = self._appy_getWrapper(force=True)
# Call the custom "onEdit" if available
try:
appyWrapper.onEdit(created)
except AttributeError, ae:
pass
# Manage "add" permissions
self._appy_managePermissions()
# Re/unindex object
if self._appy_meta_type == 'tool': self.unindexObject()
else: self.reindexObject()
def _appy_getDisplayList(self, values, labels, domain):
'''Creates a DisplayList given a list of p_values and corresponding
i18n p_labels.'''
@ -759,7 +794,7 @@ class AbstractMixin:
res = self.utranslate(msgId, domain=self.i18nDomain)
return res
def _appy_validateAllFields(self, REQUEST, errors):
def validateAllFields(self, REQUEST, errors):
'''This method is called when individual validation of all fields
succeed (when editing or creating an object). Then, this method
performs inter-field validation. This way, the user must first
@ -851,6 +886,7 @@ class AbstractMixin:
fieldValue = self.REQUEST[requestKey]
sortedRefField = getattr(self, '_appy_%s' % fieldName)
del sortedRefField[:]
if not fieldValue: fieldValue = []
if isinstance(fieldValue, basestring):
fieldValue = [fieldValue]
refObjects = []
@ -874,4 +910,15 @@ class AbstractMixin:
if self.showField(fieldDescr, isEdit=True):
exec 'self.set%s%s([])' % (fieldName[0].upper(),
fieldName[1:])
def getUrl(self):
'''This method returns the URL of the consult view for this object.'''
return self.absolute_url() + '/skyn/view'
def translate(self, label, mapping={}, domain=None, default=None):
'''Translates a given p_label into p_domain with p_mapping.'''
cfg = self.getProductConfig()
if not domain: domain = cfg.PROJECTNAME
return self.translation_service.utranslate(
domain, label, mapping, self, default=default)
# ------------------------------------------------------------------------------

0
gen/plone25/model.py Executable file → Normal file
View file

View file

Before

Width:  |  Height:  |  Size: 899 B

After

Width:  |  Height:  |  Size: 899 B

View file

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 174 B

View file

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 174 B

View file

Before

Width:  |  Height:  |  Size: 244 B

After

Width:  |  Height:  |  Size: 244 B

43
gen/plone25/templates/do.py → gen/plone25/skin/do.py Executable file → Normal file
View file

@ -1,15 +1,25 @@
## Python Script "<!applicationName!>_do.py"
##bind container=container
## Python Script "do.py"
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=actionType
##title=Executes an action
##parameters=action
rq = context.REQUEST
urlBack = rq['HTTP_REFERER']
if actionType == 'appyAction':
if action == 'create':
# A user wants to create an object.
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()
res, msg = obj.executeAppyAction(rq['fieldName'])
if not msg:
@ -18,11 +28,12 @@ if actionType == 'appyAction':
if res:
suffix = 'ok'
label = '%s_action_%s' % (obj.getLabelPrefix(rq['fieldName']), suffix)
msg = context.utranslate(label, domain='<!applicationName!>')
msg = obj.translate(label)
context.plone_utils.addPortalMessage(msg)
elif actionType == 'changeRefOrder':
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:
@ -35,17 +46,19 @@ elif actionType == 'changeRefOrder':
isDelta = False
except ValueError:
context.plone_utils.addPortalMessage(
context.utranslate('ref_invalid_index', domain='<!applicationName!>'))
context.changeAppyRefOrder(rq['fieldName'], rq['objectUid'], move, isDelta)
obj.translate('ref_invalid_index'))
obj.changeAppyRefOrder(rq['fieldName'], rq['objectUid'], move, isDelta)
elif actionType == 'triggerTransition':
elif action == 'triggerTransition':
obj = context.getParentNode()
from Products.CMFPlone import PloneMessageFactory as _
context.portal_workflow.doActionFor(context, rq['workflow_action'],
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.'))
context.plone_utils.addPortalMessage(
_(u'Your content\'s status has been modified.'))
return rq.RESPONSE.redirect(urlBack)

View file

Before

Width:  |  Height:  |  Size: 818 B

After

Width:  |  Height:  |  Size: 818 B

View file

Before

Width:  |  Height:  |  Size: 248 B

After

Width:  |  Height:  |  Size: 248 B

118
gen/plone25/skin/edit.pt Normal file
View file

@ -0,0 +1,118 @@
<tal:block metal:define-macro="master"
define="contextObj python:context.getParentNode();
errors request/errors | python:{};
Iterator python:modules['Products.Archetypes'].IndexIterator;
schematas contextObj/Schemata;
fieldsets python:[key for key in schematas.keys() if (key != 'metadata') and (schematas[key].editableFields(here, visible_only=True))];
default_fieldset python:(not schematas or schematas.has_key('default')) and 'default' or fieldsets[0];
fieldset request/fieldset|options/fieldset|default_fieldset;
fields python:schematas[fieldset].editableFields(here);
dummy python:here.at_isEditable(fields);
portal_type python:here.getPortalTypeName().lower().replace(' ', '_');
type_name here/getPortalTypeName|here/archetype_name;
lockable python:hasattr(here, 'wl_isLocked');
isLocked python:lockable and here.wl_isLocked();
tabindex tabindex|python:Iterator(pos=7000);
isEdit python:True;
tool contextObj/getTool;
flavour python: tool.getFlavour(contextObj);
appFolder tool/getAppFolder;
appName appFolder/id;
css python:here.getUniqueWidgetAttr(fields, 'helper_css');
js python:here.getUniqueWidgetAttr(fields, 'helper_js');
phaseInfo python: contextObj.getAppyPhases(fieldset=fieldset, forPlone=True);
phase request/phase|phaseInfo/name;
pageName python: contextObj.getAppyPage(isEdit, phaseInfo);">
<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 the Standard Plone green tab</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">Archetypes stuff for managing Javascript and CSS.
If I remove this stuff, Javascript popup for dates does not work anyore.</tal:comment>
<metal:javascript_head fill-slot="javascript_head_slot">
<tal:block define="macro here/archetypes_custom_js/macros/javascript_head | nothing"
condition="macro">
<metal:block use-macro="macro" />
</tal:block>
<tal:js condition="js" repeat="item js">
<script type="text/javascript" charset="iso-8859-1"
tal:condition="python:exists('portal/%s' % item)"
tal:attributes="src string:$portal_url/$item">
</script>
</tal:js>
<tal:block define="macro edit_macros/javascript_head | nothing" condition="macro">
<metal:block use-macro="macro" />
</tal:block>
</metal:javascript_head>
<metal:css fill-slot="css_slot">
<tal:css condition="css" repeat="item css">
<style type="text/css" media="all"
tal:condition="python:exists('portal/%s' % item)"
tal:content="structure string:<!-- @import url($portal_url/$item); -->">
</style>
</tal:css>
<tal:block define="macro edit_macros/css | nothing" condition="macro">
<metal:block use-macro="macro" />
</tal:block>
</metal:css>
<body>
<metal:fill fill-slot="main">
<div metal:use-macro="here/skyn/macros/macros/showPagePrologue"/>
<div metal:use-macro="here/skyn/macros/macros/showPageHeader"/>
<form name="edit_form" method="post" enctype="multipart/form-data"
class="enableUnloadProtection atBaseEditForm"
tal:attributes="action python: contextObj.absolute_url()+'/skyn/do'">
<div metal:use-macro="here/skyn/macros/macros/listFields" />
<input type="hidden" name="action" value="edit"/>
<input type="hidden" name="fieldset" tal:attributes="value fieldset"/>
<input type="hidden" name="pageName" tal:attributes="value pageName"/>
<input type="hidden" name="phase" tal:attributes="value phase"/>
<input type="hidden" name="is_new"
tal:attributes="value python: '/portal_factory/' in contextObj.absolute_url()"/>
<tal:comment replace="nothing">Buttons (Previous, Next, Save, etc)</tal:comment>
<metal:block define-slot="buttons"
tal:define="pages phaseInfo/pages;
pageIndex python:pages.index(fieldset);
numberOfPages python:len(pages)">
<tal:previousButton condition="python: pageIndex &gt; 0">
<input class="context" type="submit" name="buttonPrevious"
i18n:attributes="value label_previous;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next;
disabled python:test(isLocked, 'disabled', None);"/>
<input type="hidden" name="previousPage" tal:attributes="value python: pages[pageIndex-1]"/>
</tal:previousButton>
<tal:nextButton condition="python: pageIndex &lt; numberOfPages - 1">
<input class="context" type="submit" name="buttonNext" value="Next"
i18n:attributes="value label_next;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next;
disabled python:test(isLocked, 'disabled', None);"/>
<input type="hidden" name="nextPage" tal:attributes="value python: pages[pageIndex+1]"/>
</tal:nextButton>
<input class="context" type="submit" name="buttonOk"
i18n:attributes="value label_save;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next;
disabled python:test(isLocked, 'disabled', None);"/>
<input class="standalone" type="submit" name="buttonCancel"
i18n:attributes="value label_cancel;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next"/>
</metal:block>
</form>
<div metal:use-macro="here/skyn/macros/macros/showPageFooter"/>
</metal:fill>
</body>
</html>
</tal:block>

View file

@ -1,7 +1,5 @@
<div metal:define-macro="listPodTemplates" i18n:domain="<!applicationName!>" class="appyPod"
tal:define="flavour python: context.<!toolInstanceName!>.getFlavour(context);
podTemplates python: flavour.getAvailablePodTemplates(context, phase);"
tal:condition="podTemplates">
<div metal:define-macro="listPodTemplates" class="appyPod" tal:condition="podTemplates"
tal:define="podTemplates python: flavour.getAvailablePodTemplates(contextObj, phase);">
<script language="javascript">
<!--
// Function that allows to generate a meeting document containing selected items.
@ -16,35 +14,34 @@
<tal:comment replace="nothing">Form submitted when an object needs to be generated as a document.</tal:comment>
<form name="podTemplateForm" method="post"
tal:attributes="action python: context.absolute_url() + '/generateDocument'">
tal:attributes="action python: contextObj.absolute_url() + '/generateDocument'">
<input type="hidden" name="objectUid"/>
<input type="hidden" name="templateUid"/>
</form>
<tal:podTemplates define="maxShownTemplates python: flavour.getMaxShownTemplates(context)">
<tal:podTemplates define="maxShownTemplates python: flavour.getMaxShownTemplates(contextObj)">
<tal:comment replace="nothing">Display templates as links if a few number of templates must be shown</tal:comment>
<span class="discreet" tal:condition="python: len(podTemplates)&lt;=maxShownTemplates"
tal:repeat="podTemplate podTemplates">
<a style="cursor: pointer"
tal:define="podFormat podTemplate/getPodFormat"
tal:attributes="onclick python: 'javascript:generatePodDocument(\'%s\',\'%s\')' % (context.UID(), podTemplate.UID())" >
tal:attributes="onclick python: 'javascript:generatePodDocument(\'%s\',\'%s\')' % (contextObj.UID(), podTemplate.UID())" >
<img tal:attributes="src string: $portal_url/$podFormat.png"/>
<span tal:replace="podTemplate/Title"/>
</a>
&nbsp;</span>
<tal:comment replace="nothing">Display templates as a list if a lot of templates must be shown</tal:comment>
<select tal:condition="python: len(podTemplates)&gt;maxShownTemplates">
<option value="" i18n:translate="">choose_a_doc</option>
<option value="" tal:content="python: tool.translate('choose_a_doc')"></option>
<option tal:repeat="podTemplate podTemplates" tal:content="podTemplate/Title"
tal:attributes="onclick python: 'javascript:generatePodDocument(\'%s\',\'%s\')' % (context.UID(), podTemplate.UID())" />
tal:attributes="onclick python: 'javascript:generatePodDocument(\'%s\',\'%s\')' % (contextObj.UID(), podTemplate.UID())" />
</select>
</tal:podTemplates>
</div>
<metal:editString define-macro="editString" i18n:domain="<!applicationName!>"
tal:define="vocab python:field.Vocabulary(contextObj);">
<label tal:attributes="for fieldName" tal:condition="showLabel" tal:content="label"/>
<metal:editString define-macro="editString" tal:define="vocab python:field.Vocabulary(contextObj)">
<label tal:attributes="for fieldName" tal:condition="showLabel" tal:content="label"/>&nbsp;
<span class="fieldRequired" tal:condition="python: appyType['multiplicity'][0] &gt; 0"></span>
<div class="discreet" tal:content="structure description"/>
<select tal:attributes="name fieldName;
id fieldName;
@ -59,7 +56,7 @@
</select>
</metal:editString>
<metal:editBoolean define-macro="editBoolean" i18n:domain="<!applicationName!>">
<metal:editBoolean define-macro="editBoolean">
<input type="checkbox"
tal:attributes="tabindex tabindex/next;
name python: fieldName + '_visible';
@ -71,57 +68,56 @@
id string:${fieldName}_hidden;
value python: test(contextObj.checkboxChecked(fieldName, value), 'True', 'False')"
type="hidden" />
<span class="fieldRequired" tal:condition="python: appyType['multiplicity'][0] &gt; 0"></span>
<label tal:attributes="for fieldName" tal:condition="showLabel" tal:content="label"/>
<div class="discreet" tal:content="structure description"/>
</metal:editBoolean>
<div metal:define-macro="editField" i18n:domain="<!applicationName!>"
<div metal:define-macro="editField"
tal:define="fieldName field/getName;
isMultiple python:test(appyType['multiplicity'][1]!=1, 'multiple', '');
inError python:test(errors.has_key(fieldName), True, False);
value python:field.getAccessor(contextObj)();
defaultValue python: contextObj.getDefault(fieldName);
label python: contextObj.utranslate(field.widget.label_msgid, domain='<!applicationName!>');
description python: contextObj.utranslate(field.widget.description_msgid, domain='<!applicationName!>')"
defaultValue python: contextObj.getDefault(fieldName)"
tal:attributes="class python:'field ' + test(inError, ' error', '')">
<span class="fieldRequired" tal:condition="python: appyType['multiplicity'][0]>0"></span>
<div tal:condition="inError" tal:content="python: errors[fieldName]"></div>
<tal:stringField condition="python: appyType['type'] == 'String'">
<metal:edit use-macro="here/<!macros!>/macros/editString"/>
<metal:edit use-macro="here/skyn/macros/macros/editString"/>
</tal:stringField>
<tal:booleanField condition="python: appyType['type'] == 'Boolean'">
<metal:edit use-macro="here/<!macros!>/macros/editBoolean"/>
<metal:edit use-macro="here/skyn/macros/macros/editBoolean"/>
</tal:booleanField>
</div>
<div metal:define-macro="showComputedField" i18n:domain="<!applicationName!>">
<span class="appyLabel" tal:condition="showLabel"
tal:content="field/widget/label_msgid" i18n:translate=""></span>
<div metal:define-macro="showComputedField">
<span class="appyLabel" tal:condition="showLabel" tal:content="label"></span>
<tal:showValue define="theValue python: contextObj.getComputedValue(appyType)">
<span tal:condition="appyType/plainText" tal:replace="theValue"/>
<span tal:condition="not: appyType/plainText" tal:replace="structure theValue"/>
</tal:showValue>
</div>
<div metal:define-macro="showInfoField" i18n:domain="<!applicationName!>">
<span class="appyLabel" tal:content="field/widget/label_msgid" i18n:translate=""></span>
<span tal:content="field/widget/description_msgid" i18n:translate=""></span>
<div metal:define-macro="showInfoField">
<span class="appyLabel" tal:content="label"></span>
<span tal:content="structure description"></span>
</div>
<div metal:define-macro="showActionField" i18n:domain="<!applicationName!>">
<form name="executeAppyAction" action="<!applicationName!>_do" method="POST">
<div metal:define-macro="showActionField">
<form name="executeAppyAction" action="skyn/do" method="POST">
<input type="hidden" name="actionType" value="appyAction"/>
<input type="hidden" name="objectUid" tal:attributes="value contextObj/UID"/>
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
<input type="submit" name="do" i18n:attributes="value"
tal:attributes="value field/widget/label_msgid"/>
<input type="submit" name="do" tal:attributes="value label"/>
</form>
</div>
<div metal:define-macro="showArchetypesField" i18n:domain="<!applicationName!>"
<div metal:define-macro="showArchetypesField"
tal:define="field fieldDescr/atField|widgetDescr/atField;
appyType fieldDescr/appyType|widgetDescr/appyType;
showLabel showLabel|python:True;"
showLabel showLabel|python:True;
label python: tool.translate(field.widget.label_msgid);
descrId field/widget/description_msgid|python:'';
description python: tool.translate(descrId)"
tal:attributes="class python: contextObj.getCssClasses(appyType, asSlave=True)">
<tal:comment replace="nothing">For some fields we simply use the standard Archetypes
@ -137,18 +133,18 @@
<tal:viewField tal:condition="not: isEdit">
<tal:defField>
<tal:fileField condition="python: (appyType['type'] == 'File')">
<span tal:condition="showLabel" tal:content="field/widget/label_msgid" i18n:translate=""></span>
<span tal:condition="showLabel" tal:content="label"></span>
<metal:viewField use-macro="python: contextObj.widget(field.getName(), 'view', use_label=0)"/>
</tal:fileField>
<tal:simpleField condition="python: (appyType['type'] in ('Integer', 'Float', 'Date', 'Boolean')) or (appyType['type'] == 'String' and (appyType['format'] == 0))">
<span tal:condition="showLabel" tal:content="field/widget/label_msgid" i18n:translate=""
<span tal:condition="showLabel" tal:content="label"
tal:attributes="class python: 'appyLabel ' + contextObj.getCssClasses(appyType, asSlave=False);
id python: field.getAccessor(contextObj)()"></span>
<metal:viewField use-macro="python: contextObj.widget(field.getName(), 'view', use_label=0)"/>
</tal:simpleField>
<tal:formattedString condition="python: (appyType['type'] == 'String' and (appyType['format'] != 0))">
<fieldset tal:define="value python:field.getAccessor(contextObj)()">
<legend tal:condition="showLabel" i18n:translate="" tal:content="field/widget/label_msgid"></legend>
<legend tal:condition="showLabel" tal:content="label"></legend>
<span tal:condition="python: appyType['format'] == 1"
tal:replace="structure python: value.replace('\n', '&lt;br&gt;')"/>
<span tal:condition="python: appyType['format'] == 2" tal:replace="structure value"/>
@ -163,59 +159,58 @@
<tal:ref define="isBack python:False;
fieldRel python:field.relationship;
objs python:contextObj.getAppyRefs(field.getName());
labelMsgId field/widget/label_msgid;
descrMsgId field/widget/description_msgid;
innerRef innerRef|python:False">
<metal:viewRef use-macro="here/<!applicationName!>AppyReference/macros/showReference" />
<metal:viewRef use-macro="here/skyn/ref/macros/showReference" />
</tal:ref>
</tal:viewRef>
<tal:editRef condition="python: isEdit and (appyType['type'] == 'Ref')">
<tal:ref define="appyType fieldDescr/appyType|widgetDescr/appyType"
condition="python: appyType['link']==True">
<metal:editRef use-macro="here/<!applicationName!>AppyReference/macros/editReference" />
<metal:editRef use-macro="here/skyn/ref/macros/editReference" />
</tal:ref>
</tal:editRef>
<tal:computedField condition="python: (not isEdit) and (appyType['type'] == 'Computed')">
<metal:cf use-macro="here/<!macros!>/macros/showComputedField" />
<metal:cf use-macro="here/skyn/macros/macros/showComputedField" />
</tal:computedField>
<tal:actionField condition="python: (not isEdit) and (appyType['type'] == 'Action')">
<metal:af use-macro="here/<!macros!>/macros/showActionField" />
<metal:af use-macro="here/skyn/macros/macros/showActionField" />
</tal:actionField>
<tal:masterString condition="python: isEdit and (appyType['type'] in ('String', 'Boolean')) and (appyType['slaves'])">
<metal:mf use-macro="here/<!macros!>/macros/editField" />
<metal:mf use-macro="here/skyn/macros/macros/editField" />
</tal:masterString>
<tal:infoField condition="python: (not isEdit) and (appyType['type'] == 'Info')">
<metal:af use-macro="here/<!macros!>/macros/showInfoField" />
<metal:af use-macro="here/skyn/macros/macros/showInfoField" />
</tal:infoField>
</div>
<div metal:define-macro="showBackwardField" i18n:domain="<!applicationName!>"
<div metal:define-macro="showBackwardField"
tal:define="isBack python:True;
appyType widgetDescr/appyType;
fieldRel widgetDescr/fieldRel;
objs python:contextObj.getBRefs(fieldRel);
labelMsgId python:'%s_%s_back' % (contextObj.meta_type, appyType['backd']['attribute']);
descrMsgId python:'';
label python:contextObj.translate('%s_%s_back' % (contextObj.meta_type, appyType['backd']['attribute']));
description python:'';
innerRef innerRef|python:False">
<div metal:use-macro="here/<!applicationName!>AppyReference/macros/showReference" />
<div metal:use-macro="here/skyn/ref/macros/showReference" />
</div>
<span metal:define-macro="showGroup" i18n:domain="<!applicationName!>">
<span metal:define-macro="showGroup">
<fieldset class="appyGroup">
<legend><i i18n:translate=""
tal:content="python: '%s_group_%s' % (contextObj.meta_type, widgetDescr['name'])"></i></legend>
<legend><i tal:define="groupDescription python:contextObj.translate('%s_group_%s' % (contextObj.meta_type, widgetDescr['name']))"
tal:content="groupDescription"></i></legend>
<table tal:define="global fieldNb python:-1" width="100%">
<tr valign="top" tal:repeat="rowNb python:range(widgetDescr['rows'])">
<td tal:repeat="colNb python:range(widgetDescr['cols'])" tal:attributes="width python: str(100.0/widgetDescr['cols']) + '%'">
<td tal:repeat="colNb python:range(widgetDescr['cols'])"
tal:attributes="width python: str(100.0/widgetDescr['cols']) + '%'">
<tal:showField define="global fieldNb python:fieldNb+1;
hasFieldDescr python: test(fieldNb < len(widgetDescr['fields']), True, False);"
tal:condition="hasFieldDescr">
<tal:field define="fieldDescr python:widgetDescr['fields'][fieldNb]">
<tal:archetypesField condition="python: fieldDescr['widgetType'] == 'field'">
<metal:atField use-macro="here/<!macros!>/macros/showArchetypesField"/>
<metal:atField use-macro="here/skyn/macros/macros/showArchetypesField"/>
</tal:archetypesField>
<tal:backwardRef tal:condition="python: (not isEdit) and (fieldDescr['widgetType'] == 'backField')">
<metal:backRef use-macro="here/<!macros!>/macros/showBackwardField" />
<metal:backRef use-macro="here/skyn/macros/macros/showBackwardField" />
</tal:backwardRef>
</tal:field>
</tal:showField>
@ -226,33 +221,33 @@
<br/>
</span>
<div metal:define-macro="listFields" i18n:domain="<!applicationName!>"
<div metal:define-macro="listFields"
tal:repeat="widgetDescr python: contextObj.getAppyFields(isEdit, pageName)">
<tal:displayArchetypesField condition="python: widgetDescr['widgetType'] == 'field'">
<tal:atField condition="python: widgetDescr['page'] == pageName">
<metal:field use-macro="here/<!macros!>/macros/showArchetypesField" />
<metal:field use-macro="here/skyn/macros/macros/showArchetypesField" />
</tal:atField>
</tal:displayArchetypesField>
<tal:displayBackwardRef condition="python: (not isEdit) and (widgetDescr['widgetType'] == 'backField')">
<tal:backRef condition="python: widgetDescr['appyType']['backd']['page'] == pageName">
<metal:field metal:use-macro="here/<!macros!>/macros/showBackwardField" />
<metal:field metal:use-macro="here/skyn/macros/macros/showBackwardField" />
</tal:backRef>
</tal:displayBackwardRef>
<tal:displayGroup condition="python: widgetDescr['widgetType'] == 'group'">
<tal:displayG condition="python: widgetDescr['page'] == pageName">
<metal:group metal:use-macro="here/<!macros!>/macros/showGroup" />
<metal:group metal:use-macro="here/skyn/macros/macros/showGroup" />
</tal:displayG>
</tal:displayGroup>
</div>
<span metal:define-macro="byline" i18n:domain="<!applicationName!>"
<span metal:define-macro="byline"
tal:condition="python: site_properties.allowAnonymousViewAbout or not isAnon"
tal:define="creator here/Creator;" class="documentByLine">
<tal:name tal:condition="creator"
tal:define="author python:context.portal_membership.getMemberInfo(creator)">
tal:define="author python:contextObj.portal_membership.getMemberInfo(creator)">
<span class="documentAuthor" i18n:domain="plone" i18n:translate="label_by_author">
by <a tal:attributes="href string:${portal_url}/author/${creator}"
tal:content="python:author and author['fullname'] or creator"
@ -266,13 +261,13 @@
</span>
</span>
<span metal:define-macro="workflowHistory" i18n:domain="<!applicationName!>" class="reviewHistory"
tal:define="history context/getWorkflowHistory" tal:condition="history">
<span metal:define-macro="workflowHistory" class="reviewHistory"
tal:define="history contextObj/getWorkflowHistory" tal:condition="history">
<dl id="history" class="collapsible inline collapsedOnLoad">
<dt class="collapsibleHeader" i18n:translate="label_history" i18n:domain="plone">History</dt>
<dd class="collapsibleContent">
<table width="100%" class="listing nosort" i18n:attributes="summary summary_review_history"
tal:define="review_history python:context.portal_workflow.getInfoFor(context, 'review_history', []);
tal:define="review_history python:contextObj.portal_workflow.getInfoFor(contextObj, 'review_history', []);
review_history python:[review for review in review_history if review.get('action','')]"
tal:condition="review_history">
<tr i18n:domain="plone">
@ -287,10 +282,10 @@
rhComments items/comments|nothing;
state items/review_state|nothing"
tal:attributes="class python:test(odd, 'even', 'odd')" tal:condition="items/action">
<td i18n:translate="" tal:content="python: context.getWorkflowLabel(items['action'])"
<td tal:content="python: tool.translate(contextObj.getWorkflowLabel(items['action']))"
tal:attributes="class string:state-${state}"/>
<td tal:define="actorid python:items.get('actor');
actor python:context.portal_membership.getMemberInfo(actorid);
actor python:contextObj.portal_membership.getMemberInfo(actorid);
fullname actor/fullname|nothing;
username actor/username|nothing"
tal:content="python:fullname or username or actorid"/>
@ -305,7 +300,7 @@
</dl>
</span>
<div metal:define-macro="showPagePrologue" i18n:domain="<!applicationName!>">
<div metal:define-macro="showPagePrologue">
<tal:comment replace="nothing">Global Javascript functions, used in edit and
consult views, are defined gere.</tal:comment>
@ -357,55 +352,55 @@
</script>
</div>
<div metal:define-macro="showPageHeader" i18n:domain="<!applicationName!>"
tal:define="appyPages python: context.getAppyPages(phase);
<div metal:define-macro="showPageHeader"
tal:define="appyPages python: contextObj.getAppyPages(phase);
showCommonInfo python: not isEdit"
tal:condition="python: not context.portal_factory.isTemporary(context)">
tal:condition="python: not contextObj.portal_factory.isTemporary(contextObj)">
<tal:comment replace="nothing">Information that is common to all tabs (object title, state, etc)</tal:comment>
<table width="100%" tal:condition="showCommonInfo" class="appyCommonInfo">
<tr valign="bottom">
<tal:comment replace="nothing">Title, edit icon and state</tal:comment>
<td width="80%">
<b class="appyTitle" tal:content="title_string | here/title_or_id"></b>
<b class="appyTitle" tal:content="contextObj/title_or_id"></b>
<tal:comment replace="nothing">Show the phase name tied to this page</tal:comment>
<span class="discreet" tal:condition="python: phaseInfo['totalNbOfPhases']&gt;1">&minus;
<span i18n:translate="phase"></span>:
<span tal:define="label python:'%s_phase_%s' % (context.meta_type, phase)"
tal:content="label" i18n:translate=""></span>
<span tal:replace="python:contextObj.translate('phase')"/>:
<span tal:replace="python:tool.translate('%s_phase_%s' % (contextObj.meta_type, phase))"/>
</span>
<tal:comment replace="nothing">When no tabs are shown, we provide an edit icon.</tal:comment>
<img tal:define="editPageName python:test(pageName=='main', 'default', pageName)"
src="edit.gif" title="Edit" i18n:domain="plone" i18n:attributes="title"
style="cursor:pointer"
tal:attributes="onClick python: 'href: window.location=\'%s/<!applicationName!>_appy_edit?fieldset=%s&phase=%s\'' % (context.absolute_url(), editPageName, phase)"
tal:condition="python: (len(appyPages)==1) and member.has_permission('Modify portal content', context)"/>
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/edit?fieldset=%s&phase=%s\'' % (contextObj.absolute_url(), editPageName, phase)"
tal:condition="python: (len(appyPages)==1) and member.has_permission('Modify portal content', contextObj)"/>
</td>
<td><metal:actions use-macro="here/document_actions/macros/document_actions"/>
</td>
</tr>
<tr tal:define="descrLabel python: here.utranslate('%s_edit_descr' % here.portal_type, domain='<!applicationName!>')" tal:condition="descrLabel/strip" >
<tr tal:define="descrLabel python: contextObj.translate('%s_edit_descr' % contextObj.portal_type)"
tal:condition="descrLabel" >
<tal:comment replace="nothing">Content type description</tal:comment>
<td colspan="2" class="discreet" tal:content="descrLabel"/>
</tr>
<tr>
<td>
<metal:byLine use-macro="here/<!macros!>/macros/byline"/>
<metal:byLine use-macro="here/skyn/macros/macros/byline"/>
<tal:showWorkflow condition="showWorkflow">
<metal:workflowHistory use-macro="here/<!macros!>/macros/workflowHistory"/>
<metal:workflowHistory use-macro="here/skyn/macros/macros/workflowHistory"/>
</tal:showWorkflow>
</td>
<td valign="top"><metal:pod use-macro="here/<!macros!>/macros/listPodTemplates"/>
<td valign="top"><metal:pod use-macro="here/skyn/macros/macros/listPodTemplates"/>
</td>
</tr>
<tal:comment replace="nothing">Workflow-related information and actions</tal:comment>
<tr tal:condition="python: showWorkflow and context.getWorkflowLabel()">
<tr tal:condition="python: showWorkflow and contextObj.getWorkflowLabel()">
<td colspan="2" class="appyWorkflow">
<table width="100%">
<tr>
<td><metal:states use-macro="here/<!macros!>/macros/states"/></td>
<td align="right"><metal:states use-macro="here/<!macros!>/macros/transitions"/></td>
<td><metal:states use-macro="here/skyn/macros/macros/states"/></td>
<td align="right"><metal:states use-macro="here/skyn/macros/macros/transitions"/></td>
</tr>
</table>
</td>
@ -413,24 +408,24 @@
</table>
<tal:comment replace="nothing">Tabs</tal:comment>
<ul class="contentViews appyTabs" tal:condition="python: len(appyPages)>1">
<ul class="contentViews appyTabs" tal:condition="python: len(appyPages)&gt;1">
<li tal:repeat="thePage appyPages"
tal:attributes="class python:test(thePage == pageName, 'selected', 'plain')">
<tal:tab define="pageLabel python: '%s_page_%s' % (here.meta_type, thePage)">
<a i18n:translate="" tal:content="pageLabel"
tal:attributes="href python: here.absolute_url() + '/<!applicationName!>_appy_view?phase=%s&pageName=%s' % (phase, thePage)">
<tal:tab define="pageLabel python: tool.translate('%s_page_%s' % (contextObj.meta_type, thePage))">
<a tal:content="pageLabel"
tal:attributes="href python: contextObj.absolute_url() + '/skyn/view?phase=%s&pageName=%s' % (phase, thePage)">
</a>
<img tal:define="editPageName python:test(thePage=='main', 'default', thePage)"
src="edit.gif" title="Edit" i18n:domain="plone" i18n:attributes="title"
style="cursor:pointer" class="appyPlusImg"
tal:attributes="onClick python: 'href: window.location=\'%s/<!applicationName!>_appy_edit?fieldset=%s&phase=%s\'' % (context.absolute_url(), editPageName, phase)"
tal:condition="python: member.has_permission('Modify portal content', context)"/>
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/edit?fieldset=%s&phase=%s\'' % (contextObj.absolute_url(), editPageName, phase)"
tal:condition="python: member.has_permission('Modify portal content', contextObj)"/>
</tal:tab>
</li>
</ul>
</div>
<div metal:define-macro="showPageFooter" i18n:domain="<!applicationName!>">
<div metal:define-macro="showPageFooter">
<script language="javascript">
<!--
// When the current page is loaded, we must set the correct state for all slave fields.
@ -469,7 +464,7 @@
</script>
</div>
<div metal:define-macro="queryResult" i18n:domain="<!applicationName!>">
<div metal:define-macro="queryResult">
<script language="javascript">
<!--
@ -592,11 +587,11 @@
</script>
<table class="vertical listing" width="100%"
tal:define="fieldDescrs python: context.<!toolInstanceName!>.getResultColumns(queryResult[0].getObject(), queryName);">
tal:define="fieldDescrs python: tool.getResultColumns(queryResult[0].getObject(), queryName);">
<tal:comment replace="nothing">Every item in fieldDescr is a FieldDescr instance,
excepted for workflow state (which is not a field): in thi case it is simply string
"workflowState".</tal:comment>
excepted for workflow state (which is not a field): in this case it is simply the
string "workflowState".</tal:comment>
<tal:comment replace="nothing">Headers, with filters and sort arrows</tal:comment>
<tr>
@ -604,7 +599,7 @@
<th><img tal:attributes= "src string: $portal_url/arrowDown.gif;
onClick python:'javascript:onSort(\'title\')';"
id="arrow_title" style="cursor:pointer"/>
<span i18n:translate="ref_name"/>
<span tal:content="python: tool.translate('ref_name')"/>
<input id="filter_title" type="text" size="10" onkeyup="javascript:onTextEntered('title')"/>
</th>
@ -617,11 +612,11 @@
style="cursor:pointer"/>
<tal:comment replace="nothing">Display header for a "standard" field</tal:comment>
<tal:standardField condition="python: fieldName != 'workflow_state'">
<span i18n:translate="" tal:content="fieldDescr/atField/widget/label_msgid"/>
<span tal:replace="python: tool.translate(fieldDescr['atField'].widget.label_msgid)"/>
</tal:standardField>
<tal:comment replace="nothing">Display header for the workflow state</tal:comment>
<tal:workflowState condition="python: fieldName == 'workflow_state'">
<span i18n:translate="workflow_state"/>
<span tal:replace="python: tool.translate('workflow_state')"/>
</tal:workflowState>
<input type="text" size="10"
tal:attributes="id python: 'filter_%s' % fieldName;
@ -634,13 +629,13 @@
tal:attributes= "src string: $portal_url/arrowDown.gif;
onClick python:'javascript:onSort(\'root_type\')';"
id = "arrow_root_type" style="cursor:pointer"/>
<span i18n:translate="root_type"/>
<span tal:replace="python: tool.translate('root_type')"/>
<input type="text" size="10" id="filter_root_type"
tal:attributes="onkeyup python:'javascript:onTextEntered(\'root_type\')'"/>
</th>
<tal:comment replace="nothing">Column "Actions"</tal:comment>
<th i18n:translate="ref_actions"></th>
<th tal:content="python: tool.translate('ref_actions')"></th>
</tr>
<tal:comment replace="nothing">Results</tal:comment>
@ -648,8 +643,7 @@
<tal:row define="obj brain/getObject">
<tal:comment replace="nothing">Mandatory column "Title"/"Name"</tal:comment>
<td id="field_title"><a tal:content="brain/Title"
tal:attributes="href python: obj.absolute_url()"></a></td>
<td id="field_title"><a tal:content="brain/Title" tal:attributes="href obj/getUrl"></a></td>
<tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
<tal:otherFields repeat="fieldDescr fieldDescrs">
@ -661,7 +655,7 @@
showLabel python:False;
innerRef python:True"
condition="python: contextObj.showField(fieldDescr)">
<metal:field use-macro="here/<!macros!>/macros/showArchetypesField"/>
<metal:field use-macro="here/skyn/macros/macros/showArchetypesField"/>
</tal:field>
</td>
<td tal:condition="not: fieldDescr/atField" style="color:red">Field
@ -669,20 +663,20 @@
</td>
</tal:standardField>
<tal:workflowState condition="python: fieldDescr == 'workflowState'">
<td id="field_workflow_state" i18n:translate="" tal:content="obj/getWorkflowLabel"></td>
<td id="field_workflow_state" tal:content="python: tool.translate(obj.getWorkflowLabel())"></td>
</tal:workflowState>
</tal:otherFields>
<tal:comment replace="nothing">Column "Object type", shown if we are on tab "consult all"</tal:comment>
<td tal:condition="mainTabSelected" tal:content="obj/portal_type"
i18n:translate="" id="field_root_type"></td>
<td tal:condition="mainTabSelected" id="field_root_type"
tal:content="python: tool.translate(obj.portal_type)"></td>
<tal:comment replace="nothing">Column "Actions"</tal:comment>
<td align="right">
<table class="no-style-table" cellpadding="0" cellspacing="0">
<tr>
<tal:comment replace="nothing">Edit the element</tal:comment>
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/edit'"
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/skyn/edit'"
tal:condition="python: member.has_permission('Modify portal content', obj)">
<img src="edit.gif" title="Edit" i18n:domain="plone" i18n:attributes="title" />
</a></td>
@ -701,69 +695,96 @@
<div metal:use-macro="context/batch_macros/macros/navigation" />
</div>
<metal:phases define-macro="phases" i18n:domain="<!applicationName!>">
<metal:phases define-macro="phases">
<tal:comment replace="nothing">This macro displays phases defined for a given content type,
only if more than one phase is defined.</tal:comment>
<table width="100%" tal:define="phases context/getAppyPhases|nothing"
tal:condition="python: phases and (len(phases)>1)" cellspacing="1" cellpadding="0">
<table width="100%" tal:define="phases contextObj/getAppyPhases|nothing"
tal:condition="python: phases and (len(phases)&gt;1)" cellspacing="1" cellpadding="0">
<tal:phase repeat="phase phases">
<tr>
<td tal:define="label python:'%s_phase_%s' % (context.meta_type, phase['name']);
displayLink python: (phase['phaseStatus'] != 'Future') and ('/portal_factory' not in context.absolute_url())"
<td tal:define="label python:'%s_phase_%s' % (contextObj.meta_type, phase['name']);
displayLink python: (phase['phaseStatus'] != 'Future') and ('/portal_factory' not in contextObj.absolute_url())"
tal:attributes="class python: 'appyPhase step' + phase['phaseStatus']">
<a tal:attributes="href python: '%s?phase=%s&pageName=%s' % (context.absolute_url(), phase['name'], phase['pages'][0]);" tal:condition="displayLink"
i18n:translate="" tal:content="label"/>
<span tal:condition="not: displayLink" i18n:translate="" tal:content="label"/>
<a tal:attributes="href python: '%s?phase=%s&pageName=%s' % (contextObj.getUrl(), phase['name'], phase['pages'][0]);" tal:condition="displayLink"
tal:content="python: tool.translate(label)"/>
<span tal:condition="not: displayLink" tal:content="python: tool.translate(label)"/>
</td>
</tr>
<tr tal:condition="python: phase['name'] != phases[-1]['name']">
<td align="center"><img tal:attributes="src string: $portal_url/nextPhase.png"/></td>
<td align="center"><img tal:attributes="src string: $portal_url/skyn/nextPhase.png"/></td>
</tr>
</tal:phase>
</table>
</metal:phases>
<metal:states define-macro="states" i18n:domain="<!applicationName!>"
<metal:states define-macro="states"
tal:define="showAllStatesInPhase python: flavour.getAttr('showAllStatesInPhaseFor' + contextObj.meta_type);
states python: context.getAppyStates(phase, currentOnly=not showAllStatesInPhase)"
states python: contextObj.getAppyStates(phase, currentOnly=not showAllStatesInPhase)"
tal:condition="python: test(showAllStatesInPhase, len(states)&gt;1, True)">
<table>
<tr>
<tal:state repeat="stateInfo states">
<td tal:attributes="class python: 'appyState step' + stateInfo['stateStatus']"
tal:content="python: context.getWorkflowLabel(stateInfo['name'])" i18n:translate="">
tal:content="python: tool.translate(contextObj.getWorkflowLabel(stateInfo['name']))">
</td>
<td tal:condition="python: stateInfo['name'] != states[-1]['name']">
<img tal:attributes="src string: $portal_url/nextState.png"/>
<img tal:attributes="src string: $portal_url/skyn/nextState.png"/>
</td>
</tal:state>
</tr>
</table>
</metal:states>
<metal:transitions define-macro="transitions" i18n:domain="<!applicationName!>"
<metal:transitions define-macro="transitions"
tal:define="transitions python: contextObj.portal_workflow.getTransitionsFor(contextObj);"
tal:condition="transitions">
<form id="triggerTransitionForm" method="post"
tal:attributes="action python: contextObj.absolute_url() + '/<!applicationName!>_do'">
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'">
<input type="hidden" name="actionType" value="triggerTransition"/>
<input type="hidden" name="workflow_action"/>
<table>
<tr>
<tal:comment replace="nothing">Input field allowing to enter a comment before triggering a transition</tal:comment>
<td tal:define="showCommentsField python:flavour.getAttr('showWorkflowCommentFieldFor'+context.meta_type)"
<td tal:define="showCommentsField python:flavour.getAttr('showWorkflowCommentFieldFor'+contextObj.meta_type)"
align="right" tal:condition="showCommentsField">
<span i18n:translate="workflow_comment" class="discreet"></span>
<span tal:content="python: tool.translate('workflow_comment')" class="discreet"></span>
<input type="text" id="comment" name="comment" size="35"/>
</td>
<tal:comment replace="nothing">Buttons for triggering transitions</tal:comment>
<td align="right" tal:repeat="transition transitions">
<input type="button" i18n:attributes="value" class="context"
tal:attributes="value python: transition['name'];
onClick python: 'javascript: triggerTransition(\'%s\')' % transition['id']"/>
<input type="button" class="context"
tal:attributes="value python: tool.translate(transition['name']);
onClick python: 'javascript: triggerTransition(\'%s\')' % transition['id'];"/>
</td>
</tr>
</table>
</form>
</metal:transitions>
<metal:portletContent define-macro="portletContent">
<tal:comment replace="nothing">Portlet title, with link to tool.</tal:comment>
<dt class="portletHeader">
<span tal:replace="python: tool.translate(appName)"/>&nbsp;
<img style="cursor:pointer"
tal:condition="python: member.has_role('Manager')"
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/view\'' % tool.absolute_url();
title python: tool.translate('%sTool' % appName);
src string:$portal_url/skyn/appyConfig.gif"/>
</dt>
<tal:comment replace="nothing">Links to flavours</tal:comment>
<dt class="portletAppyItem" tal:repeat="flavourInfo tool/getFlavoursInfo">
<a tal:define="flavourNumber flavourInfo/number;
rootTypes python: test(flavourNumber==1, rootClasses, ['%s_%s' % (rc, flavourNumber) for rc in rootClasses]);
rootClassesQuery python:','.join(rootTypes)"
tal:content="flavourInfo/title"
tal:attributes="title python: tool.translate('query_consult_all');
href python:'%s/skyn/query?query=%s&flavourNumber=%d' % (appFolder.absolute_url(), rootClassesQuery, flavourNumber)"></a>
</dt>
<dt class="portletAppyItem" tal:define="contextObj tool/getPublishedObject"
tal:condition="python: contextObj.meta_type in rootClasses">
<metal:phases use-macro="here/skyn/macros/macros/phases"/>
</dt>
</metal:portletContent>

View file

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

View file

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 192 B

View file

Before

Width:  |  Height:  |  Size: 754 B

After

Width:  |  Height:  |  Size: 754 B

View file

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 228 B

View file

Before

Width:  |  Height:  |  Size: 225 B

After

Width:  |  Height:  |  Size: 225 B

64
gen/plone25/skin/query.pt Normal file
View file

@ -0,0 +1,64 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
metal:use-macro="here/main_template/macros/master">
<tal:comment replace="nothing">This page presents results of queries</tal:comment>
<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>
<div metal:fill-slot="main"
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">
<span tal:condition="python: queryName and (queryName != 'none')">
<span tal:define="queryResult python: tool.executeQuery(queryName, int(flavourNumber));
batch queryResult">
<tal:comment replace="nothing">Tabs</tal:comment>
<ul class="contentViews appyTabs">
<tal:comment replace="nothing">Tab "All objects"</tal:comment>
<li tal:define="selected python:mainTabSelected"
tal:attributes="class python:test(selected, 'selected', 'plain')"
tal:condition="python: len(rootClasses)>1">
<a tal:content="python: tool.translate('query_consult_all')"
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootClassesQuery, flavourNumber)"></a>
</li>
<tal:comment replace="nothing">One tab for each root content type</tal:comment>
<tal:tab repeat="rootContentType rootTypes">
<li tal:define="selected python:queryName == 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)"/>
<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>
<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>
</html>

View file

@ -1,22 +1,22 @@
<tal:comment replace="nothing"> We begin with some sub-macros used within
macro "showReference" defined below.</tal:comment>
<metal:objectTitle define-macro="objectTitle" i18n:domain="<!applicationName!>">
<metal:objectTitle define-macro="objectTitle">
<tal:comment replace="nothing">Displays the title of a referenced object, with a link on
it to reach the consult view for this object. If we are on a back reference, the link
allows to reach the correct page where the forward reference is defined.</tal:comment>
<a tal:define="viewUrl obj/absolute_url;
<a tal:define="viewUrl obj/getUrl;
fullUrl python: test(isBack, viewUrl + '/?pageName=%s&phase=%s' % (appyType['page'], appyType['phase']), viewUrl)"
tal:attributes="href fullUrl" tal:content="obj/Title"></a>
</metal:objectTitle>
<metal:objectActions define-macro="objectActions" i18n:domain="<!applicationName!>">
<metal:objectActions define-macro="objectActions">
<tal:comment replace="nothing">Displays icons for triggering actions on a given
referenced object (edit, delete, etc).</tal:comment>
<table class="no-style-table" cellpadding="0" cellspacing="0">
<tr>
<tal:comment replace="nothing">Edit the element</tal:comment>
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/edit'"
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/skyn/edit'"
tal:condition="python: member.has_permission('Modify portal content', obj)">
<img src="edit.gif" title="label_edit" i18n:domain="plone" i18n:attributes="title" />
</a></td>
@ -28,20 +28,22 @@
<tal:comment replace="nothing">Arrows for moving objects up or down</tal:comment>
<td class="noPadding" tal:condition="python: len(objs)>1">
<form tal:condition="python: member.has_permission('Modify portal content', obj)"
tal:attributes="action python: contextObj.absolute_url() + '/<!applicationName!>_do'"
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'"
tal:define="objectIndex python:contextObj.getAppyRefIndex(field.getName(), obj)">
<input type="hidden" name="actionType" value="changeRefOrder"/>
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
<input type="hidden" name="objectUid" tal:attributes="value obj/UID"/>
<tal:comment replace="nothing">Arrow up</tal:comment>
<span tal:condition="python: objectIndex > 0">
<input type="image" name="moveUp" tal:attributes="src python: contextObj.absolute_url() + '/arrowUp.png'"
title="move_up" i18n:attributes="title" class="imageInput"/>
<span tal:condition="python: objectIndex &gt; 0">
<input type="image" name="moveUp" class="imageInput"
tal:attributes="src string: $portal_url/skyn/arrowUp.png;
title python: tool.translate('move_up')"/>
</span>
<tal:comment replace="nothing">Arrow down</tal:comment>
<span tal:condition="python: objectIndex < (len(objs)-1)">
<input type="image" name="moveDown" tal:attributes="src python: contextObj.absolute_url() + '/arrowDown.png'"
title="move_down" i18n:attributes="title" class="imageInput"/>
<span tal:condition="python: objectIndex &lt; (len(objs)-1)">
<input type="image" name="moveDown" class="imageInput"
tal:attributes="src string: $portal_url/skyn/arrowDown.png;
title python: tool.translate('move_down')"/>
</span>
</form>
</td>
@ -49,25 +51,25 @@
</table>
</metal:objectActions>
<metal:plusIcon define-macro="plusIcon" i18n:domain="<!applicationName!>">
<metal:plusIcon define-macro="plusIcon">
<tal:comment replace="nothing">Displays the "plus" icon that allows to add new object
through a reference widget. Indeed, If field was declared as "addable", we must provide
an icon for creating a new linked object (at least if multiplicities allow it).</tal:comment>
<img src="plus.png" i18n:attributes="title" style="cursor:pointer"
tal:condition="showPlusIcon" title="add_ref"
tal:attributes="onClick python: 'href: window.location=\'%s/createAppyObject?initiator=%s&field=%s&type_name=%s\'' % (folder.absolute_url(), contextObj.UID(), field.getName(), linkedPortalType)"/>
<img style="cursor:pointer" tal:condition="showPlusIcon"
tal:attributes="src string:$portal_url/skyn/plus.png;
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)"/>
</metal:plusIcon>
<div metal:define-macro="showReference" i18n:domain="<!applicationName!>"
tal:define="tool python: contextObj.<!toolInstanceName!>;
<div metal:define-macro="showReference"
tal:define="folder python: test(contextObj.isPrincipiaFolderish, contextObj, contextObj.getParentNode());
flavour python:tool.getFlavour(contextObj);
folder python: test(contextObj.isPrincipiaFolderish, contextObj, contextObj.getParentNode());
linkedPortalType python:flavour.getPortalType(appyType['klass']);
addPermission python: '<!applicationName!>: Add %s' % linkedPortalType;
addPermission python: '%s: Add %s' % (appName, linkedPortalType);
multiplicity python:test(isBack, appyType['backd']['multiplicity'], appyType['multiplicity']);
maxReached python:(multiplicity[1] != None) and (len(objs) >= multiplicity[1]);
showPlusIcon python:not isBack and appyType['add'] and not maxReached and member.has_permission(addPermission, folder);
atMostOneRef python: (multiplicity[1] == 1) and (len(objs)<=1)">
atMostOneRef python: (multiplicity[1] == 1) and (len(objs)&lt;=1)">
<tal:comment replace="nothing">This macro displays the Reference widget on a "consult" page.
@ -79,21 +81,20 @@
<tal:comment replace="nothing">Display a simplified widget if maximum number of
referenced objects is 1.</tal:comment>
<table class="no-style-table" cellpadding="0" cellspacing="0"><tr valign="top">
<td><span class="appyLabel" tal:condition="not: innerRef"
i18n:translate="" tal:content="labelMsgId"></span></td>
<td><span class="appyLabel" tal:condition="not: innerRef" tal:content="label"></span></td>
<tal:comment replace="nothing">If there is no object...</tal:comment>
<tal:noObject condition="not:objs">
<td i18n:translate="">no_ref</td>
<td><metal:plusIcon use-macro="here/<!applicationName!>AppyReference/macros/plusIcon"/></td>
<td tal:content="python: tool.translate('no_ref')"></td>
<td><metal:plusIcon use-macro="here/skyn/ref/macros/plusIcon"/></td>
</tal:noObject>
<tal:comment replace="nothing">If there is an object...</tal:comment>
<tal:objectIsPresent condition="python: len(objs) == 1">
<tal:obj define="obj python:objs[0]">
<td><metal:showObjectTitle use-macro="here/<!applicationName!>AppyReference/macros/objectTitle" /></td>
<td><metal:showObjectTitle use-macro="here/skyn/ref/macros/objectTitle" /></td>
<td tal:condition="not: isBack">
<metal:showObjectActions use-macro="here/<!applicationName!>AppyReference/macros/objectActions" />
<metal:showObjectActions use-macro="here/skyn/ref/macros/objectActions" />
</td>
</tal:obj>
</tal:objectIsPresent>
@ -104,16 +105,16 @@
<tal:anyNumberOfReferences condition="not: atMostOneRef">
<fieldset tal:attributes="class python:test(innerRef, 'innerAppyFieldset', '')">
<legend tal:condition="python: not innerRef or showPlusIcon">
<span tal:condition="not: innerRef" i18n:translate="" tal:content="labelMsgId"/>
<metal:plusIcon use-macro="here/<!applicationName!>AppyReference/macros/plusIcon"/>
<span tal:condition="not: innerRef" tal:content="label"/>
<metal:plusIcon use-macro="here/skyn/ref/macros/plusIcon"/>
</legend>
<tal:comment replace="nothing">Object description</tal:comment>
<p tal:define="descr python:contextObj.utranslate(descrMsgId, domain='<!applicationName!>')"
tal:condition="python: not innerRef and descr.strip()" tal:content="descr" class="discreet" ></p>
<p tal:condition="python: not innerRef and description"
tal:content="description" class="discreet" ></p>
<tal:comment replace="nothing">No object is present</tal:comment>
<p tal:condition="not:objs" i18n:translate="">no_ref</p>
<p tal:condition="not:objs" tal:content="python: tool.translate('no_ref')"></p>
<table width="100%" cellspacing="0" cellpadding="0" tal:condition="objs"
tal:attributes="class python:test(innerRef, 'innerAppyTable', '')">
@ -123,7 +124,7 @@
<table class="no-style-table" cellspacing="0" cellpadding="0"
tal:condition="python: isBack and objs">
<tr tal:repeat="obj objs">
<td><metal:showObjectTitle use-macro="here/<!applicationName!>AppyReference/macros/objectTitle" />
<td><metal:showObjectTitle use-macro="here/skyn/ref/macros/objectTitle" />
</td>
</tr>
</table>
@ -133,27 +134,29 @@
width python:test(innerRef, '100%', test(appyType['wide'], '100%', ''))"
align="right" tal:condition="python: not isBack and objs" cellpadding="0" cellspacing="0">
<tr tal:condition="appyType/showHeaders">
<th tal:condition="python: 'title' not in appyType['shownInfo']" i18n:translate="ref_name"></th>
<th tal:condition="python: 'title' not in appyType['shownInfo']"
tal:content="python: tool.translate('ref_name')"></th>
<th tal:repeat="shownField appyType/shownInfo">
<tal:showHeader condition="python: objs[0].getField(shownField)">
<tal:titleHeader condition="python: shownField == 'title'" i18n:translate="ref_name"/>
<tal:titleHeader condition="python: shownField == 'title'"
content="python: tool.translate('ref_name')"/>
<tal:otherHeader condition="python: shownField != 'title'"
define="labelId python: objs[0].getField(shownField).widget.label_msgid"
content="labelId" i18n:translate=""/>
content="python: tool.translate(labelId)"/>
</tal:showHeader>
</th>
<th i18n:translate="ref_actions"></th>
<th tal:content="python: tool.translate('ref_actions')"></th>
</tr>
<tr tal:repeat="obj objs" valign="top">
<tal:comment replace="nothing">Object title, shown here if not specified somewhere
else in appyType.shownInfo.</tal:comment>
<td tal:condition="python: 'title' not in appyType['shownInfo']"><metal:showObjectTitle
use-macro="here/<!applicationName!>AppyReference/macros/objectTitle"/>&nbsp;
use-macro="here/skyn/ref/macros/objectTitle"/>&nbsp;
</td>
<tal:comment replace="nothing">Additional fields that must be shown</tal:comment>
<td tal:repeat="shownField appyType/shownInfo">
<tal:showTitle condition="python: shownField == 'title'">
<metal:showObjectTitle use-macro="here/<!applicationName!>AppyReference/macros/objectTitle"/>
<metal:showObjectTitle use-macro="here/skyn/ref/macros/objectTitle"/>
</tal:showTitle>
<tal:showOtherField define="appyType python: obj.getAppyType(shownField);
field python:obj.getField(shownField);
@ -166,23 +169,21 @@
<tal:ref tal:define="isBack python:appyType['isBack'];
fieldRel python:field.relationship;
objs python:contextObj.getAppyRefs(field.getName());
labelMsgId field/widget/label_msgid;
descrMsgId field/widget/description_msgid;
innerRef python:True">
<metal:showField use-macro="here/<!applicationName!>AppyReference/macros/showReference" />
<metal:showField use-macro="here/skyn/ref/macros/showReference" />
</tal:ref>
</tal:showRef>
<tal:showComputed condition="python: appyType['type'] == 'Computed'">
<tal:computed content="python: obj.getComputedValue(appyType)"/>
</tal:showComputed>
<tal:showAction condition="python: appyType['type'] == 'Action'">
<metal:action use-macro="here/<!macros!>/macros/showActionField" />
<metal:action use-macro="here/skyn/macros/macros/showActionField" />
</tal:showAction>
</tal:showOtherField>&nbsp;
</td>
<tal:comment replace="nothing">Actions</tal:comment>
<td align="right">
<metal:showObjectActions use-macro="here/<!applicationName!>AppyReference/macros/objectActions" />
<metal:showObjectActions use-macro="here/skyn/ref/macros/objectActions" />
</td>
</tr>
</table>
@ -196,7 +197,7 @@
</tal:anyNumberOfReferences>
</div>
<div metal:define-macro="editReference" i18n:domain="<!applicationName!>"
<div metal:define-macro="editReference"
tal:define="refPortalType python:here.getAppyRefPortalType(field.getName());
appyType python:here.getAppyType(field.getName());
allBrains python:here.uid_catalog(portal_type=refPortalType);
@ -205,23 +206,22 @@
isMultiple python:test(appyType['multiplicity'][1]!=1, 'multiple', '');
appyFieldName python: 'appy_ref_%s' % field.getName();
inError python:test(errors.has_key(field.getName()), True, False);
defaultValue python: here.getDefault(field.getName());
defaultValue python: contextObj.getDefault(field.getName());
defaultValueUID defaultValue/UID|nothing;
isBeingCreated python: context.portal_factory.isTemporary(context) or ('/portal_factory/' in context.absolute_url())"
isBeingCreated python: contextObj.portal_factory.isTemporary(contextObj) or ('/portal_factory/' in contextObj.absolute_url())"
tal:attributes="class python:'appyRefEdit field' + test(inError, ' error', '')">
<tal:comment replace="nothing">This macro displays the Reference widget on an "edit" page</tal:comment>
<label tal:attributes="for python:appyFieldName"
i18n:translate="" tal:content="field/widget/label_msgid"></label>
<span class="fieldRequired" tal:condition="python: appyType['multiplicity'][0]>0"></span><br/>
<label tal:attributes="for python:appyFieldName" tal:content="label"></label>&nbsp;
<span class="fieldRequired" tal:condition="python: appyType['multiplicity'][0]&gt;0"></span><br/>
<div tal:condition="inError" tal:content="python: errors[field.getName()]"></div>
<select tal:define="valueIsInReq python:test(request.get(appyFieldName, None) != None, True, False)"
tal:attributes="name python:'appy_ref_%s' % field.getName();
multiple isMultiple">
<option tal:condition="not: isMultiple" value="" i18n:translate="choose_a_value"/>
<option tal:repeat="brain brains"
tal:content="python: here.<!toolInstanceName!>.getReferenceLabel(brain, appyType)"
tal:content="python: tool.getReferenceLabel(brain, appyType)"
tal:attributes="value brain/UID;
selected python:test((valueIsInReq and (brain.UID in request.get(appyFieldName, []))) or (not valueIsInReq and ((brain.UID in refUids) or (isBeingCreated and (brain.UID==defaultValueUID)))), True, False)"/>
</select>

View file

Before

Width:  |  Height:  |  Size: 225 B

After

Width:  |  Height:  |  Size: 225 B

View file

@ -1,5 +1,4 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
i18n:domain="<!applicationName!>"
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"
@ -16,20 +15,22 @@
<tal:comment replace="nothing">Fill main slot of Plone main_template</tal:comment>
<body>
<metal:fill fill-slot="main"
tal:define="contextObj python:context;
tal:define="contextObj python:context.getParentNode();
portal_type python:here.getPortalTypeName().lower().replace(' ', '_');
errors python:request.get('errors', {});
isEdit python:False;
tool contextObj/getTool;
flavour python: tool.getFlavour(contextObj);
appFolder tool/getAppFolder;
appName appFolder/id;
phaseInfo python: contextObj.getAppyPhases(currentOnly=True, forPlone=False);
phase request/phase|phaseInfo/name;
pageName python: contextObj.getAppyPage(isEdit, phaseInfo);
showWorkflow python: flavour.getAttr('showWorkflowFor' + contextObj.meta_type)">
<div metal:use-macro="here/<!macros!>/macros/showPagePrologue"/>
<div metal:use-macro="here/<!macros!>/macros/showPageHeader"/>
<div metal:use-macro="here/<!macros!>/macros/listFields" />
<div metal:use-macro="here/<!macros!>/macros/showPageFooter"/>
<div metal:use-macro="here/skyn/macros/macros/showPagePrologue"/>
<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/showPageFooter"/>
</metal:fill>
</body>
</html>

View file

@ -20,8 +20,8 @@ class <!genClassName!>(<!parents!>):
allowed_content_types = []
filter_content_types = 0
global_allow = 1
immediate_view = '<!applicationName!>_appy_view'
default_view = '<!applicationName!>_appy_view'
immediate_view = 'skyn/view'
default_view = 'skyn/view'
suppl_views = ()
typeDescription = '<!genClassName!>'
typeDescMsgId = '<!genClassName!>_edit_descr'

View file

@ -22,8 +22,8 @@ class <!flavourName!>(OrderedBaseFolder, FlavourMixin):
filter_content_types = 0
global_allow = 1
#content_icon = '<!flavourName!>.gif'
immediate_view = '<!applicationName!>_appy_view'
default_view = '<!applicationName!>_appy_view'
immediate_view = 'skyn/view'
default_view = 'skyn/view'
suppl_views = ()
typeDescription = "<!flavourName!>"
typeDescMsgId = '<!flavourName!>_edit_descr'

View file

@ -1,5 +1,6 @@
<!codeHeader!>
from zExceptions import BadRequest
from Products.CMFCore.DirectoryView import manage_addDirectoryView
from Products.ExternalMethod.ExternalMethod import ExternalMethod
from Products.Archetypes.Extensions.utils import installTypes
from Products.Archetypes.Extensions.utils import install_subskin

View file

@ -21,8 +21,8 @@ class <!applicationName!>PodTemplate(BaseContent, PodTemplateMixin):
filter_content_types = 0
global_allow = 1
#content_icon = '<!applicationName!>PodTemplate.gif'
immediate_view = '<!applicationName!>_appy_view'
default_view = '<!applicationName!>_appy_view'
immediate_view = 'skyn/view'
default_view = 'skyn/view'
suppl_views = ()
typeDescription = "<!applicationName!>PodTemplate"
typeDescMsgId = '<!applicationName!>_edit_descr'

View file

@ -1,45 +1,16 @@
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
i18n:domain="<!applicationName!>">
<body>
<div metal:define-macro="portlet"
tal:define="tool python: context.<!toolInstanceName!>"
tal:condition="tool/showPortlet">
<metal:block metal:use-macro="here/global_defines/macros/defines" />
<dl class="portlet"
tal:define="rootClasses python:[<!rootClasses!>];
appFolder tool/getAppFolder">
<tal:comment replace="nothing">Portlet title, with link to tool.</tal:comment>
<dt class="portletHeader">
<span i18n:translate="" tal:content="python: '<!applicationName!>'">
</span>&nbsp;
<img i18n:attributes="title" style="cursor:pointer" title="<!applicationName!>Tool"
tal:condition="python: member.has_role('Manager')"
tal:attributes="onClick python: 'href: window.location=\'%s/\'' % tool.absolute_url();
src python: here.<!toolInstanceName!>.absolute_url() + '/appyConfig.gif'"/>
</dt>
<tal:comment replace="nothing">Links to flavours</tal:comment>
<dt class="portletAppyItem" tal:repeat="flavourInfo tool/getFlavoursInfo">
<a tal:define="flavourNumber flavourInfo/number;
rootTypes python: test(flavourNumber==1, rootClasses, ['%s_%s' % (rc, flavourNumber) for rc in rootClasses]);
rootClassesQuery python:','.join(rootTypes)"
tal:content="flavourInfo/title"
i18n:translate="" title="query_consult_all" i18n:attributes="title"
tal:attributes="href python:'%s/<!queryName!>?query=%s&flavourNumber=%d' % (appFolder.absolute_url(), rootClassesQuery, flavourNumber)"></a>
</dt>
<dt class="portletAppyItem" tal:condition="python: context.meta_type in rootClasses">
<metal:phases use-macro="here/<!macros!>/macros/phases"/>
</dt>
</dl>
</div>
</body>
<body>
<div metal:define-macro="portlet"
tal:define="tool python: context.<!toolInstanceName!>"
tal:condition="tool/showPortlet">
<metal:block metal:use-macro="here/global_defines/macros/defines" />
<dl tal:define="rootClasses tool/getRootClasses;
appName string:<!applicationName!>;
appFolder tool/getAppFolder" class="portlet">
<metal:content use-macro="here/skyn/macros/macros/portletContent"/>
</dl>
</div>
</body>
</html>

View file

@ -1,63 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
metal:use-macro="here/main_template/macros/master"
i18n:domain="<!applicationName!>">
<!-- This page presents results of queries -->
<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>
<div metal:fill-slot="main"
tal:define="tool python: context.<!toolInstanceName!>;
queryName python:context.REQUEST.get('query');
flavourNumber python:context.REQUEST.get('flavourNumber');
rootClasses python:[<!rootClasses!>];
rootTypes python: test(flavourNumber=='1', rootClasses, ['%s_%s' % (rc, flavourNumber) for rc in rootClasses]);
rootClassesQuery python:','.join(rootClasses);
mainTabSelected python: queryName.find(',') != -1;
appFolder tool/getAppFolder">
<span tal:condition="python: queryName and (queryName != 'none')">
<span tal:define="queryResult python: context.<!toolInstanceName!>.executeQuery(queryName, int(flavourNumber));
batch queryResult">
<!-- Tabs -->
<ul class="contentViews appyTabs">
<!-- Tab "All objects" -->
<li tal:define="selected python:mainTabSelected"
tal:attributes="class python:test(selected, 'selected', 'plain')"
tal:condition="python: len(rootClasses)>1">
<a tal:attributes="href python: '%s/<!queryName!>?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootClassesQuery, flavourNumber)"
i18n:translate="">query_consult_all</a>
</li>
<!-- One tab for each root content type -->
<tal:tab repeat="rootContentType rootTypes">
<li tal:define="selected python:queryName == rootContentType"
tal:attributes="class python:test(selected, 'selected', 'plain')">
<a i18n:translate="" tal:content="rootContentType"
tal:attributes="href python: '%s/<!queryName!>?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootContentType, flavourNumber)"/>
<img i18n:attributes="title" style="cursor:pointer" title="query_create" class="appyPlusImg"
tal:define="addPermission python: '<!applicationName!>: Add %s' % rootContentType"
tal:attributes="onClick python: 'href: window.location=\'%s/createObject?type_name=%s\'' % (appFolder.absolute_url(), rootContentType);
src python: here.<!toolInstanceName!>.absolute_url() + '/plus.png'"
tal:condition="python: member.has_permission(addPermission, appFolder)"/>
</li>
</tal:tab>
</ul>
<br/>
<!-- Query result -->
<span tal:condition="queryResult">
<span metal:use-macro="here/<!macros!>/macros/queryResult"></span>
</span>
<span tal:condition="not: queryResult"
i18n:translate="query_no_result">No result.</span>
</span>
</span>
</div>
</body>
</html>

View file

@ -52,14 +52,14 @@
/* stepxx classes are used for displaying status of a phase or state. */
.stepDone {
background-color: #cde2a7;
background-image: url(&dtml-portal_url;/done.png);
background-image: url(&dtml-portal_url;/skyn/done.png);
background-repeat: no-repeat;
background-position: center left;
}
.stepCurrent {
background-color: #ffce7b;
background-image: url(&dtml-portal_url;/current.png);
background-image: url(&dtml-portal_url;/skyn/current.png);
background-repeat: no-repeat;
background-position: center left;
}

View file

@ -24,8 +24,8 @@ class <!toolName!>(UniqueObject, OrderedBaseFolder, ToolMixin):
filter_content_types = 0
global_allow = 0
#content_icon = '<!toolName!>.gif'
immediate_view = '<!applicationName!>_appy_view'
default_view = '<!applicationName!>_appy_view'
immediate_view = 'skyn/view'
default_view = 'skyn/view'
suppl_views = ()
typeDescription = "<!toolName!>"
typeDescMsgId = '<!toolName!>_edit_descr'
@ -35,7 +35,7 @@ class <!toolName!>(UniqueObject, OrderedBaseFolder, ToolMixin):
schema = fullSchema
schema["id"].widget.visible = False
schema["title"].widget.visible = False
# When browsing into the tool, the 'configure' portlet should be dislayed.
# When browsing into the tool, the 'configure' portlet should be displayed.
left_slots = ['here/portlet_prefs/macros/portlet']
right_slots = []
for elem in dir(ToolMixin):

View file

@ -1,160 +0,0 @@
<tal:block metal:define-macro="master"
define="errors options/state/getErrors | nothing;
Iterator python:modules['Products.Archetypes'].IndexIterator;
schematas here/Schemata;
fieldsets python:[key for key in schematas.keys() if (key != 'metadata') and (schematas[key].editableFields(here, visible_only=True))];
default_fieldset python:(not schematas or schematas.has_key('default')) and 'default' or fieldsets[0];
fieldset request/fieldset|options/fieldset|default_fieldset;
fields python:schematas[fieldset].editableFields(here);
dummy python:here.at_isEditable(fields);
portal_type python:here.getPortalTypeName().lower().replace(' ', '_');
type_name here/getPortalTypeName|here/archetype_name;
lockable python:hasattr(here, 'wl_isLocked');
isLocked python:lockable and here.wl_isLocked();
tabindex tabindex|python:Iterator(pos=7000);
isEdit python:True;
contextObj python:context;
css python:here.getUniqueWidgetAttr(fields, 'helper_css');
js python:here.getUniqueWidgetAttr(fields, 'helper_js');
phaseInfo python: context.getAppyPhases(fieldset=fieldset, forPlone=True);
phase request/phase|phaseInfo/name;
pageName python: context.getAppyPage(isEdit, phaseInfo);">
<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">
<!-- Disable the Standard Plone green tab -->
<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>
<!-- Archetypes stuff for managing Javascript and CSS. If I remove this stuff,
Javascript popup for dates does not work anyore -->
<metal:javascript_head fill-slot="javascript_head_slot">
<tal:block define="macro here/archetypes_custom_js/macros/javascript_head | nothing"
condition="macro">
<metal:block use-macro="macro" />
</tal:block>
<tal:js condition="js" repeat="item js">
<script type="text/javascript" charset="iso-8859-1"
tal:condition="python:exists('portal/%s' % item)"
tal:attributes="src string:$portal_url/$item">
</script>
</tal:js>
<tal:block define="macro edit_macros/javascript_head | nothing" condition="macro">
<metal:block use-macro="macro" />
</tal:block>
</metal:javascript_head>
<metal:css fill-slot="css_slot">
<tal:css condition="css" repeat="item css">
<style type="text/css" media="all"
tal:condition="python:exists('portal/%s' % item)"
tal:content="structure string:<!-- @import url($portal_url/$item); -->">
</style>
</tal:css>
<tal:block define="macro edit_macros/css | nothing" condition="macro">
<metal:block use-macro="macro" />
</tal:block>
</metal:css>
<body>
<metal:fill fill-slot="main">
<div metal:use-macro="here/<!macros!>/macros/showPagePrologue"/>
<div metal:use-macro="here/<!macros!>/macros/showPageHeader"/>
<form name="edit_form" method="post" enctype="multipart/form-data"
class="enableUnloadProtection atBaseEditForm"
tal:attributes="action python:here.absolute_url()+'/'+template.id;
id string:${portal_type}-base-edit">
<div metal:use-macro="here/<!macros!>/macros/listFields" />
<div class="formControls">
<input type="hidden" name="fieldset" tal:attributes="value fieldset"/>
<input type="hidden" name="form.submitted" value="1"/>
<input type="hidden" name="add_reference.field:record" value=""/>
<input type="hidden" name="add_reference.type:record" value=""/>
<input type="hidden" name="add_reference.destination:record" value=""/>
<tal:env define="env request/controller_state/kwargs">
<tal:loop repeat="varname python:('reference_source_url', 'reference_source_field', 'reference_source_fieldset')">
<tal:reference define="items python:env.get(varname, request.get(varname))"
condition="items">
<input tal:repeat="item items" type="hidden"
tal:attributes="value item;
name string:form_env.${varname}:list:record"/>
</tal:reference>
</tal:loop>
</tal:env>
<tal:comment replace="nothing">Turn 'persistent_' variables from controller_state persistent
</tal:comment>
<tal:env repeat="env request/controller_state/kwargs/items">
<input type="hidden"
tal:define="key python:env[0];
value python:env[1]"
tal:condition="python:key.startswith('persistent_')"
tal:attributes="name string:form_env.${key}:record;
value value"/>
</tal:env>
<tal:comment replace="nothing">Turn 'persistent_' variables from forms (GET/POST) persistent
</tal:comment>
<tal:env repeat="env request/form">
<input type="hidden"
tal:define="key env;
value request/?env"
tal:condition="python:key.startswith('persistent_')"
tal:attributes="name string:form_env.${key}:record;
value value"/>
</tal:env>
<tal:comment replace="nothing">Store referrer to remember where to go back
</tal:comment>
<input type="hidden" name="last_referer"
tal:define="last_referer python:here.session_restore_value('HTTP_REFERER', request.form.get('last_referer', request.get('HTTP_REFERER')))"
tal:attributes="value python:(last_referer and '%s/%s' % (here.absolute_url(), template.id) not in last_referer) and last_referer or (here.getParentNode() and here.getParentNode().absolute_url())"/>
<tal:comment replace="nothing">Buttons (Previous, Next, Save, etc)</tal:comment>
<metal:block define-slot="buttons"
tal:define="pages phaseInfo/pages;
pageIndex python:pages.index(fieldset);
numberOfPages python:len(pages)">
<tal:previousButton condition="python: pageIndex &gt; 0">
<input class="context" type="submit" name="form_previous"
i18n:attributes="value label_previous;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next;
disabled python:test(isLocked, 'disabled', None);"/>
<input type="hidden" name="previousPage" tal:attributes="value python: pages[pageIndex-1]"/>
</tal:previousButton>
<tal:nextButton condition="python: pageIndex &lt; numberOfPages - 1">
<input class="context" type="submit" name="form_next" value="Next"
i18n:attributes="value label_next;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next;
disabled python:test(isLocked, 'disabled', None);"/>
<input type="hidden" name="nextPage" tal:attributes="value python: pages[pageIndex+1]"/>
</tal:nextButton>
<input class="context" type="submit" name="form_submit"
i18n:attributes="value label_save;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next;
disabled python:test(isLocked, 'disabled', None);"/>
<input class="standalone" type="submit" name="form.button.cancel"
i18n:attributes="value label_cancel;" i18n:domain="plone"
tal:attributes="tabindex tabindex/next"/>
</metal:block>
</div>
</form>
<div metal:use-macro="here/<!macros!>/macros/showPageFooter"/>
</metal:fill>
</body>
</html>
</tal:block>

View file

@ -1,13 +0,0 @@
[default]
title = Edit
[validators]
validators = validate_base
validators..form_add =
validators..cancel =
[actions]
action.success = traverse_to:string:content_edit
action.success..form_add = traverse_to:string:add_reference
action.success..cancel = traverse_to:string:go_back
action.failure = traverse_to_action:string:edit

View file

@ -13,24 +13,24 @@ import Extensions.appyWrappers
# every Archetype instance has a method "getProductConfig" that returns this
# module.
from persistent.list import PersistentList
from Products.Archetypes.utils import DisplayList
from OFS.Image import File
from DateTime import DateTime
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.PloneBatch import Batch
from OFS.Image import File
from Products.Archetypes.utils import DisplayList
import logging
logger = logging.getLogger('<!applicationName!>')
# Some global variables --------------------------------------------------------
PROJECTNAME = '<!applicationName!>'
defaultAddRoles = [<!defaultAddRoles!>]
DEFAULT_ADD_CONTENT_PERMISSION = "Add portal content"
ADD_CONTENT_PERMISSIONS = {
<!addPermissions!>}
setDefaultRoles(DEFAULT_ADD_CONTENT_PERMISSION, tuple(defaultAddRoles))
product_globals = globals()
PROJECTNAME = '<!applicationName!>'
applicationRoles = [<!roles!>]
rootClasses = [<!rootClasses!>]
referers = {
<!referers!>
}

View file

@ -1,27 +0,0 @@
## Controller Python Script "createAppyObject"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind state=state
##bind subpath=traverse_subpath
##parameters=initiator, field, type_name
##title=createAppyObject
##
if not initiator or not field:
raise Exception, 'You must specify the uid of the object that initiates ' \
'this creation in the "initiator" parameter and the ' \
'related field in the "field" param.'
if not type_name:
raise Exception, 'You must specify the target type name in the "type_name" ' \
'parameter.'
initiatorRes = context.uid_catalog.searchResults(UID=initiator)
if not initiatorRes:
raise Exception, 'Given initiator UID does not correspond to a valid object.'
context.REQUEST.SESSION['initiator'] = initiator
context.REQUEST.SESSION['initiatorField'] = field
context.REQUEST.SESSION['initiatorTarget'] = type_name
return state.set(status='success')

View file

@ -1,2 +0,0 @@
[actions]
action.success=redirect_to:python:'createObject?type_name=%s' % request.SESSION.get('initiatorTarget')

0
gen/plone25/utils.py Executable file → Normal file
View file

View file

@ -180,8 +180,8 @@ class AbstractWrapper:
return appyObj
def translate(self, label, mapping={}, domain=None):
if not domain: domain = self.o.getProductConfig().PROJECTNAME
return self.o.utranslate(label, mapping, domain=domain)
'''Check documentation of self.o.translate.'''
return self.o.translate(label, mapping, domain)
def do(self, transition, comment='', doAction=False, doNotify=False):
'''This method allows to trigger on p_self a workflow p_transition

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
xhtmlInput = '''
<ol><li>
<p>Test du champ kupu<br />A la ligne
1, j'y suis</p>
<ol><li>
<p>Ligne 1 de 1<br />A la ligne 1 de 1
fdsfds fsd fsd fksdf sdfs dfd sfsd fsd fsd fdsf dsfds fsdfa azra
zeeamr earkl kfl flks dlfksd lfklsd fklmsdfkl dskflmdsk flmsdf
lmdsflm dflsdfs fksd fmlsd flmdsk flmdsf mlsfkmls<br />A la ligne 2
de 1 cds fdsn sfd dsjfl dsjfhjds fhjdsf lqdhf klsfql kjfk jfkj
qfklmqds fjdlksqfj kdlfj klqfk qfjk ljfqklq djfklqjf qfk jkfljqd
sklfjqdklfjqdkl fjdqklf jdqlkfj qfq</p>
</li><li>
<p>Ligne 2 de 1<br />A la ligne 1 de 2
fdsfds fsd fsd fksdf sdfs dfd sfsd fsd fsd fdsf dsfds fsdfa azra
zeeamr earkl kfl flks dlfksd lfklsd fklmsdfkl dskflmdsk flmsdf
lmdsflm dflsdfs fksd fmlsd flmdsk flmdsf mlsfkmls<br />A la ligne 2
de 2 cds fdsn sfd dsjfl dsjfhjds fhjdsf lqdhf klsfql kjfk jfkj
qfklmqds fjdlksqfj kdlfj klqfk qfjk ljfqklq djfklqjf qfk jkfljqd
sklfjqdklfjqdkl fjdqklf jdqlkfj qf</p>
</li></ol>
</li><li>
<p>Ligne 2 tout court</p>
<ol><li>
<p>Ligne bullet dg fg dgd fgdf gdfg
dgq fg fgfq gfqd gfqg qfg qgkqlglk lgkl fkgkfq lmgkl mfqfkglmfk
gmlqf gmlqfgml kfmglk qmglk qmlgk qmlgkqmflgk qmlqg fmdlmslgk
mlsgml fskfmglk gmlkflmg ksfmlgk mlsgk</p>
</li><li>
<p>dsfl kqfs dmflm dsfsdf lskfmls
dkflmsdkf sdlmkf dslmfk sdmlfksd mlfksdmfl ksflmksdflmd slfmskd
lsmlfk mlsdfkl mskfmlsfk lmskfsfs</p>
</li><li>
<p>fmlsdm ùfkùds fldsf ùsfsdmfù
mdsfù msdùfms</p>
</li><li>
<p>fds fsd fdsf sdfds fsmd fmjdfklm
sdflmkd lfqlmklmdsqkflmq dskflmkd slmgkqdfmglklfmgksmldgk
dmlsgdkdlm fgkmdl fkgdmlfsgk mlfgksmdl fgkmldsf klmmdfkg mlsdfkgml
skfdgml skgmlkfd smlgksd mlkgml kml</p>
</li><li>
<p>lgd ksmlgjk mlsdfgkml sdfkglm
kdsfmlgk dlmskgsldmgk lms</p>
</li></ol>
</li><li>
<p>Ligne 3 tout court</p>
</li></ol>
<br />'''
xhtmlInput2 = '''
<ol start="1"><li>Le Gouvernement approuve la réaffectation de 20.056.989 attribués dans le cadre du CRAC II et laffectation du solde de 20.855.107 du solde des CRAC Ibis et II au sein du secteur des hôpitaux de lenveloppe de financement alternatif pour un montant total de 40.921.096 , au bénéfice des établissements suivants :<br /><br /></li>
<table align="center">
<tbody>
<tr>
<td>
<b>Etablissement</b></td>
<td>
<p align="center" style="text-align: center;"><b>CRAC II Phase II</b></p>
</td>
</tr>
<tr>
<td>
<p>C.H. Chrétien Liège</p>
</td>
<td nowrap="-1">
<p align="center" style="text-align: center;">11.097.377</p>
</td>
</tr>
<tr>
<td nowrap="-1">
<p>Hôp. St-Joseph, Ste-Thérèse et IMTR Gilly</p>
</td>
<td nowrap="-1">
<p align="center" style="text-align: center;">8.297.880</p>
</td>
</tr>
</tbody>
</table>
<br /><li>Il prend acte des décisions du Ministre de la Santé relatives à loctroi de la règle de 10/90 pour la subsidiation des infrastructures des établissements concernés.<br /></li>
<li>Le Gouvernement charge le Ministre de la Santé dappliquer, le cas échéant, les nouveaux plafonds à la construction visés dans larrêté ministériel du 11 mai 2007 fixant le coût maximal pouvant être pris en considération pour loctroi des subventions pour la construction de nouveaux bâtiments, les travaux dextension et de reconditionnement dun hôpital ou dun service, aux demandes doctroi de subventions antérieures au 1<sup>er</sup> janvier 2006, pour autant que ces demandes doctroi de subventions naient pas encore donné lieu à lexploitation à cette même date.<br /></li>
<li>Il charge le Ministre de la Santé de lexécution de la présente décision</li></ol>
<p></p>
'''
xhtmlInput3 = '''
<ol><li>Le Gouvernement l'exercice 2008.</li><li>Il approuve 240.000€ de007-2008.</li><li>Le Gouvernement approuve:
<ul><li>le projet d'arrêté ministériel 008;</li><li>le projet d'arrêté ministériel mique 2008-2009.</li></ul></li><li>Le Gouvernement charge le Ministre de l'Economie de l'exécution de la présente décision.</li></ol>
'''
xhtmlInput4 = '''
<div><strong>Programmes FSE Convergence et Compétitivité régionale et emploi.</strong></div>
<div><strong>Axe 1, mesure 1, et Axe 2, mesures 2, 3, 4 et 5 : formation.</strong></div>
<div><strong>Portefeuille de projets « Enseignement supérieur - Formation continue ».</strong></div>
'''

View file

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
xhtmlInput = '''
<p>Some HTML entities: é: &eacute;, è: &egrave;, Atilde: &Atilde;.</p>
<p>XML entities: amp: &amp;, quote: &quot;, apos: &apos;, lt: &lt;, gt: &gt;.</p>'''
<p>XML entities: amp: &amp;, quote: &quot;, apos: &apos;, lt: &lt;, gt: &gt;.</p>
<p>&nbsp;</p><p>Para</p>'''

Binary file not shown.

Binary file not shown.

BIN
pod/test/results/xhtmlEntities.odt Executable file → Normal file

Binary file not shown.

Binary file not shown.

View file

@ -1 +0,0 @@
0.2.1 (2008-06-04)

View file

@ -25,8 +25,8 @@ from appy.pod import *
# To which ODT tag does HTML tags correspond ?
HTML_2_ODT = {'h1':'h', 'h2':'h', 'h3':'h', 'h4':'h', 'h5':'h', 'h6':'h',
'p':'p', 'b':'span', 'i':'span', 'strong':'span', 'em': 'span',
'sub': 'span', 'sup': 'span', 'br': 'line-break', 'div': 'span'}
'p':'p', 'b':'span', 'i':'span', 'strong':'span', 'em': 'span',
'sub': 'span', 'sup': 'span', 'br': 'line-break', 'div': 'span'}
DEFAULT_ODT_STYLES = {'b': 'podBold', 'strong':'podBold', 'i': 'podItalic',
'em': 'podItalic', 'sup': 'podSup', 'sub':'podSub',
'td': 'podCell', 'th': 'podHeaderCell'}
@ -35,6 +35,7 @@ TABLE_CELL_TAGS = ('td', 'th')
OUTER_TAGS = TABLE_CELL_TAGS + ('li',)
NOT_INSIDE_P = ('table', 'ol', 'ul') # Those elements can't be rendered inside
# paragraphs.
NOT_INSIDE_LIST = ('table',)
IGNORABLE_TAGS = ('meta', 'title', 'style')
HTML_ENTITIES = {
'iexcl': '¡', 'cent': '¢', 'pound': '£', 'curren': '', 'yen': '¥',
@ -56,8 +57,8 @@ HTML_ENTITIES = {
'ntilde':'ñ', 'ograve':'ò', 'oacute':'ó', 'ocirc':'ô', 'otilde':'õ',
'ouml':'ö', 'divide':'÷', 'oslash':'ø', 'ugrave':'ù', 'uacute':'ú',
'ucirc':'û', 'uuml':'ü', 'yacute':'ý', 'thorn':'þ', 'yuml':'ÿ',
'euro':'', 'nbsp':' ', "rsquo":"'", 'ndash': ' ', 'oelig':'oe',
'quot': "'", 'mu': 'µ'}
'euro':'', 'nbsp':' ', "rsquo":"'", "lsquo":"'", "ldquo":"'",
"rdquo":"'", 'ndash': ' ', 'oelig':'oe', 'quot': "'", 'mu': 'µ'}
# ------------------------------------------------------------------------------
class Entity:
@ -71,6 +72,8 @@ class HtmlElement:
'''Every time an HTML element is encountered during the SAX parsing,
an instance of this class is pushed on the stack of currently parsed
elements.'''
elemTypes = {'p':'para', 'li':'para','ol':'list','ul':'list'}
odfElems = {'p':'p', 'li':'list-item', 'ol': 'list', 'ul': 'list'}
def __init__(self, elem, attrs):
self.elem = elem
# Keep "class" attribute (useful for finding the corresponding ODT
@ -80,34 +83,42 @@ class HtmlElement:
self.classAttr = None
if attrs.has_key('class'):
self.classAttr = attrs['class']
self.tagsToReopen = '' # When the HTML element corresponding to self
self.tagsToReopen = [] # When the HTML element corresponding to self
# is completely dumped, if there was a problem related to tags
# inclusion, we may need to dump start tags corresponding to
# tags that we had to close before dumping this element.
self.tagsToClose = '' # Before dumping the closing tag corresponding
# tags that we had to close before dumping this element. This list
# contains HtmlElement instances.
self.tagsToClose = [] # Before dumping the closing tag corresponding
# to self, we may need to close other tags (ie closing a paragraph
# before closing a cell).
def isParagraph(self, env):
'''This methods returns True if:
- self is a "p";
- self is a "td" or "th" inside which a "p" was added.'''
return (self.elem == 'p') or \
( (self.elem in OUTER_TAGS) and \
(self.tagsToClose == '</%s:p>' % env.textNs))
# before closing a cell). This list contains HtmlElement instances.
self.elemType = self.elem
if self.elemTypes.has_key(self.elem):
self.elemType = self.elemTypes[self.elem]
def getOdfTag(self, env):
'''Gets the ODF tag that corresponds to me.'''
return '%s:%s' % (env.textNs, self.odfElems[self.elem])
def getConflictualElements(self, env):
'''self was just parsed. In some cases, this element can't be dumped
in the result because there are conflictual elements among previously
parsed opening elements (p_currentElements). For example, if we just
dumped a "p", we can't dump a table within the "p". Such constraints
do not hold in XHTML code but hold in ODF code.
!! Conflictual elements must be listed in HTML_2_ODT !! '''
res = ()
do not hold in XHTML code but hold in ODF code.'''
if env.currentElements:
if (env.currentElements[-1].isParagraph(env)) and \
(self.elem in NOT_INSIDE_P):
res = ('p',)
return res
parentElem = env.currentElements[-1]
# Check elements that can't be found within a paragraph
if (parentElem.elemType=='para') and (self.elem in NOT_INSIDE_P):
return (parentElem,)
if (parentElem.elem in OUTER_TAGS) and parentElem.tagsToClose and \
(parentElem.tagsToClose[-1].elem == 'p') and \
(self.elem in NOT_INSIDE_P):
return (parentElem.tagsToClose[-1],)
# Check elements that can't be found within a list
if (parentElem.elemType=='list') and (self.elem in NOT_INSIDE_LIST):
return (parentElem,)
return ()
def addInnerParagraph(self, env):
'''Dump an inner paragraph inside self (if not already done).'''
if not self.tagsToClose:
@ -124,7 +135,36 @@ class HtmlElement:
env.dumpString(' %s:style-name="%s"' % (env.textNs,
env.itemStyles[itemStyle]))
env.dumpString('>')
self.tagsToClose = '</%s:p>' % env.textNs
self.tagsToClose.append(HtmlElement('p',{}))
def dump(self, start, env):
'''Dumps the start or stop (depending onp_start) tag of this HTML
element. We must take care of potential innerTags.'''
# Compute the tag in itself
tag = ''
prefix = '<'
if not start: prefix += '/'
# Compute tag attributes
attrs = ''
if start:
if self.elemType == 'list':
# I must specify the list style
attrs += ' %s:style-name="%s"' % (
env.textNs, env.listStyles[self.elem])
if self.elem == 'ol':
# I have interrupted a numbered list. I need to continue
# the numbering.
attrs += ' %s:continue-numbering="true"' % env.textNs
tag = prefix + self.getOdfTag(env) + attrs + '>'
# Close/open subTags if any
for subElem in self.tagsToClose:
subTag = subElem.dump(start, env)
if start: tag += subTag
else: tag = subTag + tag
return tag
def __repr__(self):
return '<Html "%s">' % self.elem
# ------------------------------------------------------------------------------
class HtmlTable:
@ -156,6 +196,7 @@ class XhtmlEnvironment(XmlEnvironment):
itemStyles = {'ul': 'podBulletItem', 'ol': 'podNumberItem',
'ul_kwn': 'podBulletItemKeepWithNext',
'ol_kwn': 'podNumberItemKeepWithNext'}
listStyles = {'ul': 'podBulletedList', 'ol': 'podNumberedList'}
def __init__(self, ns):
XmlEnvironment.__init__(self)
self.res = u''
@ -255,6 +296,16 @@ class XhtmlEnvironment(XmlEnvironment):
self.textNs, odtStyle.outlineLevel))
self.dumpString('>')
def dumpTags(self, elems, start=True):
'''Dumps a series of start or end tags (depending on p_start) of
HtmlElement instances in p_elems.'''
tags = ''
for elem in elems:
tag = elem.dump(start, self)
if start: tags += tag
else: tags = tag + tags
self.dumpString(tags)
def dumpString(self, s):
'''Dumps arbitrary content p_s.
If the table stack is not empty, we must dump p_s into the buffer
@ -269,6 +320,14 @@ class XhtmlEnvironment(XmlEnvironment):
else:
self.res += s
def getTagsToReopen(self, conflictElems):
'''Normally, tags to reopen are equal to p_conflictElems. But we have a
special case. Indeed, if a conflict elem has itself tagsToClose,
the last tag to close may not be needed anymore on the tag to
reopen, so we remove it.'''
conflictElems[-1].tagsToClose = []
return conflictElems
def onElementStart(self, elem, attrs):
previousElem = self.getCurrentElement()
if previousElem and (previousElem.elem == 'podxhtml'):
@ -281,14 +340,8 @@ class XhtmlEnvironment(XmlEnvironment):
if conflictElems:
# We must close the conflictual elements, and once the currentElem
# will be dumped, we will re-open the conflictual elements.
closingTags = ''
openingTags = ''
for conflictElem in conflictElems:
odtElem = HTML_2_ODT[conflictElem]
closingTags = ('</%s:%s>' % (self.textNs, odtElem))+ closingTags
openingTags += '<%s:%s>' % (self.textNs, odtElem)
self.dumpString(closingTags)
currentElem.tagsToReopen = openingTags
self.dumpTags(conflictElems, start=False)
currentElem.tagsToReopen = self.getTagsToReopen(conflictElems)
# Manage missing elements
if self.anElementIsMissing(previousElem, currentElem):
previousElem.addInnerParagraph(self)
@ -333,14 +386,13 @@ class XhtmlEnvironment(XmlEnvironment):
lastTable.res += lastTable.tempRes
lastTable.tempRes = u''
if currentElem.tagsToClose:
self.dumpString(currentElem.tagsToClose)
self.dumpTags(currentElem.tagsToClose, start=False)
if currentElem.tagsToReopen:
res = currentElem.tagsToReopen
return res
# ------------------------------------------------------------------------------
class XhtmlParser(XmlParser):
listStyles = {'ul': 'podBulletedList', 'ol': 'podNumberedList'}
# Initialize entities recognized by this parser
entities = {}
for name, value in HTML_ENTITIES.iteritems():
@ -398,7 +450,7 @@ class XhtmlParser(XmlParser):
# must be surrounded by a list-item element.
prologue = '<%s:list-item>' % e.textNs
e.dumpString('%s<%s:list %s:style-name="%s">' % (
prologue, e.textNs, e.textNs, self.listStyles[elem]))
prologue, e.textNs, e.textNs, e.listStyles[elem]))
elif elem == 'li':
e.dumpString('<%s:list-item>' % e.textNs)
elif elem == 'table':
@ -424,6 +476,9 @@ class XhtmlParser(XmlParser):
e = XmlParser.endElement(self, elem)
elemsToReopen = e.onElementEnd(elem)
if HTML_2_ODT.has_key(elem):
# For "div" elements, we put append a carriage return.
if elem == 'div':
e.dumpString('<%s:line-break/>' % e.textNs)
e.dumpString('</%s:%s>' % (e.textNs, HTML_2_ODT[elem]))
elif elem == 'a':
e.dumpString('</%s:a>' % e.textNs)
@ -447,7 +502,7 @@ class XhtmlParser(XmlParser):
elif elem in IGNORABLE_TAGS:
e.ignore = False
if elemsToReopen:
e.dumpString(elemsToReopen)
e.dumpTags(elemsToReopen)
def characters(self, content):
e = XmlParser.characters(self, content)
@ -469,11 +524,7 @@ class Xhtml2OdtConverter:
self.xhtmlParser = XhtmlParser(XhtmlEnvironment(ns), self)
def run(self):
#print 'XHTML is **', self.xhtmlString, '**'
#print
self.xhtmlParser.parse(self.xhtmlString)
#print 'ODT chunk is **', self.xhtmlParser.env.res, '**'
#print
return self.xhtmlParser.env.res
def findStyle(self, elem, attrs=None, classValue=None):