Added a new system for layouting production-ready forms without any HTML coding, many performance improvements and more independence towards Archetypes.
							
								
								
									
										30
									
								
								bin/job.py
									
										
									
									
									
								
							
							
						
						| 
						 | 
					@ -1,17 +1,21 @@
 | 
				
			||||||
'''job.py must be executed by a "zopectl run" command and, as single arg,
 | 
					'''job.py must be executed by a "zopectl run" command and, as single arg,
 | 
				
			||||||
   must get a string with the following format:
 | 
					   must get a string with the following format:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <ZopeAdmin><PloneInstancePath>:<ApplicationName>:<ToolMethodName>[:<args>].
 | 
					    <ZopeAdmin>:<PloneInstancePath>:<ApplicationName>:<ToolMethodName>[:<args>].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     <ZopeAdmin> is the userName of the Zope administrator for this instance.
 | 
					     <ZopeAdmin> is the userName of the Zope administrator for this instance.
 | 
				
			||||||
     <PloneInstancePath> is the path, within Zope, to the Plone Site object (if
 | 
					     <PloneInstancePath> is the path, within Zope, to the Plone Site object (if
 | 
				
			||||||
                         not at the root of the Zope hierarchy, use '/' as
 | 
					                         not at the root of the Zope hierarchy, use '/' as
 | 
				
			||||||
                         folder separator);
 | 
					                         folder separator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     <ApplicationName> is the name of the Appy application;
 | 
					     <ApplicationName> is the name of the Appy application. If it begins with
 | 
				
			||||||
 | 
					                       "path=", it does not represent an Appy application, but
 | 
				
			||||||
 | 
					                       the path, within <PloneInstancePath>, to any Zope object
 | 
				
			||||||
 | 
					                       (use '/' as folder separator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     <ToolMethodName> is the name of the method to call on the tool in this
 | 
					     <ToolMethodName> is the name of the method to call on the tool in this
 | 
				
			||||||
                      Appy application;
 | 
					                      Appy application, or the method to call on the arbitrary
 | 
				
			||||||
 | 
					                      Zope object if previous param starts with "path=".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     <args> (optional) are the arguments to give to this method (only strings
 | 
					     <args> (optional) are the arguments to give to this method (only strings
 | 
				
			||||||
            are supported). Several arguments must be separated by '*'.'''
 | 
					            are supported). Several arguments must be separated by '*'.'''
 | 
				
			||||||
| 
						 | 
					@ -43,18 +47,24 @@ else:
 | 
				
			||||||
        from AccessControl.SecurityManagement import newSecurityManager
 | 
					        from AccessControl.SecurityManagement import newSecurityManager
 | 
				
			||||||
        user = app.acl_users.getUserById(zopeUser)
 | 
					        user = app.acl_users.getUserById(zopeUser)
 | 
				
			||||||
        if not hasattr(user, 'aq_base'):
 | 
					        if not hasattr(user, 'aq_base'):
 | 
				
			||||||
            user = user.__of__(uf)
 | 
					            user = user.__of__(app.acl_users)
 | 
				
			||||||
        newSecurityManager(None, user)
 | 
					        newSecurityManager(None, user)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Get the Plone site
 | 
					        # Get the Plone site
 | 
				
			||||||
        ploneSite = app # Initialised with the Zope root object.
 | 
					        ploneSite = app # Initialised with the Zope root object.
 | 
				
			||||||
        for elem in plonePath.split('/'):
 | 
					        for elem in plonePath.split('/'):
 | 
				
			||||||
            ploneSite = getattr(ploneSite, elem)
 | 
					            ploneSite = getattr(ploneSite, elem)
 | 
				
			||||||
        # Get the tool corresponding to the Appy application
 | 
					        # If we are in a Appy application, the object on which we will call the
 | 
				
			||||||
        toolName = 'portal_%s' % appName.lower()
 | 
					        # method is the tool within this application.
 | 
				
			||||||
        tool = getattr(ploneSite, toolName).appy()
 | 
					        if not appName.startswith('path='):
 | 
				
			||||||
        # Execute the method on the tool
 | 
					            objectName = 'portal_%s' % appName.lower()
 | 
				
			||||||
 | 
					            targetObject = getattr(ploneSite, objectName).appy()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # It can be any object within the Plone site.
 | 
				
			||||||
 | 
					            targetObject = ploneSite
 | 
				
			||||||
 | 
					            for elem in appName[5:].split('/'):
 | 
				
			||||||
 | 
					                targetObject = getattr(targetObject, elem)
 | 
				
			||||||
 | 
					        # Execute the method on the target object
 | 
				
			||||||
        if args: args = args.split('*')
 | 
					        if args: args = args.split('*')
 | 
				
			||||||
        exec 'tool.%s(*args)' % toolMethod
 | 
					        exec 'targetObject.%s(*args)' % toolMethod
 | 
				
			||||||
        transaction.commit()
 | 
					        transaction.commit()
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
0.5.5
 | 
					0.6.0
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1027
									
								
								gen/__init__.py
									
										
									
									
									
								
							
							
						
						| 
						 | 
					@ -4,10 +4,13 @@ from appy.gen import State, Transition, Type
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class Descriptor: # Abstract
 | 
					class Descriptor: # Abstract
 | 
				
			||||||
    def __init__(self, klass, orderedAttributes, generator):
 | 
					    def __init__(self, klass, orderedAttributes, generator):
 | 
				
			||||||
        self.klass = klass # The corresponding Python class
 | 
					        # The corresponding Python class
 | 
				
			||||||
        self.orderedAttributes = orderedAttributes # Names of the static appy-
 | 
					        self.klass = klass
 | 
				
			||||||
        # compliant attributes declared in self.klass
 | 
					        # The names of the static appy-compliant attributes declared in
 | 
				
			||||||
        self.generator = generator # A reference to the code generator.
 | 
					        # self.klass
 | 
				
			||||||
 | 
					        self.orderedAttributes = orderedAttributes
 | 
				
			||||||
 | 
					        # A reference to the code generator.
 | 
				
			||||||
 | 
					        self.generator = generator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __repr__(self): return '<Class %s>' % self.klass.__name__
 | 
					    def __repr__(self): return '<Class %s>' % self.klass.__name__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,14 +22,22 @@ class ClassDescriptor(Descriptor):
 | 
				
			||||||
           the condition will be returned. p_condition must be a string
 | 
					           the condition will be returned. p_condition must be a string
 | 
				
			||||||
           containing an expression that will be evaluated with, in its context,
 | 
					           containing an expression that will be evaluated with, in its context,
 | 
				
			||||||
           "self" being this ClassDescriptor and "attrValue" being the current
 | 
					           "self" being this ClassDescriptor and "attrValue" being the current
 | 
				
			||||||
           Type instance.'''
 | 
					           Type instance.
 | 
				
			||||||
        res = []
 | 
					           
 | 
				
			||||||
 | 
					           Order of returned attributes already takes into account type's
 | 
				
			||||||
 | 
					           "move" attributes.'''
 | 
				
			||||||
 | 
					        attrs = []
 | 
				
			||||||
        # First, get the attributes for the current class
 | 
					        # First, get the attributes for the current class
 | 
				
			||||||
        for attrName in self.orderedAttributes:
 | 
					        for attrName in self.orderedAttributes:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
                attrValue = getattr(self.klass, attrName)
 | 
					                attrValue = getattr(self.klass, attrName)
 | 
				
			||||||
 | 
					                hookClass = self.klass
 | 
				
			||||||
 | 
					            except AttributeError:
 | 
				
			||||||
 | 
					                attrValue = getattr(self.modelClass, attrName)
 | 
				
			||||||
 | 
					                hookClass = self.modelClass
 | 
				
			||||||
            if isinstance(attrValue, Type):
 | 
					            if isinstance(attrValue, Type):
 | 
				
			||||||
                if not condition or eval(condition):
 | 
					                if not condition or eval(condition):
 | 
				
			||||||
                    res.append( (attrName, attrValue) )
 | 
					                    attrs.append( (attrName, attrValue, hookClass) )
 | 
				
			||||||
        # Then, add attributes from parent classes
 | 
					        # Then, add attributes from parent classes
 | 
				
			||||||
        for baseClass in self.klass.__bases__:
 | 
					        for baseClass in self.klass.__bases__:
 | 
				
			||||||
            # Find the classDescr that corresponds to baseClass
 | 
					            # Find the classDescr that corresponds to baseClass
 | 
				
			||||||
| 
						 | 
					@ -36,7 +47,17 @@ class ClassDescriptor(Descriptor):
 | 
				
			||||||
                    baseClassDescr = classDescr
 | 
					                    baseClassDescr = classDescr
 | 
				
			||||||
                    break
 | 
					                    break
 | 
				
			||||||
            if baseClassDescr:
 | 
					            if baseClassDescr:
 | 
				
			||||||
                res = baseClassDescr.getOrderedAppyAttributes() + res
 | 
					                attrs = baseClassDescr.getOrderedAppyAttributes() + attrs
 | 
				
			||||||
 | 
					        # Modify attributes order by using "move" attributes
 | 
				
			||||||
 | 
					        res = []
 | 
				
			||||||
 | 
					        for name, appyType, klass in attrs:
 | 
				
			||||||
 | 
					            if appyType.move:
 | 
				
			||||||
 | 
					                newPosition = len(res) - abs(appyType.move)
 | 
				
			||||||
 | 
					                if newPosition <= 0:
 | 
				
			||||||
 | 
					                    newPosition = 0
 | 
				
			||||||
 | 
					                res.insert(newPosition, (name, appyType, klass))
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                res.append((name, appyType, klass))
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getChildren(self):
 | 
					    def getChildren(self):
 | 
				
			||||||
| 
						 | 
					@ -51,7 +72,7 @@ class ClassDescriptor(Descriptor):
 | 
				
			||||||
    def getPhases(self):
 | 
					    def getPhases(self):
 | 
				
			||||||
        '''Gets the phases defined on fields of this class.'''
 | 
					        '''Gets the phases defined on fields of this class.'''
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        for fieldName, appyType in self.getOrderedAppyAttributes():
 | 
					        for fieldName, appyType, klass in self.getOrderedAppyAttributes():
 | 
				
			||||||
            if appyType.phase not in res:
 | 
					            if appyType.phase not in res:
 | 
				
			||||||
                res.append(appyType.phase)
 | 
					                res.append(appyType.phase)
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -131,14 +131,9 @@ class Generator:
 | 
				
			||||||
        if not os.path.exists(self.templatesFolder):
 | 
					        if not os.path.exists(self.templatesFolder):
 | 
				
			||||||
            print WARN_NO_TEMPLATE % self.templatesFolder
 | 
					            print WARN_NO_TEMPLATE % self.templatesFolder
 | 
				
			||||||
        # Default descriptor classes
 | 
					        # Default descriptor classes
 | 
				
			||||||
        self.classDescriptor = ClassDescriptor
 | 
					        self.descriptorClasses = {
 | 
				
			||||||
        self.workflowDescriptor = WorkflowDescriptor
 | 
					            'class': ClassDescriptor, 'tool': ClassDescriptor,
 | 
				
			||||||
        self.customToolClassDescriptor = ClassDescriptor
 | 
					            'flavour': ClassDescriptor, 'workflow': WorkflowDescriptor}
 | 
				
			||||||
        self.customFlavourClassDescriptor = ClassDescriptor
 | 
					 | 
				
			||||||
        # Custom tool and flavour classes, if they are defined in the
 | 
					 | 
				
			||||||
        # application
 | 
					 | 
				
			||||||
        self.customToolDescr = None
 | 
					 | 
				
			||||||
        self.customFlavourDescr = None
 | 
					 | 
				
			||||||
        # The following dict contains a series of replacements that need to be
 | 
					        # The following dict contains a series of replacements that need to be
 | 
				
			||||||
        # applied to file templates to generate files.
 | 
					        # applied to file templates to generate files.
 | 
				
			||||||
        self.repls = {'applicationName': self.applicationName,
 | 
					        self.repls = {'applicationName': self.applicationName,
 | 
				
			||||||
| 
						 | 
					@ -146,6 +141,8 @@ class Generator:
 | 
				
			||||||
                      'codeHeader': CODE_HEADER}
 | 
					                      'codeHeader': CODE_HEADER}
 | 
				
			||||||
        # List of Appy classes and workflows found in the application
 | 
					        # List of Appy classes and workflows found in the application
 | 
				
			||||||
        self.classes = []
 | 
					        self.classes = []
 | 
				
			||||||
 | 
					        self.tool = None
 | 
				
			||||||
 | 
					        self.flavour = None
 | 
				
			||||||
        self.workflows = []
 | 
					        self.workflows = []
 | 
				
			||||||
        self.initialize()
 | 
					        self.initialize()
 | 
				
			||||||
        self.config = Config.getDefault()
 | 
					        self.config = Config.getDefault()
 | 
				
			||||||
| 
						 | 
					@ -225,24 +222,30 @@ class Generator:
 | 
				
			||||||
                    # of their definition).
 | 
					                    # of their definition).
 | 
				
			||||||
                    attrs = astClasses[moduleElem.__name__].attributes
 | 
					                    attrs = astClasses[moduleElem.__name__].attributes
 | 
				
			||||||
                    if appyType == 'class':
 | 
					                    if appyType == 'class':
 | 
				
			||||||
 | 
					                        # Determine the class type (standard, tool, flavour...)
 | 
				
			||||||
                        if issubclass(moduleElem, Tool):
 | 
					                        if issubclass(moduleElem, Tool):
 | 
				
			||||||
                            descrClass = self.customToolClassDescriptor
 | 
					                            if not self.tool:
 | 
				
			||||||
                            self.customToolDescr = descrClass(
 | 
					                                klass = self.descriptorClasses['tool']
 | 
				
			||||||
                                moduleElem, attrs, self)
 | 
					                                self.tool = klass(moduleElem, attrs, self)
 | 
				
			||||||
                        elif issubclass(moduleElem, Flavour):
 | 
					 | 
				
			||||||
                            descrClass = self.customFlavourClassDescriptor
 | 
					 | 
				
			||||||
                            self.customFlavourDescr = descrClass(
 | 
					 | 
				
			||||||
                                moduleElem, attrs, self)
 | 
					 | 
				
			||||||
                            else:
 | 
					                            else:
 | 
				
			||||||
                            descrClass = self.classDescriptor
 | 
					                                self.tool.update(moduleElem, attrs)
 | 
				
			||||||
                            self.classes.append(
 | 
					                        elif issubclass(moduleElem, Flavour):
 | 
				
			||||||
                                descrClass(moduleElem, attrs, self))
 | 
					                            if not self.flavour:
 | 
				
			||||||
 | 
					                                klass = self.descriptorClasses['flavour']
 | 
				
			||||||
 | 
					                                self.flavour = klass(moduleElem, attrs, self)
 | 
				
			||||||
 | 
					                            else:
 | 
				
			||||||
 | 
					                                self.flavour.update(moduleElem, attrs)
 | 
				
			||||||
 | 
					                        else:
 | 
				
			||||||
 | 
					                            descriptorClass = self.descriptorClasses['class']
 | 
				
			||||||
 | 
					                            descriptor = descriptorClass(moduleElem,attrs, self)
 | 
				
			||||||
 | 
					                            self.classes.append(descriptor)
 | 
				
			||||||
 | 
					                        # Manage classes containing tests
 | 
				
			||||||
                        if self.containsTests(moduleElem):
 | 
					                        if self.containsTests(moduleElem):
 | 
				
			||||||
                            self.modulesWithTests.add(moduleObj.__name__)
 | 
					                            self.modulesWithTests.add(moduleObj.__name__)
 | 
				
			||||||
                    elif appyType == 'workflow':
 | 
					                    elif appyType == 'workflow':
 | 
				
			||||||
                        descrClass = self.workflowDescriptor
 | 
					                        descriptorClass = self.descriptorClasses['workflow']
 | 
				
			||||||
                        self.workflows.append(
 | 
					                        descriptor = descriptorClass(moduleElem, attrs, self)
 | 
				
			||||||
                            descrClass(moduleElem, attrs, self))
 | 
					                        self.workflows.append(descriptor)
 | 
				
			||||||
                        if self.containsTests(moduleElem):
 | 
					                        if self.containsTests(moduleElem):
 | 
				
			||||||
                            self.modulesWithTests.add(moduleObj.__name__)
 | 
					                            self.modulesWithTests.add(moduleObj.__name__)
 | 
				
			||||||
            elif isinstance(moduleElem, Config):
 | 
					            elif isinstance(moduleElem, Config):
 | 
				
			||||||
| 
						 | 
					@ -331,8 +334,8 @@ class Generator:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def run(self):
 | 
					    def run(self):
 | 
				
			||||||
        self.walkApplication()
 | 
					        self.walkApplication()
 | 
				
			||||||
        for classDescr in self.classes: self.generateClass(classDescr)
 | 
					        for descriptor in self.classes: self.generateClass(descriptor)
 | 
				
			||||||
        for wfDescr in self.workflows: self.generateWorkflow(wfDescr)
 | 
					        for descriptor in self.workflows: self.generateWorkflow(descriptor)
 | 
				
			||||||
        self.finalize()
 | 
					        self.finalize()
 | 
				
			||||||
        msg = ''
 | 
					        msg = ''
 | 
				
			||||||
        if self.totalNumberOfTests:
 | 
					        if self.totalNumberOfTests:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										188
									
								
								gen/layout.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,188 @@
 | 
				
			||||||
 | 
					'''This module contains classes used for layouting graphical elements
 | 
				
			||||||
 | 
					   (fields, widgets, groups, ...).'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# A layout defines how a given field is rendered in a given context. Several
 | 
				
			||||||
 | 
					# contexts exist:
 | 
				
			||||||
 | 
					#  "view"   represents a given page for a given Appy class, in read-only mode.
 | 
				
			||||||
 | 
					#  "edit"   represents a given page for a given Appy class, in edit mode.
 | 
				
			||||||
 | 
					#  "cell"   represents a cell in a table, like when we need to render a field
 | 
				
			||||||
 | 
					#           value in a query result or in a reference table.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Layout elements for a class or page ------------------------------------------
 | 
				
			||||||
 | 
					#  s - The page summary, containing summarized information about the page or
 | 
				
			||||||
 | 
					#      class, workflow information and object history.
 | 
				
			||||||
 | 
					#  w - The widgets of the current page/class
 | 
				
			||||||
 | 
					#  n - The navigation panel (inter-objects navigation)
 | 
				
			||||||
 | 
					#  b - The range of buttons (intra-object navigation, save, edit, delete...)
 | 
				
			||||||
 | 
					#  m - The global status message sometimes shown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Layout elements for a field --------------------------------------------------
 | 
				
			||||||
 | 
					#  l -  "label"        The field label
 | 
				
			||||||
 | 
					#  d -  "description"  The field description (a description is always visible)
 | 
				
			||||||
 | 
					#  h -  "help"         Help for the field (typically rendered as an icon,
 | 
				
			||||||
 | 
					#                       clicking on it shows a popup with online help
 | 
				
			||||||
 | 
					#  v -  "validation"   The icon that is shown when a validation error occurs
 | 
				
			||||||
 | 
					#                       (typically only used on "edit" layouts)
 | 
				
			||||||
 | 
					#  r -  "required"     The icon that specified that the field is required (if
 | 
				
			||||||
 | 
					#                       relevant; typically only used on "edit" layouts)
 | 
				
			||||||
 | 
					#  f -  "field"        The field value, or input for entering a value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# For every field of a Appy class, you can define, for every layout context,
 | 
				
			||||||
 | 
					# what field-related information will appear, and how it will be rendered.
 | 
				
			||||||
 | 
					# Variables defaultPageLayouts and defaultFieldLayouts defined below give the
 | 
				
			||||||
 | 
					# default layouts for pages and fields respectively.
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
 | 
					# How to express a layout? You simply define a string that is made of the
 | 
				
			||||||
 | 
					# letters corresponding to the field elements you want to render. The order of
 | 
				
			||||||
 | 
					# elements correspond to the order into which they will be rendered.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					rowDelimiters =  {'-':'middle', '=':'top', '_':'bottom'}
 | 
				
			||||||
 | 
					cellDelimiters = {'|': 'center', ';': 'left', '!': 'right'}
 | 
				
			||||||
 | 
					macroDict = {
 | 
				
			||||||
 | 
					  # Page-related elements
 | 
				
			||||||
 | 
					  's': ('page', 'header'), 'w': ('page', 'widgets'),
 | 
				
			||||||
 | 
					  'n': ('navigate', 'objectNavigate'), 'b': ('page', 'buttons'),
 | 
				
			||||||
 | 
					  'm': ('page', 'message'),
 | 
				
			||||||
 | 
					  # Field-related elements
 | 
				
			||||||
 | 
					  'l': ('show', 'label'), 'd': ('show', 'description'),
 | 
				
			||||||
 | 
					  'h': ('show', 'help'),  'v': ('show', 'validation'),
 | 
				
			||||||
 | 
					  'r': ('show', 'required')
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class LayoutElement:
 | 
				
			||||||
 | 
					    '''Abstract base class for any layout element.'''
 | 
				
			||||||
 | 
					    def get(self): return self.__dict__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Cell(LayoutElement):
 | 
				
			||||||
 | 
					    '''Represents a cell in a row in a table.'''
 | 
				
			||||||
 | 
					    def __init__(self, content, align, isHeader=False):
 | 
				
			||||||
 | 
					        self.align = align
 | 
				
			||||||
 | 
					        self.width = None
 | 
				
			||||||
 | 
					        self.content = None
 | 
				
			||||||
 | 
					        self.colspan = 1
 | 
				
			||||||
 | 
					        if isHeader:
 | 
				
			||||||
 | 
					            self.width = content
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.content = [] # The list of widgets to render in the cell
 | 
				
			||||||
 | 
					            self.decodeContent(content)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def decodeContent(self, content):
 | 
				
			||||||
 | 
					        digits = '' # We collect the digits that will give the colspan
 | 
				
			||||||
 | 
					        for char in content:
 | 
				
			||||||
 | 
					            if char.isdigit():
 | 
				
			||||||
 | 
					                digits += char
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                # It is a letter corresponding to a macro
 | 
				
			||||||
 | 
					                if char in macroDict:
 | 
				
			||||||
 | 
					                    self.content.append(macroDict[char])
 | 
				
			||||||
 | 
					                elif char == 'f':
 | 
				
			||||||
 | 
					                    # The exact macro to call will be known at render-time
 | 
				
			||||||
 | 
					                    self.content.append('?')
 | 
				
			||||||
 | 
					        # Manage the colspan
 | 
				
			||||||
 | 
					        if digits:
 | 
				
			||||||
 | 
					            self.colspan = int(digits)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class Row(LayoutElement):
 | 
				
			||||||
 | 
					    '''Represents a row in a table.'''
 | 
				
			||||||
 | 
					    def __init__(self, content, valign, isHeader=False):
 | 
				
			||||||
 | 
					        self.valign = valign
 | 
				
			||||||
 | 
					        self.cells = []
 | 
				
			||||||
 | 
					        self.decodeCells(content, isHeader)
 | 
				
			||||||
 | 
					        # Compute the row length
 | 
				
			||||||
 | 
					        length = 0
 | 
				
			||||||
 | 
					        for cell in self.cells:
 | 
				
			||||||
 | 
					            length += cell['colspan']
 | 
				
			||||||
 | 
					        self.length = length
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def decodeCells(self, content, isHeader):
 | 
				
			||||||
 | 
					        '''Decodes the given chunk of layout string p_content containing
 | 
				
			||||||
 | 
					           column-related information (if p_isHeader is True) or cell content
 | 
				
			||||||
 | 
					           (if p_isHeader is False) and produces a list of Cell instances.'''
 | 
				
			||||||
 | 
					        cellContent = ''
 | 
				
			||||||
 | 
					        for char in content:
 | 
				
			||||||
 | 
					            if char in cellDelimiters:
 | 
				
			||||||
 | 
					                align = cellDelimiters[char]
 | 
				
			||||||
 | 
					                self.cells.append(Cell(cellContent, align, isHeader).get())
 | 
				
			||||||
 | 
					                cellContent = ''
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                cellContent += char
 | 
				
			||||||
 | 
					        # Manage the last cell if any
 | 
				
			||||||
 | 
					        if cellContent:
 | 
				
			||||||
 | 
					            self.cells.append(Cell(cellContent, 'left', isHeader).get())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class Table(LayoutElement):
 | 
				
			||||||
 | 
					    '''Represents a table where to dispose graphical elements.'''
 | 
				
			||||||
 | 
					    def __init__(self, layoutString, style=None, css_class='', cellpadding=0,
 | 
				
			||||||
 | 
					                 cellspacing=0, width='100%', align='left'):
 | 
				
			||||||
 | 
					        self.style = style
 | 
				
			||||||
 | 
					        self.css_class = css_class
 | 
				
			||||||
 | 
					        self.cellpadding = cellpadding
 | 
				
			||||||
 | 
					        self.cellspacing = cellspacing
 | 
				
			||||||
 | 
					        self.width = width
 | 
				
			||||||
 | 
					        self.align = align
 | 
				
			||||||
 | 
					        # The following attribute will store a special Row instance used for
 | 
				
			||||||
 | 
					        # defining column properties.
 | 
				
			||||||
 | 
					        self.headerRow = None
 | 
				
			||||||
 | 
					        # The content rows are stored hereafter.
 | 
				
			||||||
 | 
					        self.rows = []
 | 
				
			||||||
 | 
					        self.layoutString = layoutString
 | 
				
			||||||
 | 
					        self.decodeRows(layoutString)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def addCssClasses(self, css_class):
 | 
				
			||||||
 | 
					        '''Adds a single or a group of p_css_class.'''
 | 
				
			||||||
 | 
					        classes = self.css_class
 | 
				
			||||||
 | 
					        if classes == None:
 | 
				
			||||||
 | 
					            classes = ''
 | 
				
			||||||
 | 
					        if not classes:
 | 
				
			||||||
 | 
					            self.css_class = css_class
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.css_class += ' ' + css_classes
 | 
				
			||||||
 | 
					            # Ensures that every class appears once
 | 
				
			||||||
 | 
					            self.css_class = ' '.join(set(self.css_class.split()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def isHeaderRow(self, rowContent):
 | 
				
			||||||
 | 
					        '''Determines if p_rowContent specified the table header row or a
 | 
				
			||||||
 | 
					           content row.'''
 | 
				
			||||||
 | 
					        # Find the first char that is a number or a letter
 | 
				
			||||||
 | 
					        for char in rowContent:
 | 
				
			||||||
 | 
					            if char not in cellDelimiters:
 | 
				
			||||||
 | 
					                if char.isdigit(): return True
 | 
				
			||||||
 | 
					                else:              return False
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def decodeRows(self, layoutString):
 | 
				
			||||||
 | 
					        '''Decodes the given p_layoutString and produces a list of Row
 | 
				
			||||||
 | 
					           instances.'''
 | 
				
			||||||
 | 
					        # Split the p_layoutString with the row delimiters
 | 
				
			||||||
 | 
					        rowContent = ''
 | 
				
			||||||
 | 
					        for char in layoutString:
 | 
				
			||||||
 | 
					            if char in rowDelimiters:
 | 
				
			||||||
 | 
					                valign = rowDelimiters[char]
 | 
				
			||||||
 | 
					                if self.isHeaderRow(rowContent):
 | 
				
			||||||
 | 
					                    self.headerRow = Row(rowContent,valign,isHeader=True).get()
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    self.rows.append(Row(rowContent, valign).get())
 | 
				
			||||||
 | 
					                rowContent = ''
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                rowContent += char
 | 
				
			||||||
 | 
					        # Manage the last row if any
 | 
				
			||||||
 | 
					        if rowContent:
 | 
				
			||||||
 | 
					            self.rows.append(Row(rowContent, 'middle').get())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def removeElement(self, elem):
 | 
				
			||||||
 | 
					        '''Removes given p_elem from myself.'''
 | 
				
			||||||
 | 
					        macroToRemove = macroDict[elem]
 | 
				
			||||||
 | 
					        for row in self.rows:
 | 
				
			||||||
 | 
					            for cell in row['cells']:
 | 
				
			||||||
 | 
					                if macroToRemove in cell['content']:
 | 
				
			||||||
 | 
					                    cell['content'].remove(macroToRemove)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					defaultPageLayouts  = {
 | 
				
			||||||
 | 
					    'view': Table('m;-s|-n!-w;-b|'), 'edit': Table('m;-s|-n!-w;-b|')}
 | 
				
			||||||
 | 
					defaultFieldLayouts = {'view': 'l;f!', 'edit': 'lrv;f!'}
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
           into the ODT file. This method returns the list of "dumpable"
 | 
					           into the ODT file. This method returns the list of "dumpable"
 | 
				
			||||||
           fields.'''
 | 
					           fields.'''
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        for fieldName, field in classDescr.getOrderedAppyAttributes():
 | 
					        for fieldName, field, klass in classDescr.getOrderedAppyAttributes():
 | 
				
			||||||
            if (field.type not in self.undumpable) and \
 | 
					            if (field.type not in self.undumpable) and \
 | 
				
			||||||
               (not self.fieldIsStaticallyInvisible(field)):
 | 
					               (not self.fieldIsStaticallyInvisible(field)):
 | 
				
			||||||
                res.append((fieldName, field))
 | 
					                res.append((fieldName, field))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ from appy.gen.utils import GroupDescr, PageDescr, produceNiceMessage, \
 | 
				
			||||||
TABS = 4 # Number of blanks in a Python indentation.
 | 
					TABS = 4 # Number of blanks in a Python indentation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ArchetypeFieldDescriptor:
 | 
					class FieldDescriptor:
 | 
				
			||||||
    '''This class allows to gather information needed to generate an Archetypes
 | 
					    '''This class allows to gather information needed to generate an Archetypes
 | 
				
			||||||
       definition (field + widget) from an Appy type. An Appy type is used for
 | 
					       definition (field + widget) from an Appy type. An Appy type is used for
 | 
				
			||||||
       defining the type of attributes defined in the user application.'''
 | 
					       defining the type of attributes defined in the user application.'''
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,6 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
        self.widgetParams = {}
 | 
					        self.widgetParams = {}
 | 
				
			||||||
        self.fieldType = None
 | 
					        self.fieldType = None
 | 
				
			||||||
        self.widgetType = None
 | 
					        self.widgetType = None
 | 
				
			||||||
        self.walkAppyType()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __repr__(self):
 | 
					    def __repr__(self):
 | 
				
			||||||
        return '<Field %s, %s>' % (self.fieldName, self.classDescr)
 | 
					        return '<Field %s, %s>' % (self.fieldName, self.classDescr)
 | 
				
			||||||
| 
						 | 
					@ -59,8 +58,8 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def produceMessage(self, msgId, isLabel=True):
 | 
					    def produceMessage(self, msgId, isLabel=True):
 | 
				
			||||||
        '''Gets the default label or description (if p_isLabel is False) for
 | 
					        '''Gets the default label, description or help (depending on p_msgType)
 | 
				
			||||||
           i18n message p_msgId.'''
 | 
					           for i18n message p_msgId.'''
 | 
				
			||||||
        default = ' '
 | 
					        default = ' '
 | 
				
			||||||
        produceNice = False
 | 
					        produceNice = False
 | 
				
			||||||
        if isLabel:
 | 
					        if isLabel:
 | 
				
			||||||
| 
						 | 
					@ -75,82 +74,22 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
            msg.produceNiceDefault()
 | 
					            msg.produceNiceDefault()
 | 
				
			||||||
        return msg
 | 
					        return msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def walkBasicType(self):
 | 
					 | 
				
			||||||
        '''How to dump a basic type?'''
 | 
					 | 
				
			||||||
        self.fieldType = '%sField' % self.appyType.type
 | 
					 | 
				
			||||||
        self.widgetType = "%sWidget" % self.appyType.type
 | 
					 | 
				
			||||||
        if self.appyType.type == 'Date':
 | 
					 | 
				
			||||||
            self.fieldType = 'DateTimeField'
 | 
					 | 
				
			||||||
            self.widgetType = 'CalendarWidget'
 | 
					 | 
				
			||||||
            if self.appyType.format == Date.WITHOUT_HOUR:
 | 
					 | 
				
			||||||
                self.widgetParams['show_hm'] = False
 | 
					 | 
				
			||||||
                self.widgetParams['starting_year'] = self.appyType.startYear
 | 
					 | 
				
			||||||
                self.widgetParams['ending_year'] = self.appyType.endYear
 | 
					 | 
				
			||||||
        elif self.appyType.type == 'Float':
 | 
					 | 
				
			||||||
            self.widgetType = 'DecimalWidget'
 | 
					 | 
				
			||||||
        elif self.appyType.type == 'File':
 | 
					 | 
				
			||||||
            if self.appyType.isImage:
 | 
					 | 
				
			||||||
                self.fieldType = 'ImageField'
 | 
					 | 
				
			||||||
                self.widgetType = 'ImageWidget'
 | 
					 | 
				
			||||||
            self.fieldParams['storage'] = 'python:AttributeStorage()'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def walkString(self):
 | 
					    def walkString(self):
 | 
				
			||||||
        '''How to generate an Appy String?'''
 | 
					        '''How to generate an Appy String?'''
 | 
				
			||||||
        if self.appyType.format == String.LINE:
 | 
					        if self.appyType.isSelect and \
 | 
				
			||||||
            if self.appyType.isSelection():
 | 
					           (type(self.appyType.validator) in (list, tuple)):
 | 
				
			||||||
                if self.appyType.isMultiValued():
 | 
					            # Generate i18n messages for every possible value if the list
 | 
				
			||||||
                    self.fieldType = 'LinesField'
 | 
					            # of values is fixed.
 | 
				
			||||||
                    self.widgetType = 'MultiSelectionWidget'
 | 
					            for value in self.appyType.validator:
 | 
				
			||||||
                    self.fieldParams['multiValued'] = True
 | 
					                msgLabel = '%s_%s_list_%s' % (self.classDescr.name,
 | 
				
			||||||
                    if (type(self.appyType.validator) in sequenceTypes) and \
 | 
					                    self.fieldName, value)
 | 
				
			||||||
                        len(self.appyType.validator) <= 5:
 | 
					                poMsg = PoMessage(msgLabel, '', value)
 | 
				
			||||||
                        self.widgetParams['format'] = 'checkbox'
 | 
					                poMsg.produceNiceDefault()
 | 
				
			||||||
                else:
 | 
					                self.generator.labels.append(poMsg)
 | 
				
			||||||
                    self.fieldType = 'StringField'
 | 
					 | 
				
			||||||
                    self.widgetType = 'SelectionWidget'
 | 
					 | 
				
			||||||
                    self.widgetParams['format'] = 'select'
 | 
					 | 
				
			||||||
                # Elements common to all selection fields
 | 
					 | 
				
			||||||
                methodName = 'list_%s_values' % self.fieldName
 | 
					 | 
				
			||||||
                self.fieldParams['vocabulary'] = methodName
 | 
					 | 
				
			||||||
                self.classDescr.addSelectMethod(methodName, self)
 | 
					 | 
				
			||||||
                self.fieldParams['enforceVocabulary'] = True
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                self.fieldType = 'StringField'
 | 
					 | 
				
			||||||
                self.widgetType = 'StringWidget'
 | 
					 | 
				
			||||||
                self.widgetParams['size'] = 50
 | 
					 | 
				
			||||||
                if self.appyType.width:
 | 
					 | 
				
			||||||
                    self.widgetParams['size'] = self.appyType.width
 | 
					 | 
				
			||||||
        elif self.appyType.format == String.TEXT:
 | 
					 | 
				
			||||||
            self.fieldType = 'TextField'
 | 
					 | 
				
			||||||
            self.widgetType = 'TextAreaWidget'
 | 
					 | 
				
			||||||
            if self.appyType.height:
 | 
					 | 
				
			||||||
                self.widgetParams['rows'] = self.appyType.height
 | 
					 | 
				
			||||||
        elif self.appyType.format == String.XHTML:
 | 
					 | 
				
			||||||
            self.fieldType = 'TextField'
 | 
					 | 
				
			||||||
            self.widgetType = 'RichWidget'
 | 
					 | 
				
			||||||
            self.fieldParams['allowable_content_types'] = ('text/html',)
 | 
					 | 
				
			||||||
            self.fieldParams['default_output_type'] = "text/html"
 | 
					 | 
				
			||||||
        elif self.appyType.format == String.PASSWORD:
 | 
					 | 
				
			||||||
            self.fieldType = 'StringField'
 | 
					 | 
				
			||||||
            self.widgetType = 'PasswordWidget'
 | 
					 | 
				
			||||||
            if self.appyType.width:
 | 
					 | 
				
			||||||
                self.widgetParams['size'] = self.appyType.width
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def walkComputed(self):
 | 
					 | 
				
			||||||
        '''How to generate a computed field? We generate an Archetypes String
 | 
					 | 
				
			||||||
           field.'''
 | 
					 | 
				
			||||||
        self.fieldType = 'StringField'
 | 
					 | 
				
			||||||
        self.widgetType = 'StringWidget'
 | 
					 | 
				
			||||||
        self.widgetParams['visible'] = False # Archetypes will believe the
 | 
					 | 
				
			||||||
        # field is invisible; we will display it ourselves (like for Ref fields)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def walkAction(self):
 | 
					    def walkAction(self):
 | 
				
			||||||
        '''How to generate an action field ? We generate an Archetypes String
 | 
					        '''How to generate an action field ? We generate an Archetypes String
 | 
				
			||||||
           field.'''
 | 
					           field.'''
 | 
				
			||||||
        self.fieldType = 'StringField'
 | 
					 | 
				
			||||||
        self.widgetType = 'StringWidget'
 | 
					 | 
				
			||||||
        self.widgetParams['visible'] = False # Archetypes will believe the
 | 
					 | 
				
			||||||
        # field is invisible; we will display it ourselves (like for Ref fields)
 | 
					 | 
				
			||||||
        # Add action-specific i18n messages
 | 
					        # Add action-specific i18n messages
 | 
				
			||||||
        for suffix in ('ok', 'ko'):
 | 
					        for suffix in ('ok', 'ko'):
 | 
				
			||||||
            label = '%s_%s_action_%s' % (self.classDescr.name, self.fieldName,
 | 
					            label = '%s_%s_action_%s' % (self.classDescr.name, self.fieldName,
 | 
				
			||||||
| 
						 | 
					@ -168,36 +107,22 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
        self.fieldParams['relationship'] = relationship
 | 
					        self.fieldParams['relationship'] = relationship
 | 
				
			||||||
        if self.appyType.isMultiValued():
 | 
					        if self.appyType.isMultiValued():
 | 
				
			||||||
            self.fieldParams['multiValued'] = True
 | 
					            self.fieldParams['multiValued'] = True
 | 
				
			||||||
        self.widgetParams['visible'] = False
 | 
					 | 
				
			||||||
        # Update the list of referers
 | 
					        # Update the list of referers
 | 
				
			||||||
        self.generator.addReferer(self, relationship)
 | 
					        self.generator.addReferer(self, relationship)
 | 
				
			||||||
        # Add the widget label for the back reference
 | 
					        # Add the widget label for the back reference
 | 
				
			||||||
        refClassName = ArchetypesClassDescriptor.getClassName(
 | 
					        refClassName = ClassDescriptor.getClassName(self.appyType.klass)
 | 
				
			||||||
            self.appyType.klass)
 | 
					 | 
				
			||||||
        if issubclass(self.appyType.klass, ModelClass):
 | 
					        if issubclass(self.appyType.klass, ModelClass):
 | 
				
			||||||
            refClassName = self.applicationName + self.appyType.klass.__name__
 | 
					            refClassName = self.applicationName + self.appyType.klass.__name__
 | 
				
			||||||
        elif issubclass(self.appyType.klass, appy.gen.Tool):
 | 
					        elif issubclass(self.appyType.klass, appy.gen.Tool):
 | 
				
			||||||
            refClassName = '%sTool' % self.applicationName
 | 
					            refClassName = '%sTool' % self.applicationName
 | 
				
			||||||
        elif issubclass(self.appyType.klass, appy.gen.Flavour):
 | 
					        elif issubclass(self.appyType.klass, appy.gen.Flavour):
 | 
				
			||||||
            refClassName = '%sFlavour' % self.applicationName
 | 
					            refClassName = '%sFlavour' % self.applicationName
 | 
				
			||||||
        backLabel = "%s_%s_back" % (refClassName, self.appyType.back.attribute)
 | 
					        backLabel = "%s_%s" % (refClassName, self.appyType.back.attribute)
 | 
				
			||||||
        poMsg = PoMessage(backLabel, '', self.appyType.back.attribute)
 | 
					        poMsg = PoMessage(backLabel, '', self.appyType.back.attribute)
 | 
				
			||||||
        poMsg.produceNiceDefault()
 | 
					        poMsg.produceNiceDefault()
 | 
				
			||||||
        self.generator.labels.append(poMsg)
 | 
					        self.generator.labels.append(poMsg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def walkInfo(self):
 | 
					 | 
				
			||||||
        '''How to generate an Info field? We generate an Archetypes String
 | 
					 | 
				
			||||||
           field.'''
 | 
					 | 
				
			||||||
        self.fieldType = 'StringField'
 | 
					 | 
				
			||||||
        self.widgetType = 'StringWidget'
 | 
					 | 
				
			||||||
        self.widgetParams['visible'] = False # Archetypes will believe the
 | 
					 | 
				
			||||||
        # field is invisible; we will display it ourselves (like for Ref fields)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def walkPod(self):
 | 
					    def walkPod(self):
 | 
				
			||||||
        '''How to dump a Pod type?'''
 | 
					 | 
				
			||||||
        self.fieldType = 'FileField'
 | 
					 | 
				
			||||||
        self.widgetType = 'FileWidget'
 | 
					 | 
				
			||||||
        self.fieldParams['storage'] = 'python:AttributeStorage()'
 | 
					 | 
				
			||||||
        # Add i18n-specific messages
 | 
					        # Add i18n-specific messages
 | 
				
			||||||
        if self.appyType.askAction:
 | 
					        if self.appyType.askAction:
 | 
				
			||||||
            label = '%s_%s_askaction' % (self.classDescr.name, self.fieldName)
 | 
					            label = '%s_%s_askaction' % (self.classDescr.name, self.fieldName)
 | 
				
			||||||
| 
						 | 
					@ -207,47 +132,23 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
        # Add the POD-related fields on the Flavour
 | 
					        # Add the POD-related fields on the Flavour
 | 
				
			||||||
        Flavour._appy_addPodRelatedFields(self)
 | 
					        Flavour._appy_addPodRelatedFields(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    alwaysAValidatorFor = ('Ref', 'Integer', 'Float')
 | 
					 | 
				
			||||||
    notToValidateFields = ('Info', 'Computed', 'Action', 'Pod')
 | 
					    notToValidateFields = ('Info', 'Computed', 'Action', 'Pod')
 | 
				
			||||||
    def walkAppyType(self):
 | 
					    def walkAppyType(self):
 | 
				
			||||||
        '''Walks into the Appy type definition and gathers data about the
 | 
					        '''Walks into the Appy type definition and gathers data about the
 | 
				
			||||||
           Archetype elements to generate.'''
 | 
					           i18n labels.'''
 | 
				
			||||||
        # Manage things common to all Appy types
 | 
					        # Manage things common to all Appy types
 | 
				
			||||||
        # - special accessor for fields "title" and "description"
 | 
					 | 
				
			||||||
        if self.fieldName in self.specialParams:
 | 
					 | 
				
			||||||
            self.fieldParams['accessor'] = self.fieldName.capitalize()
 | 
					 | 
				
			||||||
        # - default value
 | 
					 | 
				
			||||||
        if self.appyType.default != None:
 | 
					 | 
				
			||||||
            self.fieldParams['default'] = self.appyType.default
 | 
					 | 
				
			||||||
        # - required?
 | 
					 | 
				
			||||||
        if self.appyType.multiplicity[0] >= 1:
 | 
					 | 
				
			||||||
            if self.appyType.type != 'Ref': self.fieldParams['required'] = True
 | 
					 | 
				
			||||||
            # Indeed, if it is a ref appy will manage itself field updates in
 | 
					 | 
				
			||||||
            # onEdit, so Archetypes must not enforce required=True
 | 
					 | 
				
			||||||
        # - optional ?
 | 
					        # - optional ?
 | 
				
			||||||
        if self.appyType.optional:
 | 
					        if self.appyType.optional:
 | 
				
			||||||
            Flavour._appy_addOptionalField(self)
 | 
					            Flavour._appy_addOptionalField(self)
 | 
				
			||||||
            self.widgetParams['condition'] = ' python: ' \
 | 
					 | 
				
			||||||
                'here.fieldIsUsed("%s")'% self.fieldName
 | 
					 | 
				
			||||||
        # - edit default value ?
 | 
					        # - edit default value ?
 | 
				
			||||||
        if self.appyType.editDefault:
 | 
					        if self.appyType.editDefault:
 | 
				
			||||||
            Flavour._appy_addDefaultField(self)
 | 
					            Flavour._appy_addDefaultField(self)
 | 
				
			||||||
            methodName = 'getDefaultValueFor%s' % self.fieldName
 | 
					 | 
				
			||||||
            self.fieldParams['default_method'] = methodName
 | 
					 | 
				
			||||||
            self.classDescr.addDefaultMethod(methodName, self)
 | 
					 | 
				
			||||||
        # - put an index on this field?
 | 
					        # - put an index on this field?
 | 
				
			||||||
        if self.appyType.indexed:
 | 
					        if self.appyType.indexed and \
 | 
				
			||||||
            if (self.appyType.type == 'String') and (self.appyType.isSelect):
 | 
					           (self.fieldName not in ('title', 'description')):
 | 
				
			||||||
                self.fieldParams['index'] = 'ZCTextIndex, lexicon_id=' \
 | 
					            self.classDescr.addIndexMethod(self)
 | 
				
			||||||
                    'plone_lexicon, index_type=Okapi BM25 Rank'
 | 
					        # - searchable ? TODO
 | 
				
			||||||
            else:
 | 
					        #if self.appyType.searchable: self.fieldParams['searchable'] = True
 | 
				
			||||||
                self.fieldParams['index'] = 'FieldIndex'
 | 
					 | 
				
			||||||
        # - searchable ?
 | 
					 | 
				
			||||||
        if self.appyType.searchable: self.fieldParams['searchable'] = True
 | 
					 | 
				
			||||||
        # - slaves ?
 | 
					 | 
				
			||||||
        if self.appyType.slaves: self.widgetParams['visible'] = False
 | 
					 | 
				
			||||||
        # Archetypes will believe the field is invisible; we will display it
 | 
					 | 
				
			||||||
        # ourselves (like for Ref fields).
 | 
					 | 
				
			||||||
        # - need to generate a field validator?
 | 
					        # - need to generate a field validator?
 | 
				
			||||||
        # In all cases excepted for "immutable" fields, add an i18n message for
 | 
					        # In all cases excepted for "immutable" fields, add an i18n message for
 | 
				
			||||||
        # the validation error for this field.
 | 
					        # the validation error for this field.
 | 
				
			||||||
| 
						 | 
					@ -255,43 +156,18 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
            label = '%s_%s_valid' % (self.classDescr.name, self.fieldName)
 | 
					            label = '%s_%s_valid' % (self.classDescr.name, self.fieldName)
 | 
				
			||||||
            poMsg = PoMessage(label, '', PoMessage.DEFAULT_VALID_ERROR)
 | 
					            poMsg = PoMessage(label, '', PoMessage.DEFAULT_VALID_ERROR)
 | 
				
			||||||
            self.generator.labels.append(poMsg)
 | 
					            self.generator.labels.append(poMsg)
 | 
				
			||||||
        # Generate a validator for the field if needed.
 | 
					 | 
				
			||||||
        if (type(self.appyType.validator) == types.FunctionType) or \
 | 
					 | 
				
			||||||
           (type(self.appyType.validator) == type(String.EMAIL)) or \
 | 
					 | 
				
			||||||
           (self.appyType.type in self.alwaysAValidatorFor):
 | 
					 | 
				
			||||||
            # For references, we always add a validator because gen validates
 | 
					 | 
				
			||||||
            # itself things like multiplicities;
 | 
					 | 
				
			||||||
            # For integers and floats, we also need validators because, by
 | 
					 | 
				
			||||||
            # default, Archetypes produces an exception if the field value does
 | 
					 | 
				
			||||||
            # not have the correct type, for example.
 | 
					 | 
				
			||||||
            methodName = 'validate_%s' % self.fieldName
 | 
					 | 
				
			||||||
            # Add a validate method for this
 | 
					 | 
				
			||||||
            specificType = None
 | 
					 | 
				
			||||||
            if self.appyType.type in self.alwaysAValidatorFor:
 | 
					 | 
				
			||||||
                specificType = self.appyType.type
 | 
					 | 
				
			||||||
            self.classDescr.addValidateMethod(methodName, label, self,
 | 
					 | 
				
			||||||
                specificType=specificType)
 | 
					 | 
				
			||||||
        # Manage specific permissions
 | 
					 | 
				
			||||||
        permFieldName = '%s %s' % (self.classDescr.name, self.fieldName)
 | 
					 | 
				
			||||||
        if self.appyType.specificReadPermission:
 | 
					 | 
				
			||||||
            self.fieldParams['read_permission'] = '%s: Read %s' % \
 | 
					 | 
				
			||||||
                (self.generator.applicationName, permFieldName)
 | 
					 | 
				
			||||||
        if self.appyType.specificWritePermission:
 | 
					 | 
				
			||||||
            self.fieldParams['write_permission'] = '%s: Write %s' % \
 | 
					 | 
				
			||||||
                (self.generator.applicationName, permFieldName)
 | 
					 | 
				
			||||||
        # i18n labels
 | 
					        # i18n labels
 | 
				
			||||||
        i18nPrefix = "%s_%s" % (self.classDescr.name, self.fieldName)
 | 
					        i18nPrefix = "%s_%s" % (self.classDescr.name, self.fieldName)
 | 
				
			||||||
        wp = self.widgetParams
 | 
					 | 
				
			||||||
        wp['label'] = self.fieldName
 | 
					 | 
				
			||||||
        wp['label_msgid'] = '%s' % i18nPrefix
 | 
					 | 
				
			||||||
        wp['description'] = '%sDescr' % i18nPrefix
 | 
					 | 
				
			||||||
        wp['description_msgid'] = '%s_descr' % i18nPrefix
 | 
					 | 
				
			||||||
        wp['i18n_domain'] = self.applicationName
 | 
					 | 
				
			||||||
        # Create labels for generating them in i18n files.
 | 
					        # Create labels for generating them in i18n files.
 | 
				
			||||||
        messages = self.generator.labels
 | 
					        messages = self.generator.labels
 | 
				
			||||||
        messages.append(self.produceMessage(wp['label_msgid']))
 | 
					        if self.appyType.hasLabel:
 | 
				
			||||||
        messages.append(self.produceMessage(wp['description_msgid'],
 | 
					            messages.append(self.produceMessage(i18nPrefix))
 | 
				
			||||||
                        isLabel=False))
 | 
					        if self.appyType.hasDescr:
 | 
				
			||||||
 | 
					            descrId = i18nPrefix + '_descr'
 | 
				
			||||||
 | 
					            messages.append(self.produceMessage(descrId,isLabel=False))
 | 
				
			||||||
 | 
					        if self.appyType.hasHelp:
 | 
				
			||||||
 | 
					            helpId = i18nPrefix + '_help'
 | 
				
			||||||
 | 
					            messages.append(self.produceMessage(helpId, isLabel=False))
 | 
				
			||||||
        # Create i18n messages linked to pages and phases
 | 
					        # Create i18n messages linked to pages and phases
 | 
				
			||||||
        messages = self.generator.labels
 | 
					        messages = self.generator.labels
 | 
				
			||||||
        pageMsgId = '%s_page_%s' % (self.classDescr.name, self.appyType.page)
 | 
					        pageMsgId = '%s_page_%s' % (self.classDescr.name, self.appyType.page)
 | 
				
			||||||
| 
						 | 
					@ -305,34 +181,22 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
                messages.append(poMsg)
 | 
					                messages.append(poMsg)
 | 
				
			||||||
                self.classDescr.labelsToPropagate.append(poMsg)
 | 
					                self.classDescr.labelsToPropagate.append(poMsg)
 | 
				
			||||||
        # Create i18n messages linked to groups
 | 
					        # Create i18n messages linked to groups
 | 
				
			||||||
        if self.appyType.group:
 | 
					        group = self.appyType.group
 | 
				
			||||||
            groupName, cols = GroupDescr.getGroupInfo(self.appyType.group)
 | 
					        if group:
 | 
				
			||||||
            msgId = '%s_group_%s' % (self.classDescr.name, groupName)
 | 
					            group.generateLabels(messages, self.classDescr, set())
 | 
				
			||||||
            poMsg = PoMessage(msgId, '', groupName)
 | 
					 | 
				
			||||||
            poMsg.produceNiceDefault()
 | 
					 | 
				
			||||||
            if poMsg not in messages:
 | 
					 | 
				
			||||||
                messages.append(poMsg)
 | 
					 | 
				
			||||||
                self.classDescr.labelsToPropagate.append(poMsg)
 | 
					 | 
				
			||||||
        # Manage schemata
 | 
					 | 
				
			||||||
        if self.appyType.page != 'main':
 | 
					 | 
				
			||||||
            self.fieldParams['schemata'] = self.appyType.page
 | 
					 | 
				
			||||||
        # Manage things which are specific to basic types
 | 
					 | 
				
			||||||
        if self.appyType.type in self.singleValuedTypes: self.walkBasicType()
 | 
					 | 
				
			||||||
        # Manage things which are specific to String types
 | 
					        # Manage things which are specific to String types
 | 
				
			||||||
        elif self.appyType.type == 'String': self.walkString()
 | 
					        if self.appyType.type == 'String': self.walkString()
 | 
				
			||||||
        # Manage things which are specific to Computed types
 | 
					 | 
				
			||||||
        elif self.appyType.type == 'Computed': self.walkComputed()
 | 
					 | 
				
			||||||
        # Manage things which are specific to Actions
 | 
					        # Manage things which are specific to Actions
 | 
				
			||||||
        elif self.appyType.type == 'Action': self.walkAction()
 | 
					        elif self.appyType.type == 'Action': self.walkAction()
 | 
				
			||||||
        # Manage things which are specific to Ref types
 | 
					        # Manage things which are specific to Ref types
 | 
				
			||||||
        elif self.appyType.type == 'Ref': self.walkRef()
 | 
					        elif self.appyType.type == 'Ref': self.walkRef()
 | 
				
			||||||
        # Manage things which are specific to Info types
 | 
					 | 
				
			||||||
        elif self.appyType.type == 'Info': self.walkInfo()
 | 
					 | 
				
			||||||
        # Manage things which are specific to Pod types
 | 
					        # Manage things which are specific to Pod types
 | 
				
			||||||
        elif self.appyType.type == 'Pod': self.walkPod()
 | 
					        elif self.appyType.type == 'Pod': self.walkPod()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generate(self):
 | 
					    def generate(self):
 | 
				
			||||||
        '''Produces the Archetypes field definition as a string.'''
 | 
					        '''Generates the i18n labels for this type.'''
 | 
				
			||||||
 | 
					        self.walkAppyType()
 | 
				
			||||||
 | 
					        if self.appyType.type != 'Ref': return
 | 
				
			||||||
        res = ''
 | 
					        res = ''
 | 
				
			||||||
        s = stringify
 | 
					        s = stringify
 | 
				
			||||||
        spaces = TABS
 | 
					        spaces = TABS
 | 
				
			||||||
| 
						 | 
					@ -376,89 +240,41 @@ class ClassDescriptor(appy.gen.descriptors.ClassDescriptor):
 | 
				
			||||||
        # for child classes of this class as well, but at this time we don't
 | 
					        # for child classes of this class as well, but at this time we don't
 | 
				
			||||||
        # know yet every sub-class. So we store field definitions here; the
 | 
					        # know yet every sub-class. So we store field definitions here; the
 | 
				
			||||||
        # Generator will propagate them later.
 | 
					        # Generator will propagate them later.
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def generateSchema(self):
 | 
					 | 
				
			||||||
        '''Generates the corresponding Archetypes schema in self.schema.'''
 | 
					 | 
				
			||||||
        for attrName in self.orderedAttributes:
 | 
					 | 
				
			||||||
            attrValue = getattr(self.klass, attrName)
 | 
					 | 
				
			||||||
            if isinstance(attrValue, Type):
 | 
					 | 
				
			||||||
                field = ArchetypeFieldDescriptor(attrName, attrValue, self)
 | 
					 | 
				
			||||||
                self.schema += '\n' + field.generate()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def addSelectMethod(self, methodName, fieldDescr):
 | 
					 | 
				
			||||||
        '''For the selection field p_fieldDescr I need to generate a method
 | 
					 | 
				
			||||||
           named p_methodName that will generate the vocabulary for
 | 
					 | 
				
			||||||
           p_fieldDescr.'''
 | 
					 | 
				
			||||||
        # Generate the method signature
 | 
					 | 
				
			||||||
        m = self.methods
 | 
					 | 
				
			||||||
        s = stringify
 | 
					 | 
				
			||||||
        spaces = TABS
 | 
					 | 
				
			||||||
        m += '\n' + ' '*spaces + 'def %s(self):\n' % methodName
 | 
					 | 
				
			||||||
        spaces += TABS
 | 
					 | 
				
			||||||
        appyType = fieldDescr.appyType
 | 
					 | 
				
			||||||
        if type(appyType.validator) in (list, tuple):
 | 
					 | 
				
			||||||
            # Generate i18n messages for every possible value
 | 
					 | 
				
			||||||
            f = fieldDescr
 | 
					 | 
				
			||||||
            labels = []
 | 
					 | 
				
			||||||
            for value in appyType.validator:
 | 
					 | 
				
			||||||
                msgLabel = '%s_%s_list_%s' % (f.classDescr.name, f.fieldName,
 | 
					 | 
				
			||||||
                                              value)
 | 
					 | 
				
			||||||
                labels.append(msgLabel) # I will need it later
 | 
					 | 
				
			||||||
                poMsg = PoMessage(msgLabel, '', value)
 | 
					 | 
				
			||||||
                poMsg.produceNiceDefault()
 | 
					 | 
				
			||||||
                self.generator.labels.append(poMsg)
 | 
					 | 
				
			||||||
            # Generate a method that returns a DisplayList
 | 
					 | 
				
			||||||
            appName = self.generator.applicationName
 | 
					 | 
				
			||||||
            allValues = appyType.validator
 | 
					 | 
				
			||||||
            if not appyType.isMultiValued():
 | 
					 | 
				
			||||||
                allValues = [''] + appyType.validator
 | 
					 | 
				
			||||||
                labels.insert(0, 'choose_a_value')
 | 
					 | 
				
			||||||
            m += ' '*spaces + 'return self._appy_getDisplayList' \
 | 
					 | 
				
			||||||
                 '(%s, %s, %s)\n' % (s(allValues), s(labels), s(appName))
 | 
					 | 
				
			||||||
        elif isinstance(appyType.validator, Selection):
 | 
					 | 
				
			||||||
            # Call the custom method that will produce dynamically the list of
 | 
					 | 
				
			||||||
            # values.
 | 
					 | 
				
			||||||
            m += ' '*spaces + 'return self._appy_getDynamicDisplayList' \
 | 
					 | 
				
			||||||
                 '(%s)\n' % s(appyType.validator.methodName)
 | 
					 | 
				
			||||||
        self.methods = m
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def addValidateMethod(self, methodName, label, fieldDescr,
 | 
					 | 
				
			||||||
                          specificType=None):
 | 
					 | 
				
			||||||
        '''For the field p_fieldDescr I need to generate a validation method.
 | 
					 | 
				
			||||||
           If p_specificType is not None, it corresponds to the name of a type
 | 
					 | 
				
			||||||
           like Ref, Integer or Float, for which specific validation is needed,
 | 
					 | 
				
			||||||
           beyond the potential custom validation specified by a user-defined
 | 
					 | 
				
			||||||
           validator method.'''
 | 
					 | 
				
			||||||
        # Generate the method signature
 | 
					 | 
				
			||||||
        m = self.methods
 | 
					 | 
				
			||||||
        s = stringify
 | 
					 | 
				
			||||||
        spaces = TABS
 | 
					 | 
				
			||||||
        m += '\n' + ' '*spaces + 'def %s(self, value):\n' % methodName
 | 
					 | 
				
			||||||
        spaces += TABS
 | 
					 | 
				
			||||||
        m += ' '*spaces + 'return self._appy_validateField(%s, value, %s, ' \
 | 
					 | 
				
			||||||
             '%s)\n' %  (s(fieldDescr.fieldName), s(label), s(specificType))
 | 
					 | 
				
			||||||
        self.methods = m
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def addDefaultMethod(self, methodName, fieldDescr):
 | 
					 | 
				
			||||||
        '''When the default value of a field may be edited, we must add a method
 | 
					 | 
				
			||||||
           that will gather the default value from the flavour.'''
 | 
					 | 
				
			||||||
        m = self.methods
 | 
					 | 
				
			||||||
        spaces = TABS
 | 
					 | 
				
			||||||
        m += '\n' + ' '*spaces + 'def %s(self):\n' % methodName
 | 
					 | 
				
			||||||
        spaces += TABS
 | 
					 | 
				
			||||||
        m += ' '*spaces + 'return self.getDefaultValueFor("%s")\n' % \
 | 
					 | 
				
			||||||
             fieldDescr.fieldName
 | 
					 | 
				
			||||||
        self.methods = m
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ArchetypesClassDescriptor(ClassDescriptor):
 | 
					 | 
				
			||||||
    '''Represents an Archetypes-compliant class that corresponds to an
 | 
					 | 
				
			||||||
       application class.'''
 | 
					 | 
				
			||||||
    predefined = False
 | 
					 | 
				
			||||||
    def __init__(self, klass, orderedAttributes, generator):
 | 
					 | 
				
			||||||
        ClassDescriptor.__init__(self, klass, orderedAttributes, generator)
 | 
					 | 
				
			||||||
        if not hasattr(self, 'name'):
 | 
					 | 
				
			||||||
        self.name = self.getClassName(klass)
 | 
					        self.name = self.getClassName(klass)
 | 
				
			||||||
        self.generateSchema()
 | 
					        self.predefined = False
 | 
				
			||||||
 | 
					        self.customized = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getParents(self, allClasses):
 | 
				
			||||||
 | 
					        parentWrapper = 'AbstractWrapper'
 | 
				
			||||||
 | 
					        parentClass = '%s.%s' % (self.klass.__module__, self.klass.__name__)
 | 
				
			||||||
 | 
					        if self.klass.__bases__:
 | 
				
			||||||
 | 
					            baseClassName = self.klass.__bases__[0].__name__
 | 
				
			||||||
 | 
					            for k in allClasses:
 | 
				
			||||||
 | 
					                if self.klass.__name__ == baseClassName:
 | 
				
			||||||
 | 
					                    parentWrapper = '%s_Wrapper' % k.name
 | 
				
			||||||
 | 
					        return (parentWrapper, parentClass)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generateSchema(self, configClass=False):
 | 
				
			||||||
 | 
					        '''Generates the corresponding Archetypes schema in self.schema. If we
 | 
				
			||||||
 | 
					           are generating a schema for a class that is in the configuration
 | 
				
			||||||
 | 
					           (tool, flavour, etc) we must avoid having attributes that rely on
 | 
				
			||||||
 | 
					           the configuration (ie attributes that are optional, with
 | 
				
			||||||
 | 
					           editDefault=True, etc).'''
 | 
				
			||||||
 | 
					        for attrName in self.orderedAttributes:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                attrValue = getattr(self.klass, attrName)
 | 
				
			||||||
 | 
					            except AttributeError:
 | 
				
			||||||
 | 
					                attrValue = getattr(self.modelClass, attrName)
 | 
				
			||||||
 | 
					            if isinstance(attrValue, Type):
 | 
				
			||||||
 | 
					                if configClass:
 | 
				
			||||||
 | 
					                    attrValue = copy.copy(attrValue)
 | 
				
			||||||
 | 
					                    attrValue.optional = False
 | 
				
			||||||
 | 
					                    attrValue.editDefault = False
 | 
				
			||||||
 | 
					                field = FieldDescriptor(attrName, attrValue, self)
 | 
				
			||||||
 | 
					                fieldDef = field.generate()
 | 
				
			||||||
 | 
					                if fieldDef:
 | 
				
			||||||
 | 
					                    # Currently, we generate Archetypes fields for Refs only.
 | 
				
			||||||
 | 
					                    self.schema += '\n' + fieldDef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def getClassName(klass):
 | 
					    def getClassName(klass):
 | 
				
			||||||
| 
						 | 
					@ -502,6 +318,13 @@ class ArchetypesClassDescriptor(ClassDescriptor):
 | 
				
			||||||
                res = self.isFolder(theClass.__bases__[0])
 | 
					                res = self.isFolder(theClass.__bases__[0])
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getCreators(self):
 | 
				
			||||||
 | 
					        '''Gets the specific creators defined for this class.'''
 | 
				
			||||||
 | 
					        res = []
 | 
				
			||||||
 | 
					        if self.klass.__dict__.has_key('creators') and self.klass.creators:
 | 
				
			||||||
 | 
					            res += list(self.klass.creators)
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getCreateMean(self, type='Import'):
 | 
					    def getCreateMean(self, type='Import'):
 | 
				
			||||||
        '''Returns the mean for this class that corresponds to p_type, or
 | 
					        '''Returns the mean for this class that corresponds to p_type, or
 | 
				
			||||||
           None if the class does not support this create mean.'''
 | 
					           None if the class does not support this create mean.'''
 | 
				
			||||||
| 
						 | 
					@ -534,75 +357,87 @@ class ArchetypesClassDescriptor(ClassDescriptor):
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def getSearch(klass, searchName):
 | 
					    def getSearch(klass, searchName):
 | 
				
			||||||
        '''Gets the search named p_searchName.'''
 | 
					        '''Gets the search named p_searchName.'''
 | 
				
			||||||
        for search in ArchetypesClassDescriptor.getSearches(klass):
 | 
					        for search in ClassDescriptor.getSearches(klass):
 | 
				
			||||||
            if search.name == searchName:
 | 
					            if search.name == searchName:
 | 
				
			||||||
                return search
 | 
					                return search
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ToolClassDescriptor(ClassDescriptor):
 | 
					    def addIndexMethod(self, field):
 | 
				
			||||||
    '''Represents the POD-specific fields that must be added to the tool.'''
 | 
					        '''For indexed p_field, this method generates a method that allows to
 | 
				
			||||||
    predefined = True
 | 
					           get the value of the field as must be copied into the corresponding
 | 
				
			||||||
    def __init__(self, klass, generator):
 | 
					           index.'''
 | 
				
			||||||
        ClassDescriptor.__init__(self, klass, klass._appy_attributes, generator)
 | 
					 | 
				
			||||||
        self.name = '%sTool' % generator.applicationName
 | 
					 | 
				
			||||||
    def isFolder(self, klass=None): return True
 | 
					 | 
				
			||||||
    def isRoot(self): return False
 | 
					 | 
				
			||||||
    def addUnoValidator(self):
 | 
					 | 
				
			||||||
        m = self.methods
 | 
					        m = self.methods
 | 
				
			||||||
        spaces = TABS
 | 
					        spaces = TABS
 | 
				
			||||||
        m += '\n' + ' '*spaces + 'def validate_unoEnabledPython(self, value):\n'
 | 
					        n = field.fieldName
 | 
				
			||||||
 | 
					        m += '\n' + ' '*spaces + 'def get%s%s(self):\n' % (n[0].upper(), n[1:])
 | 
				
			||||||
        spaces += TABS
 | 
					        spaces += TABS
 | 
				
			||||||
        m += ' '*spaces + 'return self._appy_validateUnoEnabledPython(value)\n'
 | 
					        m += ' '*spaces + "'''Gets indexable value of field \"%s\".'''\n" % n
 | 
				
			||||||
 | 
					        m += ' '*spaces + 'return self.getAppyType("%s").getValue(self)\n' % n
 | 
				
			||||||
        self.methods = m
 | 
					        self.methods = m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ToolClassDescriptor(ClassDescriptor):
 | 
				
			||||||
 | 
					    '''Represents the POD-specific fields that must be added to the tool.'''
 | 
				
			||||||
 | 
					    def __init__(self, klass, generator):
 | 
				
			||||||
 | 
					        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
				
			||||||
 | 
					        self.name = '%sTool' % generator.applicationName
 | 
				
			||||||
 | 
					        self.modelClass = self.klass
 | 
				
			||||||
 | 
					        self.predefined = True
 | 
				
			||||||
 | 
					        self.customized = False
 | 
				
			||||||
 | 
					    def getParents(self, allClasses=()):
 | 
				
			||||||
 | 
					        res = ['Tool']
 | 
				
			||||||
 | 
					        if self.customized:
 | 
				
			||||||
 | 
					            res.append('%s.%s' % (self.klass.__module__, self.klass.__name__))
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					    def update(self, klass, attributes):
 | 
				
			||||||
 | 
					        '''This method is called by the generator when he finds a custom tool
 | 
				
			||||||
 | 
					           definition. We must then add the custom tool elements in this default
 | 
				
			||||||
 | 
					           Tool descriptor.'''
 | 
				
			||||||
 | 
					        self.orderedAttributes += attributes
 | 
				
			||||||
 | 
					        self.klass = klass
 | 
				
			||||||
 | 
					        self.customized = True
 | 
				
			||||||
 | 
					    def isFolder(self, klass=None): return True
 | 
				
			||||||
 | 
					    def isRoot(self): return False
 | 
				
			||||||
    def generateSchema(self):
 | 
					    def generateSchema(self):
 | 
				
			||||||
        ClassDescriptor.generateSchema(self)
 | 
					        ClassDescriptor.generateSchema(self, configClass=True)
 | 
				
			||||||
        self.addUnoValidator()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FlavourClassDescriptor(ClassDescriptor):
 | 
					class FlavourClassDescriptor(ClassDescriptor):
 | 
				
			||||||
    '''Represents an Archetypes-compliant class that corresponds to the Flavour
 | 
					    '''Represents an Archetypes-compliant class that corresponds to the Flavour
 | 
				
			||||||
       for the generated application.'''
 | 
					       for the generated application.'''
 | 
				
			||||||
    predefined = True
 | 
					 | 
				
			||||||
    def __init__(self, klass, generator):
 | 
					    def __init__(self, klass, generator):
 | 
				
			||||||
        ClassDescriptor.__init__(self, klass, klass._appy_attributes, generator)
 | 
					        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
				
			||||||
        self.name = '%sFlavour' % generator.applicationName
 | 
					        self.name = '%sFlavour' % generator.applicationName
 | 
				
			||||||
        self.attributesByClass = klass._appy_classes
 | 
					        self.attributesByClass = klass._appy_classes
 | 
				
			||||||
        # We don't generate the schema automatically here because we need to
 | 
					        self.modelClass = self.klass
 | 
				
			||||||
        # add more fields.
 | 
					        self.predefined = True
 | 
				
			||||||
 | 
					        self.customized = False
 | 
				
			||||||
 | 
					    def getParents(self, allClasses=()):
 | 
				
			||||||
 | 
					        res = ['Flavour']
 | 
				
			||||||
 | 
					        if self.customized:
 | 
				
			||||||
 | 
					            res.append('%s.%s' % (self.klass.__module__, self.klass.__name__))
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					    def update(self, klass, attributes):
 | 
				
			||||||
 | 
					        '''This method is called by the generator when he finds a custom flavour
 | 
				
			||||||
 | 
					           definition. We must then add the custom flavour elements in this
 | 
				
			||||||
 | 
					           default Flavour descriptor.'''
 | 
				
			||||||
 | 
					        self.orderedAttributes += attributes
 | 
				
			||||||
 | 
					        self.klass = klass
 | 
				
			||||||
 | 
					        self.customized = True
 | 
				
			||||||
    def isFolder(self, klass=None): return True
 | 
					    def isFolder(self, klass=None): return True
 | 
				
			||||||
    def isRoot(self): return False
 | 
					    def isRoot(self): return False
 | 
				
			||||||
 | 
					    def generateSchema(self):
 | 
				
			||||||
 | 
					        ClassDescriptor.generateSchema(self, configClass=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PodTemplateClassDescriptor(ClassDescriptor):
 | 
					class PodTemplateClassDescriptor(ClassDescriptor):
 | 
				
			||||||
    '''Represents a POD template.'''
 | 
					    '''Represents a POD template.'''
 | 
				
			||||||
    predefined = True
 | 
					 | 
				
			||||||
    def __init__(self, klass, generator):
 | 
					    def __init__(self, klass, generator):
 | 
				
			||||||
        ClassDescriptor.__init__(self, klass, klass._appy_attributes, generator)
 | 
					        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
				
			||||||
        self.name = '%sPodTemplate' % generator.applicationName
 | 
					        self.name = '%sPodTemplate' % generator.applicationName
 | 
				
			||||||
 | 
					        self.modelClass = self.klass
 | 
				
			||||||
 | 
					        self.predefined = True
 | 
				
			||||||
 | 
					        self.customized = False
 | 
				
			||||||
 | 
					    def getParents(self, allClasses=()): return ['PodTemplate']
 | 
				
			||||||
    def isRoot(self): return False
 | 
					    def isRoot(self): return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CustomToolClassDescriptor(ArchetypesClassDescriptor):
 | 
					 | 
				
			||||||
    '''If the user defines a class that inherits from Tool, we will add those
 | 
					 | 
				
			||||||
       fields to the tool.'''
 | 
					 | 
				
			||||||
    predefined = False
 | 
					 | 
				
			||||||
    def __init__(self, *args):
 | 
					 | 
				
			||||||
        self.name = '%sTool' % args[2].applicationName
 | 
					 | 
				
			||||||
        ArchetypesClassDescriptor.__init__(self, *args)
 | 
					 | 
				
			||||||
    def generateSchema(self):
 | 
					 | 
				
			||||||
        '''Custom tool fields may not use the variability mechanisms, ie
 | 
					 | 
				
			||||||
           'optional' or 'editDefault' attributes.'''
 | 
					 | 
				
			||||||
        for attrName in self.orderedAttributes:
 | 
					 | 
				
			||||||
            attrValue = getattr(self.klass, attrName)
 | 
					 | 
				
			||||||
            if isinstance(attrValue, Type):
 | 
					 | 
				
			||||||
                attrValue = copy.copy(attrValue)
 | 
					 | 
				
			||||||
                attrValue.optional = False
 | 
					 | 
				
			||||||
                attrValue.editDefault = False
 | 
					 | 
				
			||||||
                field = ArchetypeFieldDescriptor(attrName, attrValue, self)
 | 
					 | 
				
			||||||
                self.schema += '\n' + field.generate()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CustomFlavourClassDescriptor(CustomToolClassDescriptor):
 | 
					 | 
				
			||||||
    def __init__(self, *args):
 | 
					 | 
				
			||||||
        self.name = '%sFlavour' % args[2].applicationName
 | 
					 | 
				
			||||||
        ArchetypesClassDescriptor.__init__(self, *args)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class WorkflowDescriptor(appy.gen.descriptors.WorkflowDescriptor):
 | 
					class WorkflowDescriptor(appy.gen.descriptors.WorkflowDescriptor):
 | 
				
			||||||
    '''Represents a workflow.'''
 | 
					    '''Represents a workflow.'''
 | 
				
			||||||
    # How to map Appy permissions to Plone permissions ?
 | 
					    # How to map Appy permissions to Plone permissions ?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,10 +8,9 @@ from appy.gen import *
 | 
				
			||||||
from appy.gen.po import PoMessage, PoFile, PoParser
 | 
					from appy.gen.po import PoMessage, PoFile, PoParser
 | 
				
			||||||
from appy.gen.generator import Generator as AbstractGenerator
 | 
					from appy.gen.generator import Generator as AbstractGenerator
 | 
				
			||||||
from model import ModelClass, PodTemplate, Flavour, Tool
 | 
					from model import ModelClass, PodTemplate, Flavour, Tool
 | 
				
			||||||
from descriptors import ArchetypeFieldDescriptor, ArchetypesClassDescriptor, \
 | 
					from descriptors import FieldDescriptor, ClassDescriptor, \
 | 
				
			||||||
                        WorkflowDescriptor, ToolClassDescriptor, \
 | 
					                        WorkflowDescriptor, ToolClassDescriptor, \
 | 
				
			||||||
                        FlavourClassDescriptor, PodTemplateClassDescriptor, \
 | 
					                        FlavourClassDescriptor, PodTemplateClassDescriptor
 | 
				
			||||||
                        CustomToolClassDescriptor, CustomFlavourClassDescriptor
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Common methods that need to be defined on every Archetype class --------------
 | 
					# Common methods that need to be defined on every Archetype class --------------
 | 
				
			||||||
COMMON_METHODS = '''
 | 
					COMMON_METHODS = '''
 | 
				
			||||||
| 
						 | 
					@ -30,6 +29,13 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
        Flavour._appy_clean()
 | 
					        Flavour._appy_clean()
 | 
				
			||||||
        AbstractGenerator.__init__(self, *args, **kwargs)
 | 
					        AbstractGenerator.__init__(self, *args, **kwargs)
 | 
				
			||||||
 | 
					        # Set our own Descriptor classes
 | 
				
			||||||
 | 
					        self.descriptorClasses['class'] = ClassDescriptor
 | 
				
			||||||
 | 
					        self.descriptorClasses['workflow']  = WorkflowDescriptor
 | 
				
			||||||
 | 
					        # Create our own Tool, Flavour and PodTemplate instances
 | 
				
			||||||
 | 
					        self.tool = ToolClassDescriptor(Tool, self)
 | 
				
			||||||
 | 
					        self.flavour = FlavourClassDescriptor(Flavour, self)
 | 
				
			||||||
 | 
					        self.podTemplate = PodTemplateClassDescriptor(PodTemplate, self)
 | 
				
			||||||
        # i18n labels to generate
 | 
					        # i18n labels to generate
 | 
				
			||||||
        self.labels = [] # i18n labels
 | 
					        self.labels = [] # i18n labels
 | 
				
			||||||
        self.toolName = '%sTool' % self.applicationName
 | 
					        self.toolName = '%sTool' % self.applicationName
 | 
				
			||||||
| 
						 | 
					@ -50,19 +56,10 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
             'toolInstanceName': self.toolInstanceName,
 | 
					             'toolInstanceName': self.toolInstanceName,
 | 
				
			||||||
             'podTemplateName': self.podTemplateName,
 | 
					             'podTemplateName': self.podTemplateName,
 | 
				
			||||||
             'commonMethods': commonMethods})
 | 
					             'commonMethods': commonMethods})
 | 
				
			||||||
        # Predefined class descriptors
 | 
					 | 
				
			||||||
        self.toolDescr = ToolClassDescriptor(Tool, self)
 | 
					 | 
				
			||||||
        self.flavourDescr = FlavourClassDescriptor(Flavour, self)
 | 
					 | 
				
			||||||
        self.podTemplateDescr = PodTemplateClassDescriptor(PodTemplate,self)
 | 
					 | 
				
			||||||
        self.referers = {}
 | 
					        self.referers = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    versionRex = re.compile('(.*?\s+build)\s+(\d+)')
 | 
					    versionRex = re.compile('(.*?\s+build)\s+(\d+)')
 | 
				
			||||||
    def initialize(self):
 | 
					    def initialize(self):
 | 
				
			||||||
        # Use customized class descriptors
 | 
					 | 
				
			||||||
        self.classDescriptor = ArchetypesClassDescriptor
 | 
					 | 
				
			||||||
        self.workflowDescriptor = WorkflowDescriptor
 | 
					 | 
				
			||||||
        self.customToolClassDescriptor = CustomToolClassDescriptor
 | 
					 | 
				
			||||||
        self.customFlavourClassDescriptor = CustomFlavourClassDescriptor
 | 
					 | 
				
			||||||
        # Determine version number of the Plone product
 | 
					        # Determine version number of the Plone product
 | 
				
			||||||
        self.version = '0.1 build 1'
 | 
					        self.version = '0.1 build 1'
 | 
				
			||||||
        versionTxt = os.path.join(self.outputFolder, 'version.txt')
 | 
					        versionTxt = os.path.join(self.outputFolder, 'version.txt')
 | 
				
			||||||
| 
						 | 
					@ -91,6 +88,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        poMsg = msg(app, '', app); poMsg.produceNiceDefault()
 | 
					        poMsg = msg(app, '', app); poMsg.produceNiceDefault()
 | 
				
			||||||
        self.labels += [poMsg,
 | 
					        self.labels += [poMsg,
 | 
				
			||||||
            msg('workflow_state',       '', msg.WORKFLOW_STATE),
 | 
					            msg('workflow_state',       '', msg.WORKFLOW_STATE),
 | 
				
			||||||
 | 
					            msg('appy_title',           '', msg.APPY_TITLE),
 | 
				
			||||||
            msg('data_change',          '', msg.DATA_CHANGE),
 | 
					            msg('data_change',          '', msg.DATA_CHANGE),
 | 
				
			||||||
            msg('modified_field',       '', msg.MODIFIED_FIELD),
 | 
					            msg('modified_field',       '', msg.MODIFIED_FIELD),
 | 
				
			||||||
            msg('previous_value',       '', msg.PREVIOUS_VALUE),
 | 
					            msg('previous_value',       '', msg.PREVIOUS_VALUE),
 | 
				
			||||||
| 
						 | 
					@ -127,11 +125,12 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            msg('search_or',            '', msg.SEARCH_OR),
 | 
					            msg('search_or',            '', msg.SEARCH_OR),
 | 
				
			||||||
            msg('search_and',           '', msg.SEARCH_AND),
 | 
					            msg('search_and',           '', msg.SEARCH_AND),
 | 
				
			||||||
            msg('ref_invalid_index',    '', msg.REF_INVALID_INDEX),
 | 
					            msg('ref_invalid_index',    '', msg.REF_INVALID_INDEX),
 | 
				
			||||||
            msg('bad_int',              '', msg.BAD_INT),
 | 
					            msg('bad_long',             '', msg.BAD_LONG),
 | 
				
			||||||
            msg('bad_float',            '', msg.BAD_FLOAT),
 | 
					            msg('bad_float',            '', msg.BAD_FLOAT),
 | 
				
			||||||
            msg('bad_email',            '', msg.BAD_EMAIL),
 | 
					            msg('bad_email',            '', msg.BAD_EMAIL),
 | 
				
			||||||
            msg('bad_url',              '', msg.BAD_URL),
 | 
					            msg('bad_url',              '', msg.BAD_URL),
 | 
				
			||||||
            msg('bad_alphanumeric',     '', msg.BAD_ALPHANUMERIC),
 | 
					            msg('bad_alphanumeric',     '', msg.BAD_ALPHANUMERIC),
 | 
				
			||||||
 | 
					            msg('bad_select_value',     '', msg.BAD_SELECT_VALUE),
 | 
				
			||||||
            msg('select_delesect',      '', msg.SELECT_DESELECT),
 | 
					            msg('select_delesect',      '', msg.SELECT_DESELECT),
 | 
				
			||||||
            msg('no_elem_selected',     '', msg.NO_SELECTION),
 | 
					            msg('no_elem_selected',     '', msg.NO_SELECTION),
 | 
				
			||||||
            msg('delete_confirm',       '', msg.DELETE_CONFIRM),
 | 
					            msg('delete_confirm',       '', msg.DELETE_CONFIRM),
 | 
				
			||||||
| 
						 | 
					@ -145,6 +144,9 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            msg('confirm',              '', msg.CONFIRM),
 | 
					            msg('confirm',              '', msg.CONFIRM),
 | 
				
			||||||
            msg('yes',                  '', msg.YES),
 | 
					            msg('yes',                  '', msg.YES),
 | 
				
			||||||
            msg('no',                   '', msg.NO),
 | 
					            msg('no',                   '', msg.NO),
 | 
				
			||||||
 | 
					            msg('field_required',       '', msg.FIELD_REQUIRED),
 | 
				
			||||||
 | 
					            msg('file_required',        '', msg.FILE_REQUIRED),
 | 
				
			||||||
 | 
					            msg('image_required',       '', msg.IMAGE_REQUIRED),
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        # Create basic files (config.py, Install.py, etc)
 | 
					        # Create basic files (config.py, Install.py, etc)
 | 
				
			||||||
        self.generateTool()
 | 
					        self.generateTool()
 | 
				
			||||||
| 
						 | 
					@ -229,10 +231,10 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ploneRoles = ('Manager', 'Member', 'Owner', 'Reviewer')
 | 
					    ploneRoles = ('Manager', 'Member', 'Owner', 'Reviewer')
 | 
				
			||||||
    def getAllUsedRoles(self, appOnly=False):
 | 
					    def getAllUsedRoles(self, appOnly=False):
 | 
				
			||||||
        '''Produces a list of all the roles used within all workflows defined
 | 
					        '''Produces a list of all the roles used within all workflows and
 | 
				
			||||||
           in this application. If p_appOnly is True, it returns only roles
 | 
					           classes defined in this application. If p_appOnly is True, it
 | 
				
			||||||
           which are specific to this application (ie it removes predefined
 | 
					           returns only roles which are specific to this application (ie it
 | 
				
			||||||
           Plone roles like Member, Manager, etc.'''
 | 
					           removes predefined Plone roles like Member, Manager, etc.'''
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        for wfDescr in self.workflows:
 | 
					        for wfDescr in self.workflows:
 | 
				
			||||||
            # Browse states and transitions
 | 
					            # Browse states and transitions
 | 
				
			||||||
| 
						 | 
					@ -241,6 +243,8 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
                if isinstance(attrValue, State) or \
 | 
					                if isinstance(attrValue, State) or \
 | 
				
			||||||
                   isinstance(attrValue, Transition):
 | 
					                   isinstance(attrValue, Transition):
 | 
				
			||||||
                    res += attrValue.getUsedRoles()
 | 
					                    res += attrValue.getUsedRoles()
 | 
				
			||||||
 | 
					        for cDescr in self.getClasses(include='all'):
 | 
				
			||||||
 | 
					            res += cDescr.getCreators()
 | 
				
			||||||
        res = list(set(res))
 | 
					        res = list(set(res))
 | 
				
			||||||
        if appOnly:
 | 
					        if appOnly:
 | 
				
			||||||
            for ploneRole in self.ploneRoles:
 | 
					            for ploneRole in self.ploneRoles:
 | 
				
			||||||
| 
						 | 
					@ -259,28 +263,22 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        elif issubclass(k, appy.gen.Flavour):
 | 
					        elif issubclass(k, appy.gen.Flavour):
 | 
				
			||||||
            refClassName = '%sFlavour' % self.applicationName
 | 
					            refClassName = '%sFlavour' % self.applicationName
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            refClassName = ArchetypesClassDescriptor.getClassName(k)
 | 
					            refClassName = ClassDescriptor.getClassName(k)
 | 
				
			||||||
        if not self.referers.has_key(refClassName):
 | 
					        if not self.referers.has_key(refClassName):
 | 
				
			||||||
            self.referers[refClassName] = []
 | 
					            self.referers[refClassName] = []
 | 
				
			||||||
        self.referers[refClassName].append( (fieldDescr, relationship))
 | 
					        self.referers[refClassName].append( (fieldDescr, relationship))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateConfig(self):
 | 
					    def getAppyTypePath(self, name, appyType, klass, isBack=False):
 | 
				
			||||||
        # Compute referers
 | 
					        '''Gets the path to the p_appyType when a direct reference to an
 | 
				
			||||||
        referers = ''
 | 
					           appyType must be generated in a Python file.'''
 | 
				
			||||||
        for className, refInfo in self.referers.iteritems():
 | 
					        if issubclass(klass, ModelClass):
 | 
				
			||||||
            referers += '"%s":[' % className
 | 
					            res = 'wraps.%s.%s' % (klass.__name__, name)
 | 
				
			||||||
            for fieldDescr, relationship in refInfo:
 | 
					 | 
				
			||||||
                refClass = fieldDescr.classDescr.klass
 | 
					 | 
				
			||||||
                if issubclass(refClass, ModelClass):
 | 
					 | 
				
			||||||
                    refClassName = 'Extensions.appyWrappers.%s' % \
 | 
					 | 
				
			||||||
                                   refClass.__name__
 | 
					 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
                    refClassName = '%s.%s' % (refClass.__module__,
 | 
					            res = '%s.%s.%s' % (klass.__module__, klass.__name__, name)
 | 
				
			||||||
                                              refClass.__name__)
 | 
					        if isBack: res += '.back'
 | 
				
			||||||
                referers += '(%s.%s' % (refClassName, fieldDescr.fieldName)
 | 
					        return res
 | 
				
			||||||
                referers += ',"%s"' % relationship
 | 
					
 | 
				
			||||||
                referers += '),'
 | 
					    def generateConfig(self):
 | 
				
			||||||
            referers += '],\n'
 | 
					 | 
				
			||||||
        # Compute workflow instances initialisation
 | 
					        # Compute workflow instances initialisation
 | 
				
			||||||
        wfInit = ''
 | 
					        wfInit = ''
 | 
				
			||||||
        for workflowDescr in self.workflows:
 | 
					        for workflowDescr in self.workflows:
 | 
				
			||||||
| 
						 | 
					@ -301,21 +299,11 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            wfInit += 'workflowInstances[%s] = wf\n' % className
 | 
					            wfInit += 'workflowInstances[%s] = wf\n' % className
 | 
				
			||||||
        # Compute imports
 | 
					        # Compute imports
 | 
				
			||||||
        imports = ['import %s' % self.applicationName]
 | 
					        imports = ['import %s' % self.applicationName]
 | 
				
			||||||
        classDescrs = self.classes[:]
 | 
					        classDescrs = self.getClasses(include='custom')
 | 
				
			||||||
        if self.customToolDescr:
 | 
					 | 
				
			||||||
            classDescrs.append(self.customToolDescr)
 | 
					 | 
				
			||||||
        if self.customFlavourDescr:
 | 
					 | 
				
			||||||
            classDescrs.append(self.customFlavourDescr)
 | 
					 | 
				
			||||||
        for classDescr in (classDescrs + self.workflows):
 | 
					        for classDescr in (classDescrs + self.workflows):
 | 
				
			||||||
            theImport = 'import %s' % classDescr.klass.__module__
 | 
					            theImport = 'import %s' % classDescr.klass.__module__
 | 
				
			||||||
            if theImport not in imports:
 | 
					            if theImport not in imports:
 | 
				
			||||||
                imports.append(theImport)
 | 
					                imports.append(theImport)
 | 
				
			||||||
        # Compute ordered lists of attributes for every Appy class.
 | 
					 | 
				
			||||||
        attributes = []
 | 
					 | 
				
			||||||
        for classDescr in classDescrs:
 | 
					 | 
				
			||||||
            classAttrs = [a[0] for a in classDescr.getOrderedAppyAttributes()]
 | 
					 | 
				
			||||||
            attrs = ','.join([('"%s"' % a) for a in classAttrs])
 | 
					 | 
				
			||||||
            attributes.append('"%s":[%s]' % (classDescr.name, attrs))
 | 
					 | 
				
			||||||
        # Compute root classes
 | 
					        # Compute root classes
 | 
				
			||||||
        rootClasses = ''
 | 
					        rootClasses = ''
 | 
				
			||||||
        for classDescr in self.classes:
 | 
					        for classDescr in self.classes:
 | 
				
			||||||
| 
						 | 
					@ -327,14 +315,49 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            addPermissions += '    "%s":"%s: Add %s",\n' % (classDescr.name,
 | 
					            addPermissions += '    "%s":"%s: Add %s",\n' % (classDescr.name,
 | 
				
			||||||
                self.applicationName, classDescr.name)
 | 
					                self.applicationName, classDescr.name)
 | 
				
			||||||
        repls = self.repls.copy()
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
 | 
					        # Compute the list of ordered attributes (foward and backward, inherited
 | 
				
			||||||
 | 
					        # included) for every Appy class.
 | 
				
			||||||
 | 
					        attributes = []
 | 
				
			||||||
 | 
					        attributesDict = []
 | 
				
			||||||
 | 
					        for classDescr in self.getClasses(include='all'):
 | 
				
			||||||
 | 
					            titleFound = False
 | 
				
			||||||
 | 
					            attrs = []
 | 
				
			||||||
 | 
					            attrNames = []
 | 
				
			||||||
 | 
					            for name, appyType, klass in classDescr.getOrderedAppyAttributes():
 | 
				
			||||||
 | 
					                attrs.append(self.getAppyTypePath(name, appyType, klass))
 | 
				
			||||||
 | 
					                attrNames.append(name)
 | 
				
			||||||
 | 
					                if name == 'title': titleFound = True
 | 
				
			||||||
 | 
					            # Add the "title" mandatory field if not found
 | 
				
			||||||
 | 
					            if not titleFound:
 | 
				
			||||||
 | 
					                attrs.insert(0, 'copy.deepcopy(appy.gen.title)')
 | 
				
			||||||
 | 
					                attrNames.insert(0, 'title')
 | 
				
			||||||
 | 
					            # Any backward attributes to append?
 | 
				
			||||||
 | 
					            if classDescr.name in self.referers:
 | 
				
			||||||
 | 
					                for field, rel in self.referers[classDescr.name]:
 | 
				
			||||||
 | 
					                    try:
 | 
				
			||||||
 | 
					                        getattr(field.classDescr.klass, field.fieldName)
 | 
				
			||||||
 | 
					                        klass = field.classDescr.klass
 | 
				
			||||||
 | 
					                    except AttributeError:
 | 
				
			||||||
 | 
					                        klass = field.classDescr.modelClass
 | 
				
			||||||
 | 
					                    attrs.append(self.getAppyTypePath(field.fieldName,
 | 
				
			||||||
 | 
					                        field.appyType, klass, isBack=True))
 | 
				
			||||||
 | 
					                    attrNames.append(field.appyType.back.attribute)
 | 
				
			||||||
 | 
					            attributes.append('"%s":[%s]' % (classDescr.name,','.join(attrs)))
 | 
				
			||||||
 | 
					            aDict = ''
 | 
				
			||||||
 | 
					            i = -1
 | 
				
			||||||
 | 
					            for attr in attrs:
 | 
				
			||||||
 | 
					                i += 1
 | 
				
			||||||
 | 
					                aDict += '"%s":attributes["%s"][%d],' % \
 | 
				
			||||||
 | 
					                         (attrNames[i], classDescr.name, i)
 | 
				
			||||||
 | 
					            attributesDict.append('"%s":{%s}' % (classDescr.name, aDict))
 | 
				
			||||||
        # Compute list of used roles for registering them if needed
 | 
					        # Compute list of used roles for registering them if needed
 | 
				
			||||||
        repls['roles'] = ','.join(['"%s"' % r for r in \
 | 
					        repls['roles'] = ','.join(['"%s"' % r for r in \
 | 
				
			||||||
                                  self.getAllUsedRoles(appOnly=True)])
 | 
					                                  self.getAllUsedRoles(appOnly=True)])
 | 
				
			||||||
        repls['rootClasses'] = rootClasses
 | 
					        repls['rootClasses'] = rootClasses
 | 
				
			||||||
        repls['referers'] = referers
 | 
					 | 
				
			||||||
        repls['workflowInstancesInit'] = wfInit
 | 
					        repls['workflowInstancesInit'] = wfInit
 | 
				
			||||||
        repls['imports'] = '\n'.join(imports)
 | 
					        repls['imports'] = '\n'.join(imports)
 | 
				
			||||||
        repls['attributes'] = ',\n    '.join(attributes)
 | 
					        repls['attributes'] = ',\n    '.join(attributes)
 | 
				
			||||||
 | 
					        repls['attributesDict'] = ',\n    '.join(attributesDict)
 | 
				
			||||||
        repls['defaultAddRoles'] = ','.join(
 | 
					        repls['defaultAddRoles'] = ','.join(
 | 
				
			||||||
            ['"%s"' % r for r in self.config.defaultCreators])
 | 
					            ['"%s"' % r for r in self.config.defaultCreators])
 | 
				
			||||||
        repls['addPermissions'] = addPermissions
 | 
					        repls['addPermissions'] = addPermissions
 | 
				
			||||||
| 
						 | 
					@ -342,15 +365,16 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateInit(self):
 | 
					    def generateInit(self):
 | 
				
			||||||
        # Compute imports
 | 
					        # Compute imports
 | 
				
			||||||
        imports = ['    import %s' % self.toolName,
 | 
					        imports = []
 | 
				
			||||||
                   '    import %s' % self.flavourName,
 | 
					        classNames = []
 | 
				
			||||||
                   '    import %s' % self.podTemplateName]
 | 
					        for c in self.getClasses(include='all'):
 | 
				
			||||||
        for c in self.classes:
 | 
					 | 
				
			||||||
            importDef = '    import %s' % c.name
 | 
					            importDef = '    import %s' % c.name
 | 
				
			||||||
            if importDef not in imports:
 | 
					            if importDef not in imports:
 | 
				
			||||||
                imports.append(importDef)
 | 
					                imports.append(importDef)
 | 
				
			||||||
 | 
					                classNames.append("%s.%s" % (c.name, c.name))
 | 
				
			||||||
        repls = self.repls.copy()
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
        repls['imports'] = '\n'.join(imports)
 | 
					        repls['imports'] = '\n'.join(imports)
 | 
				
			||||||
 | 
					        repls['classes'] = ','.join(classNames)
 | 
				
			||||||
        repls['totalNumberOfTests'] = self.totalNumberOfTests
 | 
					        repls['totalNumberOfTests'] = self.totalNumberOfTests
 | 
				
			||||||
        self.copyFile('__init__.py', repls)
 | 
					        self.copyFile('__init__.py', repls)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -380,12 +404,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
                          "['portal_catalog']\n" % blackClass
 | 
					                          "['portal_catalog']\n" % blackClass
 | 
				
			||||||
        # Compute workflows
 | 
					        # Compute workflows
 | 
				
			||||||
        workflows = ''
 | 
					        workflows = ''
 | 
				
			||||||
        allClasses = self.classes[:]
 | 
					        for classDescr in self.getClasses(include='all'):
 | 
				
			||||||
        if self.customToolDescr:
 | 
					 | 
				
			||||||
            allClasses.append(self.customToolDescr)
 | 
					 | 
				
			||||||
        if self.customFlavourDescr:
 | 
					 | 
				
			||||||
            allClasses.append(self.customFlavourDescr)
 | 
					 | 
				
			||||||
        for classDescr in allClasses:
 | 
					 | 
				
			||||||
            if hasattr(classDescr.klass, 'workflow'):
 | 
					            if hasattr(classDescr.klass, 'workflow'):
 | 
				
			||||||
                wfName = WorkflowDescriptor.getWorkflowName(
 | 
					                wfName = WorkflowDescriptor.getWorkflowName(
 | 
				
			||||||
                    classDescr.klass.workflow)
 | 
					                    classDescr.klass.workflow)
 | 
				
			||||||
| 
						 | 
					@ -437,40 +456,30 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        repls['workflows'] = workflows
 | 
					        repls['workflows'] = workflows
 | 
				
			||||||
        self.copyFile('workflows.py', repls, destFolder='Extensions')
 | 
					        self.copyFile('workflows.py', repls, destFolder='Extensions')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateWrapperProperty(self, attrName, appyType):
 | 
					    def generateWrapperProperty(self, name):
 | 
				
			||||||
        '''Generates the getter for attribute p_attrName having type
 | 
					        '''Generates the getter for attribute p_name.'''
 | 
				
			||||||
           p_appyType.'''
 | 
					        res = '    def get_%s(self):\n        ' % name
 | 
				
			||||||
        res = '    def get_%s(self):\n' % attrName
 | 
					        if name == 'title':
 | 
				
			||||||
        blanks = ' '*8
 | 
					            res += 'return self.o.Title()\n'
 | 
				
			||||||
        getterName = 'get%s%s' % (attrName[0].upper(), attrName[1:])
 | 
					 | 
				
			||||||
        if isinstance(appyType, Ref):
 | 
					 | 
				
			||||||
            res += blanks + 'return self.o._appy_getRefs("%s", ' \
 | 
					 | 
				
			||||||
                   'noListIfSingleObj=True).objects\n' % attrName
 | 
					 | 
				
			||||||
        elif isinstance(appyType, Computed):
 | 
					 | 
				
			||||||
            res += blanks + 'appyType = getattr(self.klass, "%s")\n' % attrName
 | 
					 | 
				
			||||||
            res += blanks + 'return self.o.getComputedValue(' \
 | 
					 | 
				
			||||||
                            'appyType.__dict__)\n'
 | 
					 | 
				
			||||||
        elif isinstance(appyType, File):
 | 
					 | 
				
			||||||
            res += blanks + 'v = self.o.%s()\n' % getterName
 | 
					 | 
				
			||||||
            res += blanks + 'if not v: return None\n'
 | 
					 | 
				
			||||||
            res += blanks + 'else: return FileWrapper(v)\n'
 | 
					 | 
				
			||||||
        elif isinstance(appyType, String) and appyType.isMultiValued():
 | 
					 | 
				
			||||||
            res += blanks + 'return list(self.o.%s())\n' % getterName
 | 
					 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            if attrName in ArchetypeFieldDescriptor.specialParams:
 | 
					            res += 'return self.o.getAppyType("%s").getValue(self.o)\n' % name
 | 
				
			||||||
                getterName = attrName.capitalize()
 | 
					        res += '    %s = property(get_%s)\n\n' % (name, name)
 | 
				
			||||||
            res += blanks + 'return self.o.%s()\n' % getterName
 | 
					 | 
				
			||||||
        res += '    %s = property(get_%s)\n\n' % (attrName, attrName)
 | 
					 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateWrapperPropertyBack(self, attrName, rel):
 | 
					    def getClasses(self, include=None):
 | 
				
			||||||
        '''Generates a wrapper property for accessing the back reference named
 | 
					        '''Returns the descriptors for all the classes in the generated
 | 
				
			||||||
           p_attrName through Archetypes relationship p_rel.'''
 | 
					           gen-application. If p_include is "all", it includes the descriptors
 | 
				
			||||||
        res = '    def get_%s(self):\n' % attrName
 | 
					           for the config-related classes (tool, flavour, etc); if
 | 
				
			||||||
        blanks = ' '*8
 | 
					           p_include is "custom", it includes descriptors for the
 | 
				
			||||||
        res += blanks + 'return self.o._appy_getRefsBack("%s", "%s", ' \
 | 
					           config-related classes for which the user has created a sub-class.'''
 | 
				
			||||||
                   'noListIfSingleObj=True)\n' % (attrName, rel)
 | 
					        if not include: return self.classes
 | 
				
			||||||
        res += '    %s = property(get_%s)\n\n' % (attrName, attrName)
 | 
					        else:
 | 
				
			||||||
 | 
					            res = self.classes[:]
 | 
				
			||||||
 | 
					            configClasses = [self.tool, self.flavour, self.podTemplate]
 | 
				
			||||||
 | 
					            if include == 'all':
 | 
				
			||||||
 | 
					                res += configClasses
 | 
				
			||||||
 | 
					            elif include == 'custom':
 | 
				
			||||||
 | 
					                res += [c for c in configClasses if c.customized]
 | 
				
			||||||
            return res
 | 
					            return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getClassesInOrder(self, allClasses):
 | 
					    def getClassesInOrder(self, allClasses):
 | 
				
			||||||
| 
						 | 
					@ -506,57 +515,45 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        # We must generate imports and wrapper definitions
 | 
					        # We must generate imports and wrapper definitions
 | 
				
			||||||
        imports = []
 | 
					        imports = []
 | 
				
			||||||
        wrappers = []
 | 
					        wrappers = []
 | 
				
			||||||
        allClasses = self.classes[:]
 | 
					        allClasses = self.getClasses(include='all')
 | 
				
			||||||
        # Add predefined classes (Tool, Flavour, PodTemplate)
 | 
					 | 
				
			||||||
        allClasses += [self.toolDescr, self.flavourDescr, self.podTemplateDescr]
 | 
					 | 
				
			||||||
        if self.customToolDescr:
 | 
					 | 
				
			||||||
            allClasses.append(self.customToolDescr)
 | 
					 | 
				
			||||||
        if self.customFlavourDescr:
 | 
					 | 
				
			||||||
            allClasses.append(self.customFlavourDescr)
 | 
					 | 
				
			||||||
        for c in self.getClassesInOrder(allClasses):
 | 
					        for c in self.getClassesInOrder(allClasses):
 | 
				
			||||||
            if not c.predefined:
 | 
					            if not c.predefined or c.customized:
 | 
				
			||||||
                moduleImport = 'import %s' % c.klass.__module__
 | 
					                moduleImport = 'import %s' % c.klass.__module__
 | 
				
			||||||
                if moduleImport not in imports:
 | 
					                if moduleImport not in imports:
 | 
				
			||||||
                    imports.append(moduleImport)
 | 
					                    imports.append(moduleImport)
 | 
				
			||||||
            # Determine parent wrapper and class
 | 
					            # Determine parent wrapper and class
 | 
				
			||||||
            parentWrapper = 'AbstractWrapper'
 | 
					            parentClasses = c.getParents(allClasses)
 | 
				
			||||||
            parentClass = '%s.%s' % (c.klass.__module__, c.klass.__name__)
 | 
					            wrapperDef = 'class %s_Wrapper(%s):\n' % \
 | 
				
			||||||
            if c.predefined:
 | 
					                         (c.name, ','.join(parentClasses))
 | 
				
			||||||
                parentClass = c.klass.__name__
 | 
					 | 
				
			||||||
            if c.klass.__bases__:
 | 
					 | 
				
			||||||
                baseClassName = c.klass.__bases__[0].__name__
 | 
					 | 
				
			||||||
                for k in allClasses:
 | 
					 | 
				
			||||||
                    if k.klass.__name__ == baseClassName:
 | 
					 | 
				
			||||||
                        parentWrapper = '%s_Wrapper' % k.name
 | 
					 | 
				
			||||||
            wrapperDef = 'class %s_Wrapper(%s, %s):\n' % \
 | 
					 | 
				
			||||||
                         (c.name, parentWrapper, parentClass)
 | 
					 | 
				
			||||||
            wrapperDef += '    security = ClassSecurityInfo()\n'
 | 
					            wrapperDef += '    security = ClassSecurityInfo()\n'
 | 
				
			||||||
            titleFound = False
 | 
					            titleFound = False
 | 
				
			||||||
            for attrName in c.orderedAttributes:
 | 
					            for attrName in c.orderedAttributes:
 | 
				
			||||||
                if attrName == 'title':
 | 
					                if attrName == 'title':
 | 
				
			||||||
                    titleFound = True
 | 
					                    titleFound = True
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
                    attrValue = getattr(c.klass, attrName)
 | 
					                    attrValue = getattr(c.klass, attrName)
 | 
				
			||||||
 | 
					                except AttributeError:
 | 
				
			||||||
 | 
					                    attrValue = getattr(c.modelClass, attrName)
 | 
				
			||||||
                if isinstance(attrValue, Type):
 | 
					                if isinstance(attrValue, Type):
 | 
				
			||||||
                    wrapperDef += self.generateWrapperProperty(attrName,
 | 
					                    wrapperDef += self.generateWrapperProperty(attrName)
 | 
				
			||||||
                                                               attrValue)
 | 
					 | 
				
			||||||
            # Generate properties for back references
 | 
					            # Generate properties for back references
 | 
				
			||||||
            if self.referers.has_key(c.name):
 | 
					            if self.referers.has_key(c.name):
 | 
				
			||||||
                for refDescr, rel in self.referers[c.name]:
 | 
					                for refDescr, rel in self.referers[c.name]:
 | 
				
			||||||
                    attrName = refDescr.appyType.back.attribute
 | 
					                    attrName = refDescr.appyType.back.attribute
 | 
				
			||||||
                    wrapperDef += self.generateWrapperPropertyBack(attrName,rel)
 | 
					                    wrapperDef += self.generateWrapperProperty(attrName)
 | 
				
			||||||
            if not titleFound:
 | 
					            if not titleFound:
 | 
				
			||||||
                # Implicitly, the title will be added by Archetypes. So I need
 | 
					                # Implicitly, the title will be added by Archetypes. So I need
 | 
				
			||||||
                # to define a property for it.
 | 
					                # to define a property for it.
 | 
				
			||||||
                wrapperDef += self.generateWrapperProperty('title', String())
 | 
					                wrapperDef += self.generateWrapperProperty('title')
 | 
				
			||||||
            if isinstance(c, CustomToolClassDescriptor) or \
 | 
					            if c.customized:
 | 
				
			||||||
               isinstance(c, CustomFlavourClassDescriptor):
 | 
					 | 
				
			||||||
                # For custom tool and flavour, add a call to a method that
 | 
					                # For custom tool and flavour, add a call to a method that
 | 
				
			||||||
                # allows to customize elements from the base class.
 | 
					                # allows to customize elements from the base class.
 | 
				
			||||||
                wrapperDef += "    if hasattr(%s, 'update'):\n        " \
 | 
					                wrapperDef += "    if hasattr(%s, 'update'):\n        " \
 | 
				
			||||||
                    "%s.update(%s.__bases__[1])\n" % (
 | 
					                    "%s.update(%s)\n" % (parentClasses[1], parentClasses[1],
 | 
				
			||||||
                    parentClass, parentClass, parentWrapper)
 | 
					                                         parentClasses[0])
 | 
				
			||||||
                # For custom tool and flavour, add security declaration that
 | 
					                # For custom tool and flavour, add security declaration that
 | 
				
			||||||
                # will allow to call their methods from ZPTs.
 | 
					                # will allow to call their methods from ZPTs.
 | 
				
			||||||
 | 
					                for parentClass in parentClasses:
 | 
				
			||||||
                    wrapperDef += "    for elem in dir(%s):\n        " \
 | 
					                    wrapperDef += "    for elem in dir(%s):\n        " \
 | 
				
			||||||
                        "if not elem.startswith('_'): security.declarePublic" \
 | 
					                        "if not elem.startswith('_'): security.declarePublic" \
 | 
				
			||||||
                        "(elem)\n" % (parentClass)
 | 
					                        "(elem)\n" % (parentClass)
 | 
				
			||||||
| 
						 | 
					@ -587,20 +584,12 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        repls = self.repls.copy()
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
        # Manage predefined fields
 | 
					        # Manage predefined fields
 | 
				
			||||||
        Tool.flavours.klass = Flavour
 | 
					        Tool.flavours.klass = Flavour
 | 
				
			||||||
        if self.customFlavourDescr:
 | 
					        if self.flavour.customized:
 | 
				
			||||||
            Tool.flavours.klass = self.customFlavourDescr.klass
 | 
					            Tool.flavours.klass = self.flavour.klass
 | 
				
			||||||
        self.toolDescr.generateSchema()
 | 
					        self.tool.generateSchema()
 | 
				
			||||||
        repls['predefinedFields'] = self.toolDescr.schema
 | 
					        repls['fields'] = self.tool.schema
 | 
				
			||||||
        repls['predefinedMethods'] = self.toolDescr.methods
 | 
					        repls['methods'] = self.tool.methods
 | 
				
			||||||
        # Manage custom fields
 | 
					        repls['wrapperClass'] = '%s_Wrapper' % self.tool.name
 | 
				
			||||||
        repls['fields'] = ''
 | 
					 | 
				
			||||||
        repls['methods'] = ''
 | 
					 | 
				
			||||||
        repls['wrapperClass'] = '%s_Wrapper' % self.toolDescr.name
 | 
					 | 
				
			||||||
        if self.customToolDescr:
 | 
					 | 
				
			||||||
            repls['fields'] = self.customToolDescr.schema
 | 
					 | 
				
			||||||
            repls['methods'] = self.customToolDescr.methods
 | 
					 | 
				
			||||||
            wrapperClass = '%s_Wrapper' % self.customToolDescr.name
 | 
					 | 
				
			||||||
            repls['wrapperClass'] = wrapperClass
 | 
					 | 
				
			||||||
        self.copyFile('ToolTemplate.py', repls, destName='%s.py'% self.toolName)
 | 
					        self.copyFile('ToolTemplate.py', repls, destName='%s.py'% self.toolName)
 | 
				
			||||||
        repls = self.repls.copy()
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
        # Create i18n-related messages
 | 
					        # Create i18n-related messages
 | 
				
			||||||
| 
						 | 
					@ -623,35 +612,32 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
                importMean = classDescr.getCreateMean('Import')
 | 
					                importMean = classDescr.getCreateMean('Import')
 | 
				
			||||||
                if importMean:
 | 
					                if importMean:
 | 
				
			||||||
                    Flavour._appy_addImportRelatedFields(classDescr)
 | 
					                    Flavour._appy_addImportRelatedFields(classDescr)
 | 
				
			||||||
        Flavour._appy_addWorkflowFields(self.flavourDescr)
 | 
					        Flavour._appy_addWorkflowFields(self.flavour)
 | 
				
			||||||
        Flavour._appy_addWorkflowFields(self.podTemplateDescr)
 | 
					        Flavour._appy_addWorkflowFields(self.podTemplate)
 | 
				
			||||||
 | 
					        # Complete self.flavour.orderedAttributes from the attributes that we
 | 
				
			||||||
 | 
					        # just added to the Flavour model class.
 | 
				
			||||||
 | 
					        for fieldName in Flavour._appy_attributes:
 | 
				
			||||||
 | 
					            if fieldName not in self.flavour.orderedAttributes:
 | 
				
			||||||
 | 
					                self.flavour.orderedAttributes.append(fieldName)
 | 
				
			||||||
        # Generate the flavour class and related i18n messages
 | 
					        # Generate the flavour class and related i18n messages
 | 
				
			||||||
        self.flavourDescr.generateSchema()
 | 
					        self.flavour.generateSchema()
 | 
				
			||||||
        self.labels += [ Msg(self.flavourName, '', Msg.FLAVOUR),
 | 
					        self.labels += [ Msg(self.flavourName, '', Msg.FLAVOUR),
 | 
				
			||||||
                         Msg('%s_edit_descr' % self.flavourName, '', ' ')]
 | 
					                         Msg('%s_edit_descr' % self.flavourName, '', ' ')]
 | 
				
			||||||
        repls = self.repls.copy()
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
        repls['predefinedFields'] = self.flavourDescr.schema
 | 
					        repls['fields'] = self.flavour.schema
 | 
				
			||||||
        repls['predefinedMethods'] = self.flavourDescr.methods
 | 
					        repls['methods'] = self.flavour.methods
 | 
				
			||||||
        # Manage custom fields
 | 
					        repls['wrapperClass'] = '%s_Wrapper' % self.flavour.name
 | 
				
			||||||
        repls['fields'] = ''
 | 
					 | 
				
			||||||
        repls['methods'] = ''
 | 
					 | 
				
			||||||
        repls['wrapperClass'] = '%s_Wrapper' % self.flavourDescr.name
 | 
					 | 
				
			||||||
        if self.customFlavourDescr:
 | 
					 | 
				
			||||||
            repls['fields'] = self.customFlavourDescr.schema
 | 
					 | 
				
			||||||
            repls['methods'] = self.customFlavourDescr.methods
 | 
					 | 
				
			||||||
            wrapperClass = '%s_Wrapper' % self.customFlavourDescr.name
 | 
					 | 
				
			||||||
            repls['wrapperClass'] = wrapperClass
 | 
					 | 
				
			||||||
        repls['metaTypes'] = [c.name for c in self.classes]
 | 
					        repls['metaTypes'] = [c.name for c in self.classes]
 | 
				
			||||||
        self.copyFile('FlavourTemplate.py', repls,
 | 
					        self.copyFile('FlavourTemplate.py', repls,
 | 
				
			||||||
                      destName='%s.py'% self.flavourName)
 | 
					                      destName='%s.py'% self.flavourName)
 | 
				
			||||||
        # Generate the PodTemplate class
 | 
					        # Generate the PodTemplate class
 | 
				
			||||||
        self.podTemplateDescr.generateSchema()
 | 
					        self.podTemplate.generateSchema()
 | 
				
			||||||
        self.labels += [ Msg(self.podTemplateName, '', Msg.POD_TEMPLATE),
 | 
					        self.labels += [ Msg(self.podTemplateName, '', Msg.POD_TEMPLATE),
 | 
				
			||||||
                         Msg('%s_edit_descr' % self.podTemplateName, '', ' ')]
 | 
					                         Msg('%s_edit_descr' % self.podTemplateName, '', ' ')]
 | 
				
			||||||
        repls = self.repls.copy()
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
        repls['fields'] = self.podTemplateDescr.schema
 | 
					        repls['fields'] = self.podTemplate.schema
 | 
				
			||||||
        repls['methods'] = self.podTemplateDescr.methods
 | 
					        repls['methods'] = self.podTemplate.methods
 | 
				
			||||||
        repls['wrapperClass'] = '%s_Wrapper' % self.podTemplateDescr.name
 | 
					        repls['wrapperClass'] = '%s_Wrapper' % self.podTemplate.name
 | 
				
			||||||
        self.copyFile('PodTemplate.py', repls,
 | 
					        self.copyFile('PodTemplate.py', repls,
 | 
				
			||||||
                        destName='%s.py' % self.podTemplateName)
 | 
					                        destName='%s.py' % self.podTemplateName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -676,7 +662,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        implements = [baseClass]
 | 
					        implements = [baseClass]
 | 
				
			||||||
        for baseClass in classDescr.klass.__bases__:
 | 
					        for baseClass in classDescr.klass.__bases__:
 | 
				
			||||||
            if self.determineAppyType(baseClass) == 'class':
 | 
					            if self.determineAppyType(baseClass) == 'class':
 | 
				
			||||||
                bcName = ArchetypesClassDescriptor.getClassName(baseClass)
 | 
					                bcName = ClassDescriptor.getClassName(baseClass)
 | 
				
			||||||
                parents.remove('ClassMixin')
 | 
					                parents.remove('ClassMixin')
 | 
				
			||||||
                parents.append(bcName)
 | 
					                parents.append(bcName)
 | 
				
			||||||
                implements.append(bcName)
 | 
					                implements.append(bcName)
 | 
				
			||||||
| 
						 | 
					@ -695,6 +681,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        if classDescr.isAbstract():
 | 
					        if classDescr.isAbstract():
 | 
				
			||||||
            register = ''
 | 
					            register = ''
 | 
				
			||||||
        repls = self.repls.copy()
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
 | 
					        classDescr.generateSchema()
 | 
				
			||||||
        repls.update({
 | 
					        repls.update({
 | 
				
			||||||
          'imports': '\n'.join(imports), 'parents': parents,
 | 
					          'imports': '\n'.join(imports), 'parents': parents,
 | 
				
			||||||
          'className': classDescr.klass.__name__,
 | 
					          'className': classDescr.klass.__name__,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,9 +6,15 @@ import os, os.path, time
 | 
				
			||||||
from StringIO import StringIO
 | 
					from StringIO import StringIO
 | 
				
			||||||
from sets import Set
 | 
					from sets import Set
 | 
				
			||||||
import appy
 | 
					import appy
 | 
				
			||||||
 | 
					from appy.gen import Type, Ref
 | 
				
			||||||
from appy.gen.utils import produceNiceMessage
 | 
					from appy.gen.utils import produceNiceMessage
 | 
				
			||||||
from appy.gen.plone25.utils import updateRolesForPermission
 | 
					from appy.gen.plone25.utils import updateRolesForPermission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZCTextIndexInfo:
 | 
				
			||||||
 | 
					    '''Silly class used for storing information about a ZCTextIndex.'''
 | 
				
			||||||
 | 
					    lexicon_id = "plone_lexicon"
 | 
				
			||||||
 | 
					    index_type = 'Okapi BM25 Rank'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PloneInstaller:
 | 
					class PloneInstaller:
 | 
				
			||||||
    '''This Plone installer runs every time the generated Plone product is
 | 
					    '''This Plone installer runs every time the generated Plone product is
 | 
				
			||||||
       installed or uninstalled (in the Plone configuration interface).'''
 | 
					       installed or uninstalled (in the Plone configuration interface).'''
 | 
				
			||||||
| 
						 | 
					@ -45,6 +51,28 @@ class PloneInstaller:
 | 
				
			||||||
        self.toolName = '%sTool' % self.productName
 | 
					        self.toolName = '%sTool' % self.productName
 | 
				
			||||||
        self.toolInstanceName = 'portal_%s' % self.productName.lower()
 | 
					        self.toolInstanceName = 'portal_%s' % self.productName.lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def updateIndexes(ploneSite, indexInfo, logger):
 | 
				
			||||||
 | 
					        '''This method creates or updates, in a p_ploneSite, definitions of
 | 
				
			||||||
 | 
					           indexes in its portal_catalog, based on index-related information
 | 
				
			||||||
 | 
					           given in p_indexInfo. p_indexInfo is a dictionary of the form
 | 
				
			||||||
 | 
					           {s_indexName:s_indexType}. Here are some examples of index types:
 | 
				
			||||||
 | 
					           "FieldIndex", "ZCTextIndex", "DateIndex".'''
 | 
				
			||||||
 | 
					        catalog = ploneSite.portal_catalog
 | 
				
			||||||
 | 
					        indexNames = catalog.indexes()
 | 
				
			||||||
 | 
					        for indexName, indexType in indexInfo.iteritems():
 | 
				
			||||||
 | 
					            if indexName not in indexNames:
 | 
				
			||||||
 | 
					                # We need to create this index
 | 
				
			||||||
 | 
					                if indexType != 'ZCTextIndex':
 | 
				
			||||||
 | 
					                    catalog.addIndex(indexName, indexType)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    catalog.addIndex(indexName,indexType,extra=ZCTextIndexInfo)
 | 
				
			||||||
 | 
					                # Indexing database content based on this index.
 | 
				
			||||||
 | 
					                catalog.reindexIndex(indexName, ploneSite.REQUEST)
 | 
				
			||||||
 | 
					                logger.info('Created index "%s" of type "%s"...' % \
 | 
				
			||||||
 | 
					                            (indexName, indexType))
 | 
				
			||||||
 | 
					        # TODO: if the index already exists but has not the same type, we
 | 
				
			||||||
 | 
					        # re-create it with the same type and we reindex it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    actionsToHide = {
 | 
					    actionsToHide = {
 | 
				
			||||||
        'portal_actions': ('sitemap', 'accessibility', 'change_state','sendto'),
 | 
					        'portal_actions': ('sitemap', 'accessibility', 'change_state','sendto'),
 | 
				
			||||||
| 
						 | 
					@ -235,18 +263,17 @@ class PloneInstaller:
 | 
				
			||||||
                                    title=produceNiceMessage(templateName))
 | 
					                                    title=produceNiceMessage(templateName))
 | 
				
			||||||
                                f.close()
 | 
					                                f.close()
 | 
				
			||||||
        # Creates the new-way templates for Pod fields if they do not exist.
 | 
					        # Creates the new-way templates for Pod fields if they do not exist.
 | 
				
			||||||
        for contentType, attrNames in self.attributes.iteritems():
 | 
					        for contentType, appyTypes in self.attributes.iteritems():
 | 
				
			||||||
            appyClass = self.tool.getAppyClass(contentType)
 | 
					            appyClass = self.tool.getAppyClass(contentType)
 | 
				
			||||||
            if not appyClass: continue # May be an abstract class
 | 
					            if not appyClass: continue # May be an abstract class
 | 
				
			||||||
            for attrName in attrNames:
 | 
					            for appyType in appyTypes:
 | 
				
			||||||
                appyType = getattr(appyClass, attrName)
 | 
					 | 
				
			||||||
                if appyType.type == 'Pod':
 | 
					                if appyType.type == 'Pod':
 | 
				
			||||||
                    # For every flavour, find the attribute that stores the
 | 
					                    # For every flavour, find the attribute that stores the
 | 
				
			||||||
                    # template, and store on it the default one specified in
 | 
					                    # template, and store on it the default one specified in
 | 
				
			||||||
                    # the appyType if no template is stored yet.
 | 
					                    # the appyType if no template is stored yet.
 | 
				
			||||||
                    for flavour in self.appyTool.flavours:
 | 
					                    for flavour in self.appyTool.flavours:
 | 
				
			||||||
                        attrName = flavour.getAttributeName(
 | 
					                        attrName = flavour.getAttributeName(
 | 
				
			||||||
                            'podTemplate', appyClass, attrName)
 | 
					                            'podTemplate', appyClass, appyType.name)
 | 
				
			||||||
                        fileObject = getattr(flavour, attrName)
 | 
					                        fileObject = getattr(flavour, attrName)
 | 
				
			||||||
                        if not fileObject or (fileObject.size == 0):
 | 
					                        if not fileObject or (fileObject.size == 0):
 | 
				
			||||||
                            # There is no file. Put the one specified in the
 | 
					                            # There is no file. Put the one specified in the
 | 
				
			||||||
| 
						 | 
					@ -298,9 +325,9 @@ class PloneInstaller:
 | 
				
			||||||
        self.tool = getattr(self.ploneSite, self.toolInstanceName)
 | 
					        self.tool = getattr(self.ploneSite, self.toolInstanceName)
 | 
				
			||||||
        self.appyTool = self.tool.appy()
 | 
					        self.appyTool = self.tool.appy()
 | 
				
			||||||
        if self.reinstall:
 | 
					        if self.reinstall:
 | 
				
			||||||
            self.tool.createOrUpdate(False)
 | 
					            self.tool.createOrUpdate(False, None)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.tool.createOrUpdate(True)
 | 
					            self.tool.createOrUpdate(True, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not self.appyTool.flavours:
 | 
					        if not self.appyTool.flavours:
 | 
				
			||||||
            # Create the default flavour
 | 
					            # Create the default flavour
 | 
				
			||||||
| 
						 | 
					@ -324,9 +351,9 @@ class PloneInstaller:
 | 
				
			||||||
            self.productName, None)
 | 
					            self.productName, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def installRolesAndGroups(self):
 | 
					    def installRolesAndGroups(self):
 | 
				
			||||||
        '''Registers roles used by workflows defined in this application if
 | 
					        '''Registers roles used by workflows and classes defined in this
 | 
				
			||||||
           they are not registered yet. Creates the corresponding groups if
 | 
					           application if they are not registered yet. Creates the corresponding
 | 
				
			||||||
           needed.'''
 | 
					           groups if needed.'''
 | 
				
			||||||
        site = self.ploneSite
 | 
					        site = self.ploneSite
 | 
				
			||||||
        data = list(site.__ac_roles__)
 | 
					        data = list(site.__ac_roles__)
 | 
				
			||||||
        for role in self.applicationRoles:
 | 
					        for role in self.applicationRoles:
 | 
				
			||||||
| 
						 | 
					@ -412,6 +439,22 @@ class PloneInstaller:
 | 
				
			||||||
        if self.minimalistPlone:
 | 
					        if self.minimalistPlone:
 | 
				
			||||||
            site.manage_changeProperties(right_slots=())
 | 
					            site.manage_changeProperties(right_slots=())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def manageIndexes(self):
 | 
				
			||||||
 | 
					        '''For every indexed field, this method installs and updates the
 | 
				
			||||||
 | 
					           corresponding index if it does not exist yet.'''
 | 
				
			||||||
 | 
					        indexInfo = {}
 | 
				
			||||||
 | 
					        for className, appyTypes in self.attributes.iteritems():
 | 
				
			||||||
 | 
					            for appyType in appyTypes:
 | 
				
			||||||
 | 
					                if appyType.indexed:
 | 
				
			||||||
 | 
					                    n = appyType.name
 | 
				
			||||||
 | 
					                    indexName = 'get%s%s' % (n[0].upper(), n[1:])
 | 
				
			||||||
 | 
					                    indexType = 'FieldIndex'
 | 
				
			||||||
 | 
					                    if (appyType.type == 'String') and appyType.isSelect:
 | 
				
			||||||
 | 
					                        indexType = 'ZCTextIndex'
 | 
				
			||||||
 | 
					                    indexInfo[indexName] = indexType
 | 
				
			||||||
 | 
					        if indexInfo:
 | 
				
			||||||
 | 
					            PloneInstaller.updateIndexes(self.ploneSite, indexInfo, self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def finalizeInstallation(self):
 | 
					    def finalizeInstallation(self):
 | 
				
			||||||
        '''Performs some final installation steps.'''
 | 
					        '''Performs some final installation steps.'''
 | 
				
			||||||
        site = self.ploneSite
 | 
					        site = self.ploneSite
 | 
				
			||||||
| 
						 | 
					@ -435,7 +478,8 @@ class PloneInstaller:
 | 
				
			||||||
            frontPageName = self.productName + 'FrontPage'
 | 
					            frontPageName = self.productName + 'FrontPage'
 | 
				
			||||||
            site.manage_changeProperties(default_page=frontPageName)
 | 
					            site.manage_changeProperties(default_page=frontPageName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def log(self, msg): print >> self.toLog, msg
 | 
					    def log(self, msg): print msg
 | 
				
			||||||
 | 
					    def info(self, msg): return self.log(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def install(self):
 | 
					    def install(self):
 | 
				
			||||||
        self.log("Installation of %s:" % self.productName)
 | 
					        self.log("Installation of %s:" % self.productName)
 | 
				
			||||||
| 
						 | 
					@ -447,9 +491,9 @@ class PloneInstaller:
 | 
				
			||||||
        self.installWorkflows()
 | 
					        self.installWorkflows()
 | 
				
			||||||
        self.installStyleSheet()
 | 
					        self.installStyleSheet()
 | 
				
			||||||
        self.managePortlets()
 | 
					        self.managePortlets()
 | 
				
			||||||
 | 
					        self.manageIndexes()
 | 
				
			||||||
        self.finalizeInstallation()
 | 
					        self.finalizeInstallation()
 | 
				
			||||||
        self.log("Installation of %s done." % self.productName)
 | 
					        self.log("Installation of %s done." % self.productName)
 | 
				
			||||||
        return self.toLog.getvalue()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def uninstallTool(self):
 | 
					    def uninstallTool(self):
 | 
				
			||||||
        site = self.ploneSite
 | 
					        site = self.ploneSite
 | 
				
			||||||
| 
						 | 
					@ -502,7 +546,7 @@ class ZopeInstaller:
 | 
				
			||||||
       generated Zope product.'''
 | 
					       generated Zope product.'''
 | 
				
			||||||
    def __init__(self, zopeContext, productName, toolClass,
 | 
					    def __init__(self, zopeContext, productName, toolClass,
 | 
				
			||||||
                 defaultAddContentPermission, addContentPermissions,
 | 
					                 defaultAddContentPermission, addContentPermissions,
 | 
				
			||||||
                 logger, ploneStuff):
 | 
					                 logger, ploneStuff, classes):
 | 
				
			||||||
        self.zopeContext = zopeContext
 | 
					        self.zopeContext = zopeContext
 | 
				
			||||||
        self.productName = productName
 | 
					        self.productName = productName
 | 
				
			||||||
        self.toolClass = toolClass
 | 
					        self.toolClass = toolClass
 | 
				
			||||||
| 
						 | 
					@ -510,6 +554,22 @@ class ZopeInstaller:
 | 
				
			||||||
        self.addContentPermissions = addContentPermissions
 | 
					        self.addContentPermissions = addContentPermissions
 | 
				
			||||||
        self.logger = logger
 | 
					        self.logger = logger
 | 
				
			||||||
        self.ploneStuff = ploneStuff # A dict of some Plone functions or vars
 | 
					        self.ploneStuff = ploneStuff # A dict of some Plone functions or vars
 | 
				
			||||||
 | 
					        self.classes = classes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def completeAppyTypes(self):
 | 
				
			||||||
 | 
					        '''We complete here the initialisation process of every Appy type of
 | 
				
			||||||
 | 
					           every gen-class of the application.'''
 | 
				
			||||||
 | 
					        for klass in self.classes:
 | 
				
			||||||
 | 
					            for baseClass in klass.wrapperClass.__bases__:
 | 
				
			||||||
 | 
					                for name, appyType in baseClass.__dict__.iteritems():
 | 
				
			||||||
 | 
					                    if isinstance(appyType, Type):
 | 
				
			||||||
 | 
					                        appyType.init(name, baseClass, self.productName)
 | 
				
			||||||
 | 
					                    # Do not forget back references
 | 
				
			||||||
 | 
					                    if isinstance(appyType, Ref):
 | 
				
			||||||
 | 
					                        bAppyType = appyType.back
 | 
				
			||||||
 | 
					                        bAppyType.init(bAppyType.attribute, appyType.klass,
 | 
				
			||||||
 | 
					                                       self.productName)
 | 
				
			||||||
 | 
					                        bAppyType.klass = baseClass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def installApplication(self):
 | 
					    def installApplication(self):
 | 
				
			||||||
        '''Performs some application-wide installation steps.'''
 | 
					        '''Performs some application-wide installation steps.'''
 | 
				
			||||||
| 
						 | 
					@ -562,6 +622,7 @@ class ZopeInstaller:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def install(self):
 | 
					    def install(self):
 | 
				
			||||||
        self.logger.info('is being installed...')
 | 
					        self.logger.info('is being installed...')
 | 
				
			||||||
 | 
					        self.completeAppyTypes()
 | 
				
			||||||
        self.installApplication()
 | 
					        self.installApplication()
 | 
				
			||||||
        self.installTool()
 | 
					        self.installTool()
 | 
				
			||||||
        self.installTypes()
 | 
					        self.installTypes()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,40 +3,5 @@ from appy.gen.plone25.mixins import AbstractMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ClassMixin(AbstractMixin):
 | 
					class ClassMixin(AbstractMixin):
 | 
				
			||||||
    _appy_meta_type = 'class'
 | 
					    _appy_meta_type = 'Class'
 | 
				
			||||||
    def _appy_fieldIsUsed(self, portalTypeName, fieldName):
 | 
					 | 
				
			||||||
        tool = self.getTool()
 | 
					 | 
				
			||||||
        flavour = tool.getFlavour(portalTypeName)
 | 
					 | 
				
			||||||
        optionalFieldsAccessor = 'getOptionalFieldsFor%s' % self.meta_type
 | 
					 | 
				
			||||||
        exec 'usedFields = flavour.%s()' % optionalFieldsAccessor
 | 
					 | 
				
			||||||
        res = False
 | 
					 | 
				
			||||||
        if fieldName in usedFields:
 | 
					 | 
				
			||||||
            res = True
 | 
					 | 
				
			||||||
        return res
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _appy_getDefaultValueFor(self, portalTypeName, fieldName):
 | 
					 | 
				
			||||||
        tool = self.getTool()
 | 
					 | 
				
			||||||
        flavour = tool.getFlavour(portalTypeName)
 | 
					 | 
				
			||||||
        fieldFound = False
 | 
					 | 
				
			||||||
        klass = self.__class__
 | 
					 | 
				
			||||||
        while not fieldFound:
 | 
					 | 
				
			||||||
            metaType = klass.meta_type
 | 
					 | 
				
			||||||
            defValueAccessor = 'getDefaultValueFor%s_%s' % (metaType, fieldName)
 | 
					 | 
				
			||||||
            if not hasattr(flavour, defValueAccessor):
 | 
					 | 
				
			||||||
                # The field belongs to a super-class.
 | 
					 | 
				
			||||||
                klass = klass.__bases__[-1]
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                fieldFound = True
 | 
					 | 
				
			||||||
        exec 'res = flavour.%s()' % defValueAccessor
 | 
					 | 
				
			||||||
        return res
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def fieldIsUsed(self, fieldName):
 | 
					 | 
				
			||||||
        '''Checks in the corresponding flavour if p_fieldName is used.'''
 | 
					 | 
				
			||||||
        portalTypeName = self._appy_getPortalType(self.REQUEST)
 | 
					 | 
				
			||||||
        return self._appy_fieldIsUsed(portalTypeName, fieldName)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getDefaultValueFor(self, fieldName):
 | 
					 | 
				
			||||||
        '''Gets in the flavour the default value for p_fieldName.'''
 | 
					 | 
				
			||||||
        portalTypeName = self._appy_getPortalType(self.REQUEST)
 | 
					 | 
				
			||||||
        return self._appy_getDefaultValueFor(portalTypeName,fieldName)
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ from appy.pod.renderer import Renderer
 | 
				
			||||||
import appy.gen
 | 
					import appy.gen
 | 
				
			||||||
from appy.gen import Type
 | 
					from appy.gen import Type
 | 
				
			||||||
from appy.gen.plone25.mixins import AbstractMixin
 | 
					from appy.gen.plone25.mixins import AbstractMixin
 | 
				
			||||||
from appy.gen.plone25.descriptors import ArchetypesClassDescriptor
 | 
					from appy.gen.plone25.descriptors import ClassDescriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Errors -----------------------------------------------------------------------
 | 
					# Errors -----------------------------------------------------------------------
 | 
				
			||||||
DELETE_TEMP_DOC_ERROR = 'A temporary document could not be removed. %s.'
 | 
					DELETE_TEMP_DOC_ERROR = 'A temporary document could not be removed. %s.'
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@ POD_ERROR = 'An error occurred while generating the document. Please ' \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class FlavourMixin(AbstractMixin):
 | 
					class FlavourMixin(AbstractMixin):
 | 
				
			||||||
    _appy_meta_type = 'flavour'
 | 
					    _appy_meta_type = 'Flavour'
 | 
				
			||||||
    def getPortalType(self, metaTypeOrAppyType):
 | 
					    def getPortalType(self, metaTypeOrAppyType):
 | 
				
			||||||
        '''Returns the name of the portal_type that is based on
 | 
					        '''Returns the name of the portal_type that is based on
 | 
				
			||||||
           p_metaTypeOrAppyType in this flavour.'''
 | 
					           p_metaTypeOrAppyType in this flavour.'''
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@ class FlavourMixin(AbstractMixin):
 | 
				
			||||||
        isAppy = False
 | 
					        isAppy = False
 | 
				
			||||||
        appName = self.getProductConfig().PROJECTNAME
 | 
					        appName = self.getProductConfig().PROJECTNAME
 | 
				
			||||||
        if not isinstance(res, basestring):
 | 
					        if not isinstance(res, basestring):
 | 
				
			||||||
            res = ArchetypesClassDescriptor.getClassName(res)
 | 
					            res = ClassDescriptor.getClassName(res)
 | 
				
			||||||
            isAppy = True
 | 
					            isAppy = True
 | 
				
			||||||
        if res.find('Extensions_appyWrappers') != -1:
 | 
					        if res.find('Extensions_appyWrappers') != -1:
 | 
				
			||||||
            isPredefined = True
 | 
					            isPredefined = True
 | 
				
			||||||
| 
						 | 
					@ -41,8 +41,9 @@ class FlavourMixin(AbstractMixin):
 | 
				
			||||||
            isPredefined = True
 | 
					            isPredefined = True
 | 
				
			||||||
            res = '%sFlavour' % appName
 | 
					            res = '%sFlavour' % appName
 | 
				
			||||||
        if not isPredefined:
 | 
					        if not isPredefined:
 | 
				
			||||||
            if self.getNumber() != 1:
 | 
					            number = self.appy().number
 | 
				
			||||||
                res = '%s_%d' % (res, self.number)
 | 
					            if number != 1:
 | 
				
			||||||
 | 
					                res = '%s_%d' % (res, number)
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def registerPortalTypes(self):
 | 
					    def registerPortalTypes(self):
 | 
				
			||||||
| 
						 | 
					@ -129,9 +130,9 @@ class FlavourMixin(AbstractMixin):
 | 
				
			||||||
        n = appyFlavour.getAttributeName('podTemplate', appyClass, fieldName)
 | 
					        n = appyFlavour.getAttributeName('podTemplate', appyClass, fieldName)
 | 
				
			||||||
        res['template'] = getattr(appyFlavour, n)
 | 
					        res['template'] = getattr(appyFlavour, n)
 | 
				
			||||||
        appyType = ploneObj.getAppyType(fieldName)
 | 
					        appyType = ploneObj.getAppyType(fieldName)
 | 
				
			||||||
        res['title'] = self.translate(appyType['label'])
 | 
					        res['title'] = self.translate(appyType.labelId)
 | 
				
			||||||
        res['context'] = appyType['context']
 | 
					        res['context'] = appyType.context
 | 
				
			||||||
        res['action'] = appyType['action']
 | 
					        res['action'] = appyType.action
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateDocument(self):
 | 
					    def generateDocument(self):
 | 
				
			||||||
| 
						 | 
					@ -225,18 +226,18 @@ class FlavourMixin(AbstractMixin):
 | 
				
			||||||
            appyTool.log(DELETE_TEMP_DOC_ERROR % str(ie), type='warning')
 | 
					            appyTool.log(DELETE_TEMP_DOC_ERROR % str(ie), type='warning')
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getAttr(self, attrName):
 | 
					    def getAttr(self, name):
 | 
				
			||||||
        '''Gets on this flavour attribute named p_attrName. Useful because we
 | 
					        '''Gets on this flavour attribute named p_attrName. Useful because we
 | 
				
			||||||
           can't use getattr directly in Zope Page Templates.'''
 | 
					           can't use getattr directly in Zope Page Templates.'''
 | 
				
			||||||
        return getattr(self, attrName, None)
 | 
					        return getattr(self.appy(), name, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _appy_getAllFields(self, contentType):
 | 
					    def _appy_getAllFields(self, contentType):
 | 
				
			||||||
        '''Returns the (translated) names of fields of p_contentType.'''
 | 
					        '''Returns the (translated) names of fields of p_contentType.'''
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        for attrName in self.getProductConfig().attributes[contentType]:
 | 
					        for appyType in self.getProductConfig().attributes[contentType]:
 | 
				
			||||||
            if attrName != 'title': # Will be included by default.
 | 
					            if appyType.name != 'title': # Will be included by default.
 | 
				
			||||||
                label = '%s_%s' % (contentType, attrName)
 | 
					                label = '%s_%s' % (contentType, appyType.name)
 | 
				
			||||||
                res.append((attrName, self.translate(label)))
 | 
					                res.append((appyType.name, self.translate(label)))
 | 
				
			||||||
        # Add object state
 | 
					        # Add object state
 | 
				
			||||||
        res.append(('workflowState', self.translate('workflow_state')))
 | 
					        res.append(('workflowState', self.translate('workflow_state')))
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
| 
						 | 
					@ -244,15 +245,10 @@ class FlavourMixin(AbstractMixin):
 | 
				
			||||||
    def _appy_getSearchableFields(self, contentType):
 | 
					    def _appy_getSearchableFields(self, contentType):
 | 
				
			||||||
        '''Returns the (translated) names of fields that may be searched on
 | 
					        '''Returns the (translated) names of fields that may be searched on
 | 
				
			||||||
           objects of type p_contentType (=indexed fields).'''
 | 
					           objects of type p_contentType (=indexed fields).'''
 | 
				
			||||||
        tool = self.getParentNode()
 | 
					 | 
				
			||||||
        appyClass = tool.getAppyClass(contentType)
 | 
					 | 
				
			||||||
        attrNames = self.getProductConfig().attributes[contentType]
 | 
					 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        for attrName in attrNames:
 | 
					        for appyType in self.getProductConfig().attributes[contentType]:
 | 
				
			||||||
            attr = getattr(appyClass, attrName)
 | 
					            if appyType.indexed:
 | 
				
			||||||
            if isinstance(attr, Type) and attr.indexed:
 | 
					                res.append((appyType.name, self.translate(appyType.labelId)))
 | 
				
			||||||
                label = '%s_%s' % (contentType, attrName)
 | 
					 | 
				
			||||||
                res.append((attrName, self.translate(label)))
 | 
					 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getSearchableFields(self, contentType):
 | 
					    def getSearchableFields(self, contentType):
 | 
				
			||||||
| 
						 | 
					@ -260,11 +256,10 @@ class FlavourMixin(AbstractMixin):
 | 
				
			||||||
           the list of fields that the user has configured in the flavour as
 | 
					           the list of fields that the user has configured in the flavour as
 | 
				
			||||||
           being effectively used in the search screen.'''
 | 
					           being effectively used in the search screen.'''
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        appyClass = self.getAppyClass(contentType)
 | 
					        fieldNames = getattr(self.appy(), 'searchFieldsFor%s' % contentType, ())
 | 
				
			||||||
        for attrName in getattr(self, 'searchFieldsFor%s' % contentType, ()):
 | 
					        for name in fieldNames:
 | 
				
			||||||
            attr = getattr(appyClass, attrName)
 | 
					            appyType = self.getAppyType(name, asDict=True,className=contentType)
 | 
				
			||||||
            dAttr = self._appy_getTypeAsDict(attrName, attr, appyClass)
 | 
					            res.append(appyType)
 | 
				
			||||||
            res.append((attrName, dAttr))
 | 
					 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getImportElements(self, contentType):
 | 
					    def getImportElements(self, contentType):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,5 +3,5 @@ from appy.gen.plone25.mixins import AbstractMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class PodTemplateMixin(AbstractMixin):
 | 
					class PodTemplateMixin(AbstractMixin):
 | 
				
			||||||
    _appy_meta_type = 'podtemplate'
 | 
					    _appy_meta_type = 'PodTemplate'
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,40 +1,18 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import re, os, os.path, Cookie
 | 
					import re, os, os.path, Cookie
 | 
				
			||||||
 | 
					from appy.shared.utils import getOsTempFolder
 | 
				
			||||||
from appy.gen import Type, Search, Selection
 | 
					from appy.gen import Type, Search, Selection
 | 
				
			||||||
from appy.gen.utils import FieldDescr, SomeObjects, sequenceTypes
 | 
					from appy.gen.utils import SomeObjects, sequenceTypes
 | 
				
			||||||
from appy.gen.plone25.mixins import AbstractMixin
 | 
					from appy.gen.plone25.mixins import AbstractMixin
 | 
				
			||||||
from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
 | 
					from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
 | 
				
			||||||
from appy.gen.plone25.wrappers import AbstractWrapper
 | 
					from appy.gen.plone25.wrappers import AbstractWrapper
 | 
				
			||||||
from appy.gen.plone25.descriptors import ArchetypesClassDescriptor
 | 
					from appy.gen.plone25.descriptors import ClassDescriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_PY = 'Please specify a file corresponding to a Python interpreter ' \
 | 
					 | 
				
			||||||
      '(ie "/usr/bin/python").'
 | 
					 | 
				
			||||||
FILE_NOT_FOUND = 'Path "%s" was not found.'
 | 
					 | 
				
			||||||
VALUE_NOT_FILE = 'Path "%s" is not a file. ' + _PY
 | 
					 | 
				
			||||||
NO_PYTHON = "Name '%s' does not starts with 'python'. " + _PY
 | 
					 | 
				
			||||||
NOT_UNO_ENABLED_PYTHON = '"%s" is not a UNO-enabled Python interpreter. ' \
 | 
					 | 
				
			||||||
                         'To check if a Python interpreter is UNO-enabled, ' \
 | 
					 | 
				
			||||||
                         'launch it and type "import uno". If you have no ' \
 | 
					 | 
				
			||||||
                         'ImportError exception it is ok.'
 | 
					 | 
				
			||||||
jsMessages = ('no_elem_selected', 'delete_confirm')
 | 
					jsMessages = ('no_elem_selected', 'delete_confirm')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ToolMixin(AbstractMixin):
 | 
					class ToolMixin(AbstractMixin):
 | 
				
			||||||
    _appy_meta_type = 'tool'
 | 
					    _appy_meta_type = 'Tool'
 | 
				
			||||||
    def _appy_validateUnoEnabledPython(self, value):
 | 
					 | 
				
			||||||
        '''This method represents the validator for field unoEnabledPython.
 | 
					 | 
				
			||||||
           This field is present on the Tool only if POD is needed.'''
 | 
					 | 
				
			||||||
        if value:
 | 
					 | 
				
			||||||
            if not os.path.exists(value):
 | 
					 | 
				
			||||||
                return FILE_NOT_FOUND % value
 | 
					 | 
				
			||||||
            if not os.path.isfile(value):
 | 
					 | 
				
			||||||
                return VALUE_NOT_FILE % value
 | 
					 | 
				
			||||||
            if not os.path.basename(value).startswith('python'):
 | 
					 | 
				
			||||||
                return NO_PYTHON % value
 | 
					 | 
				
			||||||
            if os.system('%s -c "import uno"' % value):
 | 
					 | 
				
			||||||
                return NOT_UNO_ENABLED_PYTHON % value
 | 
					 | 
				
			||||||
        return None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getFlavour(self, contextObjOrPortalType, appy=False):
 | 
					    def getFlavour(self, contextObjOrPortalType, appy=False):
 | 
				
			||||||
        '''Gets the flavour that corresponds to p_contextObjOrPortalType.'''
 | 
					        '''Gets the flavour that corresponds to p_contextObjOrPortalType.'''
 | 
				
			||||||
        if isinstance(contextObjOrPortalType, basestring):
 | 
					        if isinstance(contextObjOrPortalType, basestring):
 | 
				
			||||||
| 
						 | 
					@ -102,8 +80,11 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
    def getObject(self, uid, appy=False):
 | 
					    def getObject(self, uid, appy=False):
 | 
				
			||||||
        '''Allows to retrieve an object from its p_uid.'''
 | 
					        '''Allows to retrieve an object from its p_uid.'''
 | 
				
			||||||
        res = self.uid_catalog(UID=uid)
 | 
					        res = self.uid_catalog(UID=uid)
 | 
				
			||||||
        if res: return res[0].getObject()
 | 
					        if res:
 | 
				
			||||||
        return None
 | 
					            res = res[0].getObject()
 | 
				
			||||||
 | 
					            if appy:
 | 
				
			||||||
 | 
					                res = res.appy()
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def executeQuery(self, contentType, flavourNumber=1, searchName=None,
 | 
					    def executeQuery(self, contentType, flavourNumber=1, searchName=None,
 | 
				
			||||||
                     startNumber=0, search=None, remember=False,
 | 
					                     startNumber=0, search=None, remember=False,
 | 
				
			||||||
| 
						 | 
					@ -133,7 +114,7 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
           useful for some usages like knowing the number of objects without
 | 
					           useful for some usages like knowing the number of objects without
 | 
				
			||||||
           needing to get information about them). If no p_maxResults is
 | 
					           needing to get information about them). If no p_maxResults is
 | 
				
			||||||
           specified, the method returns maximum
 | 
					           specified, the method returns maximum
 | 
				
			||||||
           self.getNumberOfResultsPerPage(). The method returns all objects if
 | 
					           self.numberOfResultsPerPage. The method returns all objects if
 | 
				
			||||||
           p_maxResults equals string "NO_LIMIT".
 | 
					           p_maxResults equals string "NO_LIMIT".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
           If p_noSecurity is True, it gets all the objects, even those that the
 | 
					           If p_noSecurity is True, it gets all the objects, even those that the
 | 
				
			||||||
| 
						 | 
					@ -163,7 +144,7 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
            # In this case, contentType must contain a single content type.
 | 
					            # In this case, contentType must contain a single content type.
 | 
				
			||||||
            appyClass = self.getAppyClass(contentType)
 | 
					            appyClass = self.getAppyClass(contentType)
 | 
				
			||||||
            if searchName != '_advanced':
 | 
					            if searchName != '_advanced':
 | 
				
			||||||
                search = ArchetypesClassDescriptor.getSearch(
 | 
					                search = ClassDescriptor.getSearch(
 | 
				
			||||||
                    appyClass, searchName)
 | 
					                    appyClass, searchName)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                fields = self.REQUEST.SESSION['searchCriteria']
 | 
					                fields = self.REQUEST.SESSION['searchCriteria']
 | 
				
			||||||
| 
						 | 
					@ -201,7 +182,7 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
            # Return brains only.
 | 
					            # Return brains only.
 | 
				
			||||||
            if not maxResults: return brains
 | 
					            if not maxResults: return brains
 | 
				
			||||||
            else: return brains[:maxResults]
 | 
					            else: return brains[:maxResults]
 | 
				
			||||||
        if not maxResults: maxResults = self.getNumberOfResultsPerPage()
 | 
					        if not maxResults: maxResults = self.appy().numberOfResultsPerPage
 | 
				
			||||||
        elif maxResults == 'NO_LIMIT': maxResults = None
 | 
					        elif maxResults == 'NO_LIMIT': maxResults = None
 | 
				
			||||||
        res = SomeObjects(brains, maxResults, startNumber,noSecurity=noSecurity)
 | 
					        res = SomeObjects(brains, maxResults, startNumber,noSecurity=noSecurity)
 | 
				
			||||||
        res.brainsToObjects()
 | 
					        res.brainsToObjects()
 | 
				
			||||||
| 
						 | 
					@ -249,26 +230,31 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
    def getResultColumns(self, anObject, contentType):
 | 
					    def getResultColumns(self, anObject, contentType):
 | 
				
			||||||
        '''What columns must I show when displaying a list of root class
 | 
					        '''What columns must I show when displaying a list of root class
 | 
				
			||||||
           instances? Result is a list of tuples containing the name of the
 | 
					           instances? Result is a list of tuples containing the name of the
 | 
				
			||||||
           column (=name of the field) and a FieldDescr instance.'''
 | 
					           column (=name of the field) and the corresponding appyType (dict
 | 
				
			||||||
 | 
					           version).'''
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        for fieldName in self.getResultColumnsNames(contentType):
 | 
					        for fieldName in self.getResultColumnsNames(contentType):
 | 
				
			||||||
            if fieldName == 'workflowState':
 | 
					            if fieldName == 'workflowState':
 | 
				
			||||||
                # We do not return a FieldDescr instance if the attributes is
 | 
					                # We do not return a appyType if the attribute is not a *real*
 | 
				
			||||||
                # not a *real* attribute but the workfow state.
 | 
					                # attribute, but the workfow state.
 | 
				
			||||||
                res.append(fieldName)
 | 
					                res.append(fieldName)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                # Create a FieldDescr instance
 | 
					                appyType = anObject.getAppyType(fieldName, asDict=True)
 | 
				
			||||||
                appyType = anObject.getAppyType(fieldName)
 | 
					 | 
				
			||||||
                if not appyType:
 | 
					                if not appyType:
 | 
				
			||||||
                    res.append({'atField': None, 'name': fieldName})
 | 
					                    res.append({'name': fieldName, '_wrong': True})
 | 
				
			||||||
                    # The field name is wrong.
 | 
					                    # The field name is wrong.
 | 
				
			||||||
                    # We return it so we can show it in an error message.
 | 
					                    # We return it so we can show it in an error message.
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    atField = anObject.schema.get(fieldName)
 | 
					                    res.append(appyType)
 | 
				
			||||||
                    fieldDescr = FieldDescr(atField, appyType, None)
 | 
					 | 
				
			||||||
                    res.append(fieldDescr.get())
 | 
					 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def truncateValue(self, value, appyType):
 | 
				
			||||||
 | 
					        '''Truncates the p_value according to p_appyType width.'''
 | 
				
			||||||
 | 
					        maxWidth = appyType['width']
 | 
				
			||||||
 | 
					        if len(value) > maxWidth:
 | 
				
			||||||
 | 
					            return value[:maxWidth] + '...'
 | 
				
			||||||
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    xhtmlToText = re.compile('<.*?>', re.S)
 | 
					    xhtmlToText = re.compile('<.*?>', re.S)
 | 
				
			||||||
    def getReferenceLabel(self, brain, appyType):
 | 
					    def getReferenceLabel(self, brain, appyType):
 | 
				
			||||||
        '''p_appyType is a Ref with link=True. I need to display, on an edit
 | 
					        '''p_appyType is a Ref with link=True. I need to display, on an edit
 | 
				
			||||||
| 
						 | 
					@ -288,8 +274,8 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
            elif isinstance(value, basestring):
 | 
					            elif isinstance(value, basestring):
 | 
				
			||||||
                value = value.decode('utf-8')
 | 
					                value = value.decode('utf-8')
 | 
				
			||||||
                refAppyType = appyObj.o.getAppyType(fieldName)
 | 
					                refAppyType = appyObj.o.getAppyType(fieldName)
 | 
				
			||||||
                if refAppyType and (refAppyType['type'] == 'String') and \
 | 
					                if refAppyType and (refAppyType.type == 'String') and \
 | 
				
			||||||
                   (refAppyType['format'] == 2):
 | 
					                   (refAppyType.format == 2):
 | 
				
			||||||
                    value = self.xhtmlToText.sub(' ', value)
 | 
					                    value = self.xhtmlToText.sub(' ', value)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                value = str(value)
 | 
					                value = str(value)
 | 
				
			||||||
| 
						 | 
					@ -312,13 +298,21 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
        appName = self.getProductConfig().PROJECTNAME
 | 
					        appName = self.getProductConfig().PROJECTNAME
 | 
				
			||||||
        return self.utranslate(label, self.translationMapping, domain=appName)
 | 
					        return self.utranslate(label, self.translationMapping, domain=appName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getPublishedObject(self):
 | 
					    def getPublishedObject(self, rootClasses):
 | 
				
			||||||
        '''Gets the currently published object.'''
 | 
					        '''Gets the currently published object, if its meta_class is among
 | 
				
			||||||
 | 
					           p_rootClasses or if it is the corresponding tool or flavour.'''
 | 
				
			||||||
        rq = self.REQUEST
 | 
					        rq = self.REQUEST
 | 
				
			||||||
        obj = rq['PUBLISHED']
 | 
					        obj = rq['PUBLISHED']
 | 
				
			||||||
        parent = obj.getParentNode()
 | 
					        parent = obj.getParentNode()
 | 
				
			||||||
        if parent.id == 'skyn': return parent.getParentNode()
 | 
					        if parent.id == 'skyn':
 | 
				
			||||||
        return rq['PUBLISHED']
 | 
					            obj = parent.getParentNode()
 | 
				
			||||||
 | 
					        if obj.meta_type in rootClasses:
 | 
				
			||||||
 | 
					            return obj
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            appName = self.getAppName()
 | 
				
			||||||
 | 
					            if obj.meta_type in ('%sTool' % appName, '%sFlavour' % appName):
 | 
				
			||||||
 | 
					                return obj
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getAppyClass(self, contentType):
 | 
					    def getAppyClass(self, contentType):
 | 
				
			||||||
        '''Gets the Appy Python class that is related to p_contentType.'''
 | 
					        '''Gets the Appy Python class that is related to p_contentType.'''
 | 
				
			||||||
| 
						 | 
					@ -359,6 +353,17 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
                    res[means.id] = means.__dict__
 | 
					                    res[means.id] = means.__dict__
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def userMayAdd(self, rootClass):
 | 
				
			||||||
 | 
					        '''For deciding if a user may add a new instance of a class, beyond the
 | 
				
			||||||
 | 
					           permission-based check, we can have a custom method that proposes an
 | 
				
			||||||
 | 
					           additional condition. This method checks if there is such a custom
 | 
				
			||||||
 | 
					           method (must be named "mayCreate") define on p_rootClass, and calls
 | 
				
			||||||
 | 
					           it if yes. If no, it returns True.'''
 | 
				
			||||||
 | 
					        pythonClass = self.getAppyClass(rootClass)
 | 
				
			||||||
 | 
					        if 'mayCreate' in pythonClass.__dict__:
 | 
				
			||||||
 | 
					            return pythonClass.mayCreate(self.appy())
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def onImportObjects(self):
 | 
					    def onImportObjects(self):
 | 
				
			||||||
        '''This method is called when the user wants to create objects from
 | 
					        '''This method is called when the user wants to create objects from
 | 
				
			||||||
           external data.'''
 | 
					           external data.'''
 | 
				
			||||||
| 
						 | 
					@ -503,7 +508,7 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
        appyClass = self.getAppyClass(contentType)
 | 
					        appyClass = self.getAppyClass(contentType)
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        visitedGroups = {} # Names of already visited search groups
 | 
					        visitedGroups = {} # Names of already visited search groups
 | 
				
			||||||
        for search in ArchetypesClassDescriptor.getSearches(appyClass):
 | 
					        for search in ClassDescriptor.getSearches(appyClass):
 | 
				
			||||||
            # Determine first group label, we will need it.
 | 
					            # Determine first group label, we will need it.
 | 
				
			||||||
            groupLabel = ''
 | 
					            groupLabel = ''
 | 
				
			||||||
            if search.group:
 | 
					            if search.group:
 | 
				
			||||||
| 
						 | 
					@ -610,7 +615,7 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
        if t == 'ref': # Manage navigation from a reference
 | 
					        if t == 'ref': # Manage navigation from a reference
 | 
				
			||||||
            fieldName = d2
 | 
					            fieldName = d2
 | 
				
			||||||
            masterObj = self.getObject(d1)
 | 
					            masterObj = self.getObject(d1)
 | 
				
			||||||
            batchSize = masterObj.getAppyType(fieldName)['maxPerPage']
 | 
					            batchSize = masterObj.getAppyType(fieldName).maxPerPage
 | 
				
			||||||
            uids = getattr(masterObj, '_appy_%s' % fieldName)
 | 
					            uids = getattr(masterObj, '_appy_%s' % fieldName)
 | 
				
			||||||
            # In the case of a reference, we retrieve ALL surrounding objects.
 | 
					            # In the case of a reference, we retrieve ALL surrounding objects.
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
| 
						 | 
					@ -679,7 +684,6 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
           into a list of lists, where every sub-list has length p_numberOfRows.
 | 
					           into a list of lists, where every sub-list has length p_numberOfRows.
 | 
				
			||||||
           This method is typically used for rendering elements in a table of
 | 
					           This method is typically used for rendering elements in a table of
 | 
				
			||||||
           p_numberOfRows rows.'''
 | 
					           p_numberOfRows rows.'''
 | 
				
			||||||
        if numberOfRows > 1:
 | 
					 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        row = []
 | 
					        row = []
 | 
				
			||||||
        for elem in data:
 | 
					        for elem in data:
 | 
				
			||||||
| 
						 | 
					@ -692,8 +696,6 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
            while len(row) < numberOfRows: row.append(None)
 | 
					            while len(row) < numberOfRows: row.append(None)
 | 
				
			||||||
            res.append(row)
 | 
					            res.append(row)
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return data
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def truncate(self, value, numberOfChars):
 | 
					    def truncate(self, value, numberOfChars):
 | 
				
			||||||
        '''Truncates string p_value to p_numberOfChars.'''
 | 
					        '''Truncates string p_value to p_numberOfChars.'''
 | 
				
			||||||
| 
						 | 
					@ -708,22 +710,6 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
        '''Gets the translated month name of month numbered p_monthNumber.'''
 | 
					        '''Gets the translated month name of month numbered p_monthNumber.'''
 | 
				
			||||||
        return self.translate(self.monthsIds[int(monthNumber)], domain='plone')
 | 
					        return self.translate(self.monthsIds[int(monthNumber)], domain='plone')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getSelectValues(self, appyType):
 | 
					 | 
				
			||||||
        '''Return the possible values (with their translation) of String type
 | 
					 | 
				
			||||||
           p_appyType (dict version) which is a string whose validator limits
 | 
					 | 
				
			||||||
           the possible values, either statically (validator is simply a list
 | 
					 | 
				
			||||||
           of values) or dynamically (validator is a Selection instance).'''
 | 
					 | 
				
			||||||
        validator = appyType['validator']
 | 
					 | 
				
			||||||
        if isinstance(validator, Selection):
 | 
					 | 
				
			||||||
            vocab = self._appy_getDynamicDisplayList(validator.methodName)
 | 
					 | 
				
			||||||
            return vocab.items()
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            res = []
 | 
					 | 
				
			||||||
            for v in validator:
 | 
					 | 
				
			||||||
                text = self.translate('%s_list_%s' % (appyType['label'], v))
 | 
					 | 
				
			||||||
                res.append((v, self.truncate(text, 30)))
 | 
					 | 
				
			||||||
        return res
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def logout(self):
 | 
					    def logout(self):
 | 
				
			||||||
        '''Logs out the current user when he clicks on "disconnect".'''
 | 
					        '''Logs out the current user when he clicks on "disconnect".'''
 | 
				
			||||||
        rq = self.REQUEST
 | 
					        rq = self.REQUEST
 | 
				
			||||||
| 
						 | 
					@ -748,4 +734,20 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
        from appy.gen.plone25.installer import loggedUsers
 | 
					        from appy.gen.plone25.installer import loggedUsers
 | 
				
			||||||
        if loggedUsers.has_key(userId): del loggedUsers[userId]
 | 
					        if loggedUsers.has_key(userId): del loggedUsers[userId]
 | 
				
			||||||
        return self.goto(self.getParentNode().absolute_url())
 | 
					        return self.goto(self.getParentNode().absolute_url())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tempFile(self):
 | 
				
			||||||
 | 
					        '''A temp file has been created in a temp folder. This method returns
 | 
				
			||||||
 | 
					           this file to the browser.'''
 | 
				
			||||||
 | 
					        rq = self.REQUEST
 | 
				
			||||||
 | 
					        baseFolder = os.path.join(getOsTempFolder(), self.getAppName())
 | 
				
			||||||
 | 
					        baseFolder = os.path.join(baseFolder, rq.SESSION.id)
 | 
				
			||||||
 | 
					        fileName   = os.path.join(baseFolder, rq.get('name', ''))
 | 
				
			||||||
 | 
					        if os.path.exists(fileName):
 | 
				
			||||||
 | 
					            f = file(fileName)
 | 
				
			||||||
 | 
					            content = f.read()
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					            # Remove the temp file
 | 
				
			||||||
 | 
					            os.remove(fileName)
 | 
				
			||||||
 | 
					            return content
 | 
				
			||||||
 | 
					        return 'File does not exist'
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import copy, types
 | 
					import copy, types
 | 
				
			||||||
from appy.gen import Type, Integer, String, File, Ref, Boolean, Selection
 | 
					from appy.gen import Type, Integer, String, File, Ref, Boolean, Selection, Group
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ModelClass:
 | 
					class ModelClass:
 | 
				
			||||||
| 
						 | 
					@ -17,10 +17,12 @@ class ModelClass:
 | 
				
			||||||
       prefixed with _appy_ in order to avoid name conflicts with user-defined
 | 
					       prefixed with _appy_ in order to avoid name conflicts with user-defined
 | 
				
			||||||
       parts of the application model.'''
 | 
					       parts of the application model.'''
 | 
				
			||||||
    _appy_attributes = [] # We need to keep track of attributes order.
 | 
					    _appy_attributes = [] # We need to keep track of attributes order.
 | 
				
			||||||
    _appy_notinit = ('id', 'type', 'pythonType', 'slaves', 'selfClass',
 | 
					    # When creating a new instance of a ModelClass, the following attributes
 | 
				
			||||||
                     'phase', 'pageShow', 'isSelect') # When creating a new
 | 
					    # must not be given in the constructor (they are computed attributes).
 | 
				
			||||||
                     # instance of a ModelClass, those attributes must not be
 | 
					    _appy_notinit = ('id', 'type', 'pythonType', 'slaves', 'phase', 'pageShow',
 | 
				
			||||||
                     # given in the constructor.
 | 
					                     'isSelect', 'hasLabel', 'hasDescr', 'hasHelp',
 | 
				
			||||||
 | 
					                     'master_css', 'layouts', 'required', 'filterable',
 | 
				
			||||||
 | 
					                     'validable', 'backd', 'isBack')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def _appy_addField(klass, fieldName, fieldType, classDescr):
 | 
					    def _appy_addField(klass, fieldName, fieldType, classDescr):
 | 
				
			||||||
| 
						 | 
					@ -38,8 +40,11 @@ class ModelClass:
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            if isinstance(attrValue, basestring):
 | 
					            if isinstance(attrValue, basestring):
 | 
				
			||||||
                attrValue = '"%s"' % attrValue
 | 
					                attrValue = '"%s"' % attrValue
 | 
				
			||||||
            elif isinstance(attrValue, Type):
 | 
					            elif isinstance(attrValue, Ref):
 | 
				
			||||||
 | 
					                if attrValue.isBack:
 | 
				
			||||||
                    attrValue = klass._appy_getTypeBody(attrValue)
 | 
					                    attrValue = klass._appy_getTypeBody(attrValue)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
            elif type(attrValue) == type(ModelClass):
 | 
					            elif type(attrValue) == type(ModelClass):
 | 
				
			||||||
                moduleName = attrValue.__module__
 | 
					                moduleName = attrValue.__module__
 | 
				
			||||||
                if moduleName.startswith('appy.gen'):
 | 
					                if moduleName.startswith('appy.gen'):
 | 
				
			||||||
| 
						 | 
					@ -48,6 +53,10 @@ class ModelClass:
 | 
				
			||||||
                    attrValue = '%s.%s' % (moduleName, attrValue.__name__)
 | 
					                    attrValue = '%s.%s' % (moduleName, attrValue.__name__)
 | 
				
			||||||
            elif isinstance(attrValue, Selection):
 | 
					            elif isinstance(attrValue, Selection):
 | 
				
			||||||
                attrValue = 'Selection("%s")' % attrValue.methodName
 | 
					                attrValue = 'Selection("%s")' % attrValue.methodName
 | 
				
			||||||
 | 
					            elif isinstance(attrValue, Group):
 | 
				
			||||||
 | 
					                attrValue = 'Group("%s")' % attrValue.name
 | 
				
			||||||
 | 
					            elif type(attrValue) == types.FunctionType:
 | 
				
			||||||
 | 
					                attrValue = '%sWrapper.%s'% (klass.__name__, attrValue.__name__)
 | 
				
			||||||
            typeArgs += '%s=%s,' % (attrName, attrValue)
 | 
					            typeArgs += '%s=%s,' % (attrName, attrValue)
 | 
				
			||||||
        return '%s(%s)' % (appyType.__class__.__name__, typeArgs)
 | 
					        return '%s(%s)' % (appyType.__class__.__name__, typeArgs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,10 +115,15 @@ class Flavour(ModelClass):
 | 
				
			||||||
        '''From a given p_appyType, produce a type definition suitable for
 | 
					        '''From a given p_appyType, produce a type definition suitable for
 | 
				
			||||||
           storing the default value for this field.'''
 | 
					           storing the default value for this field.'''
 | 
				
			||||||
        res = copy.copy(appyType)
 | 
					        res = copy.copy(appyType)
 | 
				
			||||||
 | 
					        # A fiekd in the flavour can't have parameters that would lead to the
 | 
				
			||||||
 | 
					        # creation of new fields in the flavour.
 | 
				
			||||||
        res.editDefault = False
 | 
					        res.editDefault = False
 | 
				
			||||||
        res.optional = False
 | 
					        res.optional = False
 | 
				
			||||||
        res.show = True
 | 
					        res.show = True
 | 
				
			||||||
 | 
					        res.group = copy.copy(appyType.group)
 | 
				
			||||||
        res.phase = 'main'
 | 
					        res.phase = 'main'
 | 
				
			||||||
 | 
					        # Set default layouts for all Flavour fields
 | 
				
			||||||
 | 
					        res.layouts = None
 | 
				
			||||||
        res.specificReadPermission = False
 | 
					        res.specificReadPermission = False
 | 
				
			||||||
        res.specificWritePermission = False
 | 
					        res.specificWritePermission = False
 | 
				
			||||||
        res.multiplicity = (0, appyType.multiplicity[1])
 | 
					        res.multiplicity = (0, appyType.multiplicity[1])
 | 
				
			||||||
| 
						 | 
					@ -136,7 +150,7 @@ class Flavour(ModelClass):
 | 
				
			||||||
            klass._appy_addField(fieldName, fieldType, fieldDescr.classDescr)
 | 
					            klass._appy_addField(fieldName, fieldType, fieldDescr.classDescr)
 | 
				
			||||||
        fieldType.validator.append(fieldDescr.fieldName)
 | 
					        fieldType.validator.append(fieldDescr.fieldName)
 | 
				
			||||||
        fieldType.page = 'data'
 | 
					        fieldType.page = 'data'
 | 
				
			||||||
        fieldType.group = fieldDescr.classDescr.klass.__name__
 | 
					        fieldType.group = Group(fieldDescr.classDescr.klass.__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def _appy_addDefaultField(klass, fieldDescr):
 | 
					    def _appy_addDefaultField(klass, fieldDescr):
 | 
				
			||||||
| 
						 | 
					@ -145,7 +159,7 @@ class Flavour(ModelClass):
 | 
				
			||||||
        fieldType = klass._appy_copyField(fieldDescr.appyType)
 | 
					        fieldType = klass._appy_copyField(fieldDescr.appyType)
 | 
				
			||||||
        klass._appy_addField(fieldName, fieldType, fieldDescr.classDescr)
 | 
					        klass._appy_addField(fieldName, fieldType, fieldDescr.classDescr)
 | 
				
			||||||
        fieldType.page = 'data'
 | 
					        fieldType.page = 'data'
 | 
				
			||||||
        fieldType.group = fieldDescr.classDescr.klass.__name__
 | 
					        fieldType.group = Group(fieldDescr.classDescr.klass.__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def _appy_addPodRelatedFields(klass, fieldDescr):
 | 
					    def _appy_addPodRelatedFields(klass, fieldDescr):
 | 
				
			||||||
| 
						 | 
					@ -276,7 +290,9 @@ class Tool(ModelClass):
 | 
				
			||||||
                   # First arg is None because we don't know yet if it will link
 | 
					                   # First arg is None because we don't know yet if it will link
 | 
				
			||||||
                   # to the predefined Flavour class or a custom class defined
 | 
					                   # to the predefined Flavour class or a custom class defined
 | 
				
			||||||
                   # in the application.
 | 
					                   # in the application.
 | 
				
			||||||
    unoEnabledPython = String(group="connectionToOpenOffice")
 | 
					    def validPythonWithUno(self, value): pass
 | 
				
			||||||
 | 
					    unoEnabledPython = String(group="connectionToOpenOffice",
 | 
				
			||||||
 | 
					                              validator=validPythonWithUno)
 | 
				
			||||||
    openOfficePort = Integer(default=2002, group="connectionToOpenOffice")
 | 
					    openOfficePort = Integer(default=2002, group="connectionToOpenOffice")
 | 
				
			||||||
    numberOfResultsPerPage = Integer(default=30)
 | 
					    numberOfResultsPerPage = Integer(default=30)
 | 
				
			||||||
    listBoxesMaximumWidth = Integer(default=100)
 | 
					    listBoxesMaximumWidth = Integer(default=100)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,14 +12,15 @@
 | 
				
			||||||
                  member     context/portal_membership/getAuthenticatedMember;
 | 
					                  member     context/portal_membership/getAuthenticatedMember;
 | 
				
			||||||
                  portal     context/portal_url/getPortalObject;
 | 
					                  portal     context/portal_url/getPortalObject;
 | 
				
			||||||
                  portal_url context/portal_url/getPortalPath;
 | 
					                  portal_url context/portal_url/getPortalPath;
 | 
				
			||||||
                  dummy python:response.setHeader('Content-Type','text/html;;charset=utf-8');
 | 
					                  template   python: contextObj.getPageTemplate(portal.skyn, page);
 | 
				
			||||||
                  dummy2 python:response.setHeader('Expires', 'Mon, 11 Dec 1975 12:05:05 GMT');
 | 
					                  dummy      python: response.setHeader('Content-Type','text/html;;charset=utf-8');
 | 
				
			||||||
                  dummy3 python:response.setHeader('CacheControl', 'no-cache')">
 | 
					                  dummy2     python: response.setHeader('Expires', 'Mon, 11 Dec 1975 12:05:05 GMT');
 | 
				
			||||||
 | 
					                  dummy3     python: response.setHeader('CacheControl', 'no-cache')">
 | 
				
			||||||
  <tal:comment replace="nothing">Keys "Expires" and "CacheControl" are used for preventing IE to cache
 | 
					  <tal:comment replace="nothing">Keys "Expires" and "CacheControl" are used for preventing IE to cache
 | 
				
			||||||
    this page. Indeed, this page is retrieved through an asynchronous XMLHttpRequest by the browser, and
 | 
					    this page. Indeed, this page is retrieved through an asynchronous XMLHttpRequest by the browser, and
 | 
				
			||||||
    IE caches this by default.</tal:comment>
 | 
					    IE caches this by default.</tal:comment>
 | 
				
			||||||
  <tal:executeAction condition="action">
 | 
					  <tal:executeAction condition="action">
 | 
				
			||||||
    <tal:do define="dummy python: contextObj.getAppyValue('on'+action)()" omit-tag=""/>
 | 
					    <tal:do define="dummy python: contextObj.getMethod('on'+action)()" omit-tag=""/>
 | 
				
			||||||
  </tal:executeAction>
 | 
					  </tal:executeAction>
 | 
				
			||||||
  <metal:callMacro use-macro="python: portal.skyn.get(page).macros.get(macro)"/>
 | 
					  <metal:callMacro use-macro="python: template.macros.get(macro)"/>
 | 
				
			||||||
</tal:ajax>
 | 
					</tal:ajax>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/cancel.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.4 KiB  | 
| 
						 | 
					@ -12,4 +12,4 @@ else:
 | 
				
			||||||
        from Products.CMFCore.utils import getToolByName
 | 
					        from Products.CMFCore.utils import getToolByName
 | 
				
			||||||
        portal = getToolByName(obj, 'portal_url').getPortalObject()
 | 
					        portal = getToolByName(obj, 'portal_url').getPortalObject()
 | 
				
			||||||
        obj = portal.get('portal_%s' % obj.id.lower()) # The tool
 | 
					        obj = portal.get('portal_%s' % obj.id.lower()) # The tool
 | 
				
			||||||
return obj.getAppyValue('on'+action)()
 | 
					return obj.getMethod('on'+action)()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,24 +1,18 @@
 | 
				
			||||||
<tal:block metal:define-macro="master"
 | 
					<tal:edit metal:define-macro="master"
 | 
				
			||||||
          define="contextObj  python:context.getParentNode();
 | 
					          define="contextObj  python:context.getParentNode();
 | 
				
			||||||
                  errors      request/errors | python:{};
 | 
					                  errors      request/errors | python:{};
 | 
				
			||||||
                   schematas contextObj/Schemata;
 | 
					                  layoutType  python:'edit';
 | 
				
			||||||
                   fieldsets python:[key for key in schematas.keys() if (key != 'metadata') and (schematas[key].editableFields(contextObj, visible_only=True))];
 | 
					                  layout      python: contextObj.getPageLayout(layoutType);
 | 
				
			||||||
                   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(contextObj);
 | 
					 | 
				
			||||||
                   lockable python:hasattr(contextObj, 'wl_isLocked');
 | 
					 | 
				
			||||||
                   isLocked python:lockable and contextObj.wl_isLocked();
 | 
					 | 
				
			||||||
                   isEdit python:True;
 | 
					 | 
				
			||||||
                  tool        contextObj/getTool;
 | 
					                  tool        contextObj/getTool;
 | 
				
			||||||
                  flavour     python: tool.getFlavour(contextObj);
 | 
					                  flavour     python: tool.getFlavour(contextObj);
 | 
				
			||||||
                  appFolder   tool/getAppFolder;
 | 
					                  appFolder   tool/getAppFolder;
 | 
				
			||||||
                   appName appFolder/id;
 | 
					                  appName     appFolder/getId;
 | 
				
			||||||
                   css python:contextObj.getUniqueWidgetAttr(fields, 'helper_css');
 | 
					                  page        request/page|python:'main';
 | 
				
			||||||
                   js python:contextObj.getUniqueWidgetAttr(fields, 'helper_js');
 | 
					                  cssAndJs    python: contextObj.getCssAndJs(layoutType, page);
 | 
				
			||||||
                   phaseInfo python: contextObj.getAppyPhases(fieldset=fieldset, forPlone=True);
 | 
					                  css         python: cssAndJs[0];
 | 
				
			||||||
                   phase request/phase|phaseInfo/name;
 | 
					                  js          python: cssAndJs[1];
 | 
				
			||||||
                   appyPages python: contextObj.getAppyPages(phase);
 | 
					                  phaseInfo   python: contextObj.getAppyPhases(page=page);
 | 
				
			||||||
                   pageName python: contextObj.getAppyPage(isEdit, phaseInfo, appyPages);">
 | 
					                  phase       phaseInfo/name">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
 | 
					<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
 | 
				
			||||||
      xmlns:tal="http://xml.zope.org/namespaces/tal"
 | 
					      xmlns:tal="http://xml.zope.org/namespaces/tal"
 | 
				
			||||||
| 
						 | 
					@ -32,80 +26,38 @@
 | 
				
			||||||
    <div tal:define="dummy python:request.set('disable_border', 1)" />
 | 
					    <div tal:define="dummy python:request.set('disable_border', 1)" />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <tal:comment replace="nothing">Archetypes stuff for managing Javascript and CSS.
 | 
					  <tal:comment replace="nothing">Include type-specific CSS and JS.</tal:comment>
 | 
				
			||||||
    If I remove this stuff, Javascript popup for dates does not work anyore.</tal:comment>
 | 
					  <metal:js fill-slot="javascript_head_slot">
 | 
				
			||||||
  <metal:javascript_head fill-slot="javascript_head_slot">
 | 
					    <tal:js condition="js" repeat="jsFile js">
 | 
				
			||||||
    <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"
 | 
					      <script type="text/javascript" charset="iso-8859-1"
 | 
				
			||||||
              tal:condition="python:exists('portal/%s' % item)"
 | 
					              tal:condition="python:exists('portal/%s' % jsFile)"
 | 
				
			||||||
              tal:attributes="src string:$portal_url/$item">
 | 
					              tal:attributes="src string:$portal_url/$jsFile">
 | 
				
			||||||
      </script>
 | 
					      </script>
 | 
				
			||||||
    </tal:js>
 | 
					    </tal:js>
 | 
				
			||||||
    <tal:block define="macro edit_macros/javascript_head | nothing" condition="macro">
 | 
					  </metal:js>
 | 
				
			||||||
      <metal:block use-macro="macro" />
 | 
					 | 
				
			||||||
    </tal:block>
 | 
					 | 
				
			||||||
  </metal:javascript_head>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <metal:css fill-slot="css_slot">
 | 
					  <metal:css fill-slot="css_slot">
 | 
				
			||||||
    <tal:css condition="css" repeat="item css">
 | 
					    <tal:css condition="css" repeat="cssFile css">
 | 
				
			||||||
      <style type="text/css" media="all"
 | 
					      <style type="text/css" media="all"
 | 
				
			||||||
             tal:condition="python:exists('portal/%s' % item)"
 | 
					             tal:condition="python:exists('portal/%s' % cssFile)"
 | 
				
			||||||
             tal:content="structure string:<!-- @import url($portal_url/$item); -->">
 | 
					             tal:content="structure string:<!-- @import url($portal_url/$cssFile); -->">
 | 
				
			||||||
      </style>
 | 
					      </style>
 | 
				
			||||||
    </tal:css>
 | 
					    </tal:css>
 | 
				
			||||||
    <tal:block define="macro edit_macros/css | nothing" condition="macro">
 | 
					 | 
				
			||||||
      <metal:block use-macro="macro" />
 | 
					 | 
				
			||||||
    </tal:block>
 | 
					 | 
				
			||||||
  </metal:css>
 | 
					  </metal:css>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <body>
 | 
					  <body>
 | 
				
			||||||
    <metal:fill fill-slot="main">
 | 
					    <metal:fill fill-slot="main">
 | 
				
			||||||
      <div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
 | 
					      <metal:prologue use-macro="here/skyn/page/macros/prologue"/>
 | 
				
			||||||
      <div metal:use-macro="here/skyn/macros/macros/showPageHeader"/>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <form name="edit_form" method="post" enctype="multipart/form-data"
 | 
					      <form name="edit_form" method="post" enctype="multipart/form-data"
 | 
				
			||||||
            class="enableUnloadProtection atBaseEditForm"
 | 
					            class="enableUnloadProtection atBaseEditForm"
 | 
				
			||||||
            tal:attributes="action python: contextObj.absolute_url()+'/skyn/do'">
 | 
					            tal:attributes="action python: contextObj.absolute_url()+'/skyn/do'">
 | 
				
			||||||
        <div metal:use-macro="here/skyn/macros/macros/listFields" /><br/>
 | 
					 | 
				
			||||||
        <input type="hidden" name="action" value="Update"/>
 | 
					        <input type="hidden" name="action" value="Update"/>
 | 
				
			||||||
        <input type="hidden" name="fieldset" tal:attributes="value fieldset"/>
 | 
					        <input type="hidden" name="page" tal:attributes="value page"/>
 | 
				
			||||||
        <input type="hidden" name="pageName" tal:attributes="value pageName"/>
 | 
					 | 
				
			||||||
        <input type="hidden" name="phase" tal:attributes="value phase"/>
 | 
					 | 
				
			||||||
        <input type="hidden" name="nav" tal:attributes="value python:request.get('nav', '')"/>
 | 
					        <input type="hidden" name="nav" tal:attributes="value python:request.get('nav', '')"/>
 | 
				
			||||||
        <input type="hidden" name="is_new"
 | 
					        <input type="hidden" name="is_new" tal:attributes="value contextObj/checkCreationFlag"/>
 | 
				
			||||||
               tal:attributes="value python: '/portal_factory/' in contextObj.absolute_url()"/>
 | 
					        <metal:show use-macro="here/skyn/page/macros/show"/>
 | 
				
			||||||
 | 
					 | 
				
			||||||
        <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 > 0">
 | 
					 | 
				
			||||||
            <input class="context" type="submit" name="buttonPrevious"
 | 
					 | 
				
			||||||
                   i18n:attributes="value label_previous;" i18n:domain="plone"
 | 
					 | 
				
			||||||
                   tal:attributes="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 < numberOfPages - 1">
 | 
					 | 
				
			||||||
            <input class="context" type="submit" name="buttonNext" value="Next"
 | 
					 | 
				
			||||||
                   i18n:attributes="value label_next;" i18n:domain="plone"
 | 
					 | 
				
			||||||
                   tal:attributes="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="disabled python:test(isLocked, 'disabled', None);"/>
 | 
					 | 
				
			||||||
          <input class="standalone" type="submit" name="buttonCancel"
 | 
					 | 
				
			||||||
                 i18n:attributes="value label_cancel;" i18n:domain="plone"/>
 | 
					 | 
				
			||||||
        </metal:block>
 | 
					 | 
				
			||||||
      </form>
 | 
					      </form>
 | 
				
			||||||
      <div metal:use-macro="here/skyn/macros/macros/showPageFooter"/>
 | 
					      <metal:footer use-macro="here/skyn/page/macros/footer"/>
 | 
				
			||||||
    </metal:fill>
 | 
					    </metal:fill>
 | 
				
			||||||
  </body>
 | 
					  </body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
</tal:block>
 | 
					</tal:edit>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/editBig.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/help.jpg
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 415 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/help.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 735 B  | 
| 
						 | 
					@ -20,7 +20,7 @@
 | 
				
			||||||
                   importElems python: flavour.getImportElements(contentType);
 | 
					                   importElems python: flavour.getImportElements(contentType);
 | 
				
			||||||
                   global allAreImported python:True">
 | 
					                   global allAreImported python:True">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
 | 
					  <div metal:use-macro="here/skyn/page/macros/prologue"/>
 | 
				
			||||||
  <script language="javascript">
 | 
					  <script language="javascript">
 | 
				
			||||||
  <!--
 | 
					  <!--
 | 
				
			||||||
  var importedElemsShown = false;
 | 
					  var importedElemsShown = false;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,814 +1,3 @@
 | 
				
			||||||
<div metal:define-macro="listPodTemplates" class="appyPod" tal:condition="podTemplates"
 | 
					 | 
				
			||||||
     tal:define="podTemplates python: flavour.getAvailablePodTemplates(contextObj, phase);">
 | 
					 | 
				
			||||||
  <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)<=maxShownTemplates"
 | 
					 | 
				
			||||||
          tal:repeat="podTemplate podTemplates">
 | 
					 | 
				
			||||||
      <a style="cursor: pointer"
 | 
					 | 
				
			||||||
         tal:define="podFormat podTemplate/getPodFormat"
 | 
					 | 
				
			||||||
         tal:attributes="onclick python: 'javascript:generatePodDocument(\'%s\',\'%s\', \'\', \'\')' % (contextObj.UID(), podTemplate.UID())" >
 | 
					 | 
				
			||||||
        <img tal:attributes="src string: $portal_url/skyn/$podFormat.png"/>
 | 
					 | 
				
			||||||
        <span tal:replace="podTemplate/Title"/>
 | 
					 | 
				
			||||||
      </a>
 | 
					 | 
				
			||||||
   </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)>maxShownTemplates">
 | 
					 | 
				
			||||||
    <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\', \'\', \'\')' % (contextObj.UID(), podTemplate.UID())" />
 | 
					 | 
				
			||||||
  </select>
 | 
					 | 
				
			||||||
  </tal:podTemplates>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:editString define-macro="editString" tal:define="vocab python:field.Vocabulary(contextObj)">
 | 
					 | 
				
			||||||
  <label tal:attributes="for fieldName" tal:condition="showLabel" tal:content="label"/> 
 | 
					 | 
				
			||||||
  <span class="fieldRequired" tal:condition="python: appyType['multiplicity'][0] > 0"></span>
 | 
					 | 
				
			||||||
  <div class="discreet" tal:content="structure description"/>
 | 
					 | 
				
			||||||
  <select tal:attributes="name fieldName;
 | 
					 | 
				
			||||||
                          id fieldName;
 | 
					 | 
				
			||||||
                          tabindex tabindex/next;
 | 
					 | 
				
			||||||
                          multiple isMultiple;
 | 
					 | 
				
			||||||
                          onchange python: 'javascript:updateSlaves(getMasterValue(this), \'%s\')' % appyType['id'];
 | 
					 | 
				
			||||||
                          class python: contextObj.getCssClasses(appyType, asSlave=False)">
 | 
					 | 
				
			||||||
      <option tal:repeat="item vocab" i18n:translate=""
 | 
					 | 
				
			||||||
              tal:attributes="value item;
 | 
					 | 
				
			||||||
                              selected python:contextObj.fieldValueSelected(fieldName, value, item)"
 | 
					 | 
				
			||||||
              tal:content="python:here.translate(vocab.getMsgId(item), default=vocab.getValue(item))"/>
 | 
					 | 
				
			||||||
  </select>
 | 
					 | 
				
			||||||
</metal:editString>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:editBoolean define-macro="editBoolean">
 | 
					 | 
				
			||||||
  <input type="checkbox"
 | 
					 | 
				
			||||||
         tal:attributes="tabindex tabindex/next;
 | 
					 | 
				
			||||||
                         name python: fieldName + '_visible';
 | 
					 | 
				
			||||||
                         id fieldName;
 | 
					 | 
				
			||||||
                         checked python:contextObj.checkboxChecked(fieldName, value);
 | 
					 | 
				
			||||||
                         onClick python:'toggleCheckbox(\'%s\', \'%s_hidden\');;updateSlaves(getMasterValue(this), \'%s\')' % (fieldName, fieldName, appyType['id']);
 | 
					 | 
				
			||||||
                         class python: 'noborder ' + contextObj.getCssClasses(appyType, asSlave=False)"/>
 | 
					 | 
				
			||||||
  <input tal:attributes="name fieldName;
 | 
					 | 
				
			||||||
                         id string:${fieldName}_hidden;
 | 
					 | 
				
			||||||
                         value python: test(contextObj.checkboxChecked(fieldName, value), 'True', 'False')"
 | 
					 | 
				
			||||||
         type="hidden" />
 | 
					 | 
				
			||||||
  <span class="fieldRequired" tal:condition="python: appyType['multiplicity'][0] > 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"
 | 
					 | 
				
			||||||
     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)"
 | 
					 | 
				
			||||||
     tal:attributes="class python:'field ' + test(inError, ' error', '')">
 | 
					 | 
				
			||||||
  <div tal:condition="inError" tal:content="python: errors[fieldName]"></div>
 | 
					 | 
				
			||||||
  <tal:stringField condition="python: appyType['type'] == 'String'">
 | 
					 | 
				
			||||||
    <metal:edit use-macro="here/skyn/macros/macros/editString"/>
 | 
					 | 
				
			||||||
  </tal:stringField>
 | 
					 | 
				
			||||||
  <tal:booleanField condition="python: appyType['type'] == 'Boolean'">
 | 
					 | 
				
			||||||
    <metal:edit use-macro="here/skyn/macros/macros/editBoolean"/>
 | 
					 | 
				
			||||||
  </tal:booleanField>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div metal:define-macro="showComputedField">
 | 
					 | 
				
			||||||
  <span class="appyLabel" tal:condition="showLabel" tal:content="label"></span>
 | 
					 | 
				
			||||||
  <span class="formHelp" tal:content="structure description"></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">
 | 
					 | 
				
			||||||
  <span class="appyLabel" tal:content="structure label"></span>
 | 
					 | 
				
			||||||
  <span class="formHelp" tal:content="structure description"></span>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div metal:define-macro="showActionField">
 | 
					 | 
				
			||||||
  <form name="executeAppyAction"
 | 
					 | 
				
			||||||
        tal:define="formId python: '%s_%s' % (contextObj.UID(), field.getName())"
 | 
					 | 
				
			||||||
        tal:attributes="id formId; action python: contextObj.absolute_url()+'/skyn/do'">
 | 
					 | 
				
			||||||
    <input type="hidden" name="action" value="ExecuteAppyAction"/>
 | 
					 | 
				
			||||||
    <input type="hidden" name="objectUid" tal:attributes="value contextObj/UID"/>
 | 
					 | 
				
			||||||
    <input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
 | 
					 | 
				
			||||||
    <input type="button" tal:condition="appyType/confirm"
 | 
					 | 
				
			||||||
           tal:attributes="value label; onClick python: 'javascript:askConfirm(\'%s\')' % formId"/>
 | 
					 | 
				
			||||||
    <input type="submit" name="do" tal:condition="not: appyType/confirm"
 | 
					 | 
				
			||||||
           tal:attributes="value label" onClick="javascript:;"/>
 | 
					 | 
				
			||||||
    <tal:comment replace="nothing">The previous onClick is simply used to prevent Plone
 | 
					 | 
				
			||||||
      from adding a CSS class that displays a popup when the user triggers the form multiple
 | 
					 | 
				
			||||||
      times.</tal:comment>
 | 
					 | 
				
			||||||
  </form>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:showDate define-macro="showDateField"
 | 
					 | 
				
			||||||
                tal:define="v python: contextObj.getAppyValue(field.getName(), appyType)">
 | 
					 | 
				
			||||||
  <span tal:condition="showLabel" tal:content="label" class="appyLabel"></span>
 | 
					 | 
				
			||||||
  <span tal:replace="v"></span>
 | 
					 | 
				
			||||||
</metal:showDate>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:showFloat define-macro="showFloatField"
 | 
					 | 
				
			||||||
                 tal:define="v python: contextObj.getAppyValue(field.getName(), appyType)">
 | 
					 | 
				
			||||||
  <span tal:condition="showLabel" tal:content="label"
 | 
					 | 
				
			||||||
        tal:attributes="class python: 'appyLabel ' + contextObj.getCssClasses(appyType, asSlave=False);
 | 
					 | 
				
			||||||
                        id python: v"></span>
 | 
					 | 
				
			||||||
  <span tal:replace="v"></span>
 | 
					 | 
				
			||||||
</metal:showFloat>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:showString define-macro="showStringField"
 | 
					 | 
				
			||||||
                  tal:define="v python: contextObj.getAppyValue(field.getName(), appyType);
 | 
					 | 
				
			||||||
                              fmt python: appyType['format'];
 | 
					 | 
				
			||||||
                              maxMult python: appyType['multiplicity'][1];
 | 
					 | 
				
			||||||
                              severalValues python: (maxMult == None) or (maxMult > 1)">
 | 
					 | 
				
			||||||
  <tal:simpleString condition="python: fmt in (0, 3)">
 | 
					 | 
				
			||||||
    <span tal:condition="showLabel" tal:content="label" class="appyLabel"
 | 
					 | 
				
			||||||
          tal:attributes="class python: 'appyLabel ' + contextObj.getCssClasses(appyType, asSlave=False);
 | 
					 | 
				
			||||||
                          id python: contextObj.getAppyValue(field.getName(), appyType, forMasterId=True)"></span>
 | 
					 | 
				
			||||||
    <ul class="appyList" tal:condition="python: v and severalValues">
 | 
					 | 
				
			||||||
      <li class="appyBullet" tal:repeat="sv v"><i tal:content="structure sv"></i></li>
 | 
					 | 
				
			||||||
    </ul>
 | 
					 | 
				
			||||||
    <tal:singleValue condition="python: v and not severalValues">
 | 
					 | 
				
			||||||
      <span tal:condition="python: fmt != 3" tal:replace="structure v"/>
 | 
					 | 
				
			||||||
      <span tal:condition="python: fmt == 3">********</span>
 | 
					 | 
				
			||||||
    </tal:singleValue>
 | 
					 | 
				
			||||||
  </tal:simpleString>
 | 
					 | 
				
			||||||
  <tal:formattedString condition="python: fmt not in (0, 3)">
 | 
					 | 
				
			||||||
    <fieldset>
 | 
					 | 
				
			||||||
      <legend tal:condition="showLabel" tal:content="label"></legend>
 | 
					 | 
				
			||||||
      <span tal:condition="python: v and (appyType['format'] == 1)"
 | 
					 | 
				
			||||||
            tal:replace="structure python: v.replace('\n', '<br>')"/>
 | 
					 | 
				
			||||||
      <span tal:condition="python: v and (appyType['format'] == 2)" tal:replace="structure v"/>
 | 
					 | 
				
			||||||
    </fieldset>
 | 
					 | 
				
			||||||
  </tal:formattedString>
 | 
					 | 
				
			||||||
</metal:showString>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:showPod define-macro="showPodField"
 | 
					 | 
				
			||||||
               tal:define="fieldName field/getName">
 | 
					 | 
				
			||||||
  <tal:askAction condition="appyType/askAction"
 | 
					 | 
				
			||||||
                 define="doLabel python:'%s_askaction' % appyType['label'];
 | 
					 | 
				
			||||||
                         chekboxId python: '%s_%s' % (contextObj.UID(), fieldName)">
 | 
					 | 
				
			||||||
    <input type="checkbox" tal:attributes="name doLabel; id chekboxId"/>
 | 
					 | 
				
			||||||
    <label tal:attributes="for chekboxId" class="discreet"
 | 
					 | 
				
			||||||
           tal:content="python: tool.translate(doLabel)"></label>
 | 
					 | 
				
			||||||
  </tal:askAction>
 | 
					 | 
				
			||||||
  <img tal:repeat="podFormat python:flavour.getPodInfo(contextObj, fieldName)['formats']"
 | 
					 | 
				
			||||||
       tal:attributes="src string: $portal_url/skyn/${podFormat}.png;
 | 
					 | 
				
			||||||
                       title label;
 | 
					 | 
				
			||||||
                       onClick python: 'javascript:generatePodDocument(\'%s\',\'\',\'%s\',\'%s\')' % (contextObj.UID(), fieldName, podFormat)"
 | 
					 | 
				
			||||||
       style="cursor:pointer"/>
 | 
					 | 
				
			||||||
</metal:showPod>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div metal:define-macro="showArchetypesField"
 | 
					 | 
				
			||||||
     tal:define="field fieldDescr/atField|widgetDescr/atField;
 | 
					 | 
				
			||||||
                 appyType fieldDescr/appyType|widgetDescr/appyType;
 | 
					 | 
				
			||||||
                 showLabel showLabel|python:True;
 | 
					 | 
				
			||||||
                 labelId field/widget/label_msgid;
 | 
					 | 
				
			||||||
                 label python: tool.translate(labelId);
 | 
					 | 
				
			||||||
                 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
 | 
					 | 
				
			||||||
      macro for showing it. Special Appy field types like Ref and Computed have their
 | 
					 | 
				
			||||||
      corresponding Archetypes fields set as invisible, so they won't be shown by the following
 | 
					 | 
				
			||||||
      tal:showField.</tal:comment>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <tal:showField define="mode python:test(isEdit, 'edit', 'view');"
 | 
					 | 
				
			||||||
                 tal:condition="python: test(isEdit, member.has_permission(field.write_permission, contextObj), member.has_permission(field.read_permission, contextObj))">
 | 
					 | 
				
			||||||
    <tal:editField condition="isEdit">
 | 
					 | 
				
			||||||
      <metal:editMacro use-macro="python:contextObj.widget(field.getName(), mode='edit', use_label=showLabel)" />
 | 
					 | 
				
			||||||
    </tal:editField>
 | 
					 | 
				
			||||||
    <tal:viewField tal:condition="not: isEdit">
 | 
					 | 
				
			||||||
      <tal:fileField condition="python: (appyType['type'] == 'File')">
 | 
					 | 
				
			||||||
        <span tal:condition="showLabel" tal:content="label" class="appyLabel"></span>
 | 
					 | 
				
			||||||
        <metal:viewField use-macro="python: contextObj.widget(field.getName(), 'view', use_label=0)"/>
 | 
					 | 
				
			||||||
      </tal:fileField>
 | 
					 | 
				
			||||||
      <tal:date condition="python: appyType['type'] == 'Date'">
 | 
					 | 
				
			||||||
        <metal:showDate use-macro="here/skyn/macros/macros/showDateField"/>
 | 
					 | 
				
			||||||
      </tal:date>
 | 
					 | 
				
			||||||
      <tal:string condition="python: appyType['type'] == 'String'">
 | 
					 | 
				
			||||||
        <metal:showString use-macro="here/skyn/macros/macros/showStringField"/>
 | 
					 | 
				
			||||||
      </tal:string>
 | 
					 | 
				
			||||||
      <tal:float condition="python: appyType['type'] == 'Float'">
 | 
					 | 
				
			||||||
        <metal:showFloat use-macro="here/skyn/macros/macros/showFloatField"/>
 | 
					 | 
				
			||||||
      </tal:float>
 | 
					 | 
				
			||||||
      <tal:simpleField condition="python: (appyType['type'] in ('Integer', 'Boolean'))">
 | 
					 | 
				
			||||||
        <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:viewField>
 | 
					 | 
				
			||||||
  </tal:showField>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">For other fields like Refs we use specific view/edit macros.</tal:comment>
 | 
					 | 
				
			||||||
  <tal:viewRef condition="python: (not isEdit) and (appyType['type'] == 'Ref')">
 | 
					 | 
				
			||||||
    <tal:ref define="isBack python:False;
 | 
					 | 
				
			||||||
                     fieldName field/getName;
 | 
					 | 
				
			||||||
                     innerRef innerRef|python:False">
 | 
					 | 
				
			||||||
      <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/skyn/ref/macros/editReference" />
 | 
					 | 
				
			||||||
    </tal:ref>
 | 
					 | 
				
			||||||
  </tal:editRef>
 | 
					 | 
				
			||||||
  <tal:computedField condition="python: appyType['type'] == 'Computed'">
 | 
					 | 
				
			||||||
    <metal:cf use-macro="here/skyn/macros/macros/showComputedField" />
 | 
					 | 
				
			||||||
  </tal:computedField>
 | 
					 | 
				
			||||||
  <tal:actionField condition="python: appyType['type'] == 'Action'">
 | 
					 | 
				
			||||||
    <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/skyn/macros/macros/editField" />
 | 
					 | 
				
			||||||
  </tal:masterString>
 | 
					 | 
				
			||||||
  <tal:infoField condition="python: appyType['type'] == 'Info'">
 | 
					 | 
				
			||||||
    <metal:af use-macro="here/skyn/macros/macros/showInfoField" />
 | 
					 | 
				
			||||||
  </tal:infoField>
 | 
					 | 
				
			||||||
  <tal:podField condition="python: (not isEdit) and (appyType['type'] == 'Pod')">
 | 
					 | 
				
			||||||
    <metal:af use-macro="here/skyn/macros/macros/showPodField" />
 | 
					 | 
				
			||||||
  </tal:podField>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div metal:define-macro="showBackwardField"
 | 
					 | 
				
			||||||
     tal:define="isBack python:True;
 | 
					 | 
				
			||||||
                 appyType widgetDescr/appyType;
 | 
					 | 
				
			||||||
                 fieldName widgetDescr/fieldRel;
 | 
					 | 
				
			||||||
                 labelId python: '%s_%s_back' % (contextObj.meta_type, appyType['backd']['attribute']);
 | 
					 | 
				
			||||||
                 descrId python: '';
 | 
					 | 
				
			||||||
                 innerRef innerRef|python:False">
 | 
					 | 
				
			||||||
  <div metal:use-macro="here/skyn/ref/macros/showReference" />
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:group define-macro="showGroup">
 | 
					 | 
				
			||||||
  <fieldset class="appyGroup">
 | 
					 | 
				
			||||||
    <legend><i tal:define="groupDescription python:contextObj.translate('%s_group_%s' % (contextObj.meta_type, widgetDescr['name']))"
 | 
					 | 
				
			||||||
               tal:content="structure 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']) + '%'">
 | 
					 | 
				
			||||||
          <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/skyn/macros/macros/showArchetypesField"/>
 | 
					 | 
				
			||||||
              </tal:archetypesField>
 | 
					 | 
				
			||||||
              <tal:backwardRef tal:condition="python: (not isEdit) and (fieldDescr['widgetType'] == 'backField')">
 | 
					 | 
				
			||||||
                <metal:backRef use-macro="here/skyn/macros/macros/showBackwardField" />
 | 
					 | 
				
			||||||
              </tal:backwardRef>
 | 
					 | 
				
			||||||
            </tal:field>
 | 
					 | 
				
			||||||
          </tal:showField>
 | 
					 | 
				
			||||||
        </td>
 | 
					 | 
				
			||||||
      </tr>
 | 
					 | 
				
			||||||
    </table>
 | 
					 | 
				
			||||||
  </fieldset>
 | 
					 | 
				
			||||||
  <br/>
 | 
					 | 
				
			||||||
</metal:group>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:fields 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/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/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/skyn/macros/macros/showGroup" />
 | 
					 | 
				
			||||||
      </tal:displayG>
 | 
					 | 
				
			||||||
    </tal:displayGroup>
 | 
					 | 
				
			||||||
</metal:fields>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:history define-macro="history"
 | 
					 | 
				
			||||||
      tal:define="startNumber request/startNumber|python:0;
 | 
					 | 
				
			||||||
                  startNumber python: int(startNumber);
 | 
					 | 
				
			||||||
                  historyInfo python: contextObj.getHistory(startNumber);
 | 
					 | 
				
			||||||
                  objs        historyInfo/events;
 | 
					 | 
				
			||||||
                  batchSize   historyInfo/batchSize;
 | 
					 | 
				
			||||||
                  totalNumber historyInfo/totalNumber;
 | 
					 | 
				
			||||||
                  ajaxHookId  python:'appyHistory';
 | 
					 | 
				
			||||||
                  navBaseCall python: 'askObjectHistory(\'%s\',\'%s\',**v**)' % (ajaxHookId, contextObj.absolute_url());
 | 
					 | 
				
			||||||
                  tool        contextObj/getTool">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">Table containing the history</tal:comment>
 | 
					 | 
				
			||||||
  <tal:history condition="objs">
 | 
					 | 
				
			||||||
  <metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
 | 
					 | 
				
			||||||
  <table width="100%" class="listing nosort">
 | 
					 | 
				
			||||||
    <tr i18n:domain="plone">
 | 
					 | 
				
			||||||
      <th i18n:translate="listingheader_action"/>
 | 
					 | 
				
			||||||
      <th i18n:translate="listingheader_performed_by"/>
 | 
					 | 
				
			||||||
      <th i18n:translate="listingheader_date_and_time"/>
 | 
					 | 
				
			||||||
      <th i18n:translate="listingheader_comment"/>
 | 
					 | 
				
			||||||
    </tr>
 | 
					 | 
				
			||||||
    <tal:event repeat="event objs">
 | 
					 | 
				
			||||||
    <tr tal:define="odd repeat/event/odd;
 | 
					 | 
				
			||||||
                    rhComments event/comments|nothing;
 | 
					 | 
				
			||||||
                    state event/review_state|nothing;
 | 
					 | 
				
			||||||
                    isDataChange python: event['action'] == '_datachange_'"
 | 
					 | 
				
			||||||
        tal:attributes="class python:test(odd, 'even', 'odd')" valign="top">
 | 
					 | 
				
			||||||
      <td tal:condition="isDataChange" tal:content="python: tool.translate('data_change')"></td>
 | 
					 | 
				
			||||||
      <td tal:condition="not: isDataChange"
 | 
					 | 
				
			||||||
          tal:content="python: tool.translate(contextObj.getWorkflowLabel(event['action']))"
 | 
					 | 
				
			||||||
          tal:attributes="class string:state-${state}"/>
 | 
					 | 
				
			||||||
      <td tal:define="actorid python:event.get('actor');
 | 
					 | 
				
			||||||
                      actor python:contextObj.portal_membership.getMemberInfo(actorid);
 | 
					 | 
				
			||||||
                      fullname actor/fullname|nothing;
 | 
					 | 
				
			||||||
                      username actor/username|nothing"
 | 
					 | 
				
			||||||
          tal:content="python:fullname or username or actorid"/>
 | 
					 | 
				
			||||||
      <td tal:content="python:contextObj.restrictedTraverse('@@plone').toLocalizedTime(event['time'],long_format=True)"/>
 | 
					 | 
				
			||||||
      <td tal:condition="not: isDataChange"><tal:comment condition="rhComments" tal:content="structure rhComments"/>
 | 
					 | 
				
			||||||
        <tal:noComment condition="not: rhComments" i18n:translate="no_comments" i18n:domain="plone"/></td>
 | 
					 | 
				
			||||||
      <td tal:condition="isDataChange">
 | 
					 | 
				
			||||||
        <tal:comment replace="nothing">
 | 
					 | 
				
			||||||
          Display the previous values of the fields whose value were modified in this change.</tal:comment>
 | 
					 | 
				
			||||||
        <table class="appyChanges" width="100%">
 | 
					 | 
				
			||||||
          <tr>
 | 
					 | 
				
			||||||
            <th align="left" width="30%" tal:content="python: tool.translate('modified_field')"></th>
 | 
					 | 
				
			||||||
            <th align="left" width="70%" tal:content="python: tool.translate('previous_value')"></th>
 | 
					 | 
				
			||||||
          </tr>
 | 
					 | 
				
			||||||
          <tr tal:repeat="change event/changes/items" valign="top">
 | 
					 | 
				
			||||||
            <td tal:content="python: tool.translate(change[1][1])"></td>
 | 
					 | 
				
			||||||
            <td tal:define="appyType python:contextObj.getAppyType(change[0]);
 | 
					 | 
				
			||||||
                            appyValue python: contextObj.getAppyValue(change[0], appyType, True, change[1][0]);
 | 
					 | 
				
			||||||
                            severalValues python: (appyType['multiplicity'][1] > 1) or (appyType['multiplicity'][1] == None)">
 | 
					 | 
				
			||||||
              <span tal:condition="not: severalValues" tal:replace="appyValue"></span>
 | 
					 | 
				
			||||||
              <ul tal:condition="python: severalValues">
 | 
					 | 
				
			||||||
                <li tal:repeat="av appyValue" tal:content="av"></li>
 | 
					 | 
				
			||||||
              </ul>
 | 
					 | 
				
			||||||
            </td>
 | 
					 | 
				
			||||||
          </tr>
 | 
					 | 
				
			||||||
        </table>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
    </tr>
 | 
					 | 
				
			||||||
    </tal:event>
 | 
					 | 
				
			||||||
  </table>
 | 
					 | 
				
			||||||
  </tal:history>
 | 
					 | 
				
			||||||
</metal:history>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div metal:define-macro="pagePrologue">
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">Global elements used in every page.</tal:comment>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">Javascript messages</tal:comment>
 | 
					 | 
				
			||||||
  <script language="javascript" tal:content="tool/getJavascriptMessages"></script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">"Static" javascripts</tal:comment>
 | 
					 | 
				
			||||||
  <script language="javascript">
 | 
					 | 
				
			||||||
  <!--
 | 
					 | 
				
			||||||
  var isIe = (navigator.appName == "Microsoft Internet Explorer");
 | 
					 | 
				
			||||||
  // AJAX machinery
 | 
					 | 
				
			||||||
  var xhrObjects = new Array(); // An array of XMLHttpRequest objects
 | 
					 | 
				
			||||||
  function XhrObject() { // Wraps a XmlHttpRequest object
 | 
					 | 
				
			||||||
    this.freed = 1; // Is this xhr object already dealing with a request or not?
 | 
					 | 
				
			||||||
    this.xhr = false;
 | 
					 | 
				
			||||||
    if (window.XMLHttpRequest) this.xhr = new XMLHttpRequest();
 | 
					 | 
				
			||||||
    else this.xhr = new ActiveXObject("Microsoft.XMLHTTP");
 | 
					 | 
				
			||||||
    this.hook = '';  /* The ID of the HTML element in the page that will be
 | 
					 | 
				
			||||||
                        replaced by result of executing the Ajax request. */
 | 
					 | 
				
			||||||
    this.onGet = ''; /* The name of a Javascript function to call once we
 | 
					 | 
				
			||||||
                        receive the result. */
 | 
					 | 
				
			||||||
    this.info = {};  /* An associative array for putting anything else. */
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function getAjaxChunk(pos) {
 | 
					 | 
				
			||||||
    // This function is the callback called by the AJAX machinery (see function
 | 
					 | 
				
			||||||
    // askAjaxChunk below) when an Ajax response is available.
 | 
					 | 
				
			||||||
    // First, find back the correct XMLHttpRequest object
 | 
					 | 
				
			||||||
    if ( (typeof(xhrObjects[pos]) != 'undefined') &&
 | 
					 | 
				
			||||||
         (xhrObjects[pos].freed == 0)) {
 | 
					 | 
				
			||||||
      var hook = xhrObjects[pos].hook;
 | 
					 | 
				
			||||||
      if (xhrObjects[pos].xhr.readyState == 1) {
 | 
					 | 
				
			||||||
        // The request has been initialized: display the waiting radar
 | 
					 | 
				
			||||||
        var hookElem = document.getElementById(hook);
 | 
					 | 
				
			||||||
        if (hookElem) hookElem.innerHTML = "<div align=\"center\"><img src=\"skyn/waiting.gif\"/><\/div>";
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (xhrObjects[pos].xhr.readyState == 4) {
 | 
					 | 
				
			||||||
        // We have received the HTML chunk
 | 
					 | 
				
			||||||
        var hookElem = document.getElementById(hook);
 | 
					 | 
				
			||||||
        if (hookElem && (xhrObjects[pos].xhr.status == 200)) {
 | 
					 | 
				
			||||||
          hookElem.innerHTML = xhrObjects[pos].xhr.responseText;
 | 
					 | 
				
			||||||
          // Call a custom Javascript function if required
 | 
					 | 
				
			||||||
          if (xhrObjects[pos].onGet) {
 | 
					 | 
				
			||||||
            xhrObjects[pos].onGet(xhrObjects[pos], hookElem);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        xhrObjects[pos].freed = 1;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function askAjaxChunk(hook,mode,url,page,macro,params,beforeSend,onGet) {
 | 
					 | 
				
			||||||
    /* This function will ask to get a chunk of HTML on the server through a
 | 
					 | 
				
			||||||
       XMLHttpRequest. p_mode can be 'GET' or 'POST'. p_url is the URL of a
 | 
					 | 
				
			||||||
       given server object. On this URL we will call the page "ajax.pt" that
 | 
					 | 
				
			||||||
       will call a specific p_macro in a given p_page with some additional
 | 
					 | 
				
			||||||
       p_params (must be an associative array) if required.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
       p_hook is the ID of the HTML element that will be filled with the HTML
 | 
					 | 
				
			||||||
       result from the server.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
       p_beforeSend is a Javascript function to call before sending the request.
 | 
					 | 
				
			||||||
       This function will get 2 args: the XMLHttpRequest object and the
 | 
					 | 
				
			||||||
       p_params. This method can return, in a string, additional parameters to
 | 
					 | 
				
			||||||
       send, ie: "¶m1=blabla¶m2=blabla".
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
       p_onGet is a Javascript function to call when we will receive the answer.
 | 
					 | 
				
			||||||
       This function will get 2 args, too: the XMLHttpRequest object and the
 | 
					 | 
				
			||||||
       HTML node element into which the result has been inserted.
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    // First, get a non-busy XMLHttpRequest object.
 | 
					 | 
				
			||||||
    var pos = -1;
 | 
					 | 
				
			||||||
    for (var i=0; i < xhrObjects.length; i++) {
 | 
					 | 
				
			||||||
      if (xhrObjects[i].freed == 1) { pos = i; break; }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (pos == -1) {
 | 
					 | 
				
			||||||
      pos = xhrObjects.length;
 | 
					 | 
				
			||||||
      xhrObjects[pos] = new XhrObject();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    xhrObjects[pos].hook = hook;
 | 
					 | 
				
			||||||
    xhrObjects[pos].onGet = onGet;
 | 
					 | 
				
			||||||
    if (xhrObjects[pos].xhr) {
 | 
					 | 
				
			||||||
      var rq = xhrObjects[pos];
 | 
					 | 
				
			||||||
      rq.freed = 0;
 | 
					 | 
				
			||||||
      // Construct parameters
 | 
					 | 
				
			||||||
      var paramsFull = 'page=' + page + '¯o=' + macro;
 | 
					 | 
				
			||||||
      if (params) {
 | 
					 | 
				
			||||||
        for (var paramName in params)
 | 
					 | 
				
			||||||
          paramsFull = paramsFull + '&' + paramName + '=' + params[paramName];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      // Call beforeSend if required
 | 
					 | 
				
			||||||
      if (beforeSend) {
 | 
					 | 
				
			||||||
         var res = beforeSend(rq, params);
 | 
					 | 
				
			||||||
         if (res) paramsFull = paramsFull + res;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      // Construct the URL to call
 | 
					 | 
				
			||||||
      var urlFull = url + '/skyn/ajax';
 | 
					 | 
				
			||||||
      if (mode == 'GET') {
 | 
					 | 
				
			||||||
        urlFull = urlFull + '?' + paramsFull;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      // Perform the asynchronous HTTP GET or POST
 | 
					 | 
				
			||||||
      rq.xhr.open(mode, urlFull, true);
 | 
					 | 
				
			||||||
      if (mode == 'POST') {
 | 
					 | 
				
			||||||
        // Set the correct HTTP headers
 | 
					 | 
				
			||||||
        rq.xhr.setRequestHeader(
 | 
					 | 
				
			||||||
          "Content-Type", "application/x-www-form-urlencoded");
 | 
					 | 
				
			||||||
        rq.xhr.setRequestHeader("Content-length", paramsFull.length);
 | 
					 | 
				
			||||||
        rq.xhr.setRequestHeader("Connection", "close");
 | 
					 | 
				
			||||||
        rq.xhr.onreadystatechange = function(){ getAjaxChunk(pos); }
 | 
					 | 
				
			||||||
        rq.xhr.send(paramsFull);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      else if (mode == 'GET') {
 | 
					 | 
				
			||||||
        rq.xhr.onreadystatechange = function() { getAjaxChunk(pos); }
 | 
					 | 
				
			||||||
        if (window.XMLHttpRequest) { rq.xhr.send(null); }
 | 
					 | 
				
			||||||
        else if (window.ActiveXObject) { rq.xhr.send(); }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* The functions below wrap askAjaxChunk for getting specific content through
 | 
					 | 
				
			||||||
     an Ajax request. */
 | 
					 | 
				
			||||||
  function askQueryResult(hookId, objectUrl, contentType, flavourNumber,
 | 
					 | 
				
			||||||
              searchName, startNumber, sortKey, sortOrder, filterKey) {
 | 
					 | 
				
			||||||
    // Sends an Ajax request for getting the result of a query.
 | 
					 | 
				
			||||||
    var params = {'type_name': contentType, 'flavourNumber': flavourNumber,
 | 
					 | 
				
			||||||
                  'search': searchName, 'startNumber': startNumber};
 | 
					 | 
				
			||||||
    if (sortKey) params['sortKey'] = sortKey;
 | 
					 | 
				
			||||||
    if (sortOrder) params['sortOrder'] = sortOrder;
 | 
					 | 
				
			||||||
    if (filterKey) {
 | 
					 | 
				
			||||||
      var filterWidget = document.getElementById(hookId + '_' + filterKey);
 | 
					 | 
				
			||||||
      if (filterWidget && filterWidget.value) {
 | 
					 | 
				
			||||||
        params['filterKey'] = filterKey;
 | 
					 | 
				
			||||||
        params['filterValue'] = filterWidget.value;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    askAjaxChunk(hookId,'GET',objectUrl,'macros','queryResult',params);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function askObjectHistory(hookId, objectUrl, startNumber) {
 | 
					 | 
				
			||||||
    // Sends an Ajax request for getting the history of an object
 | 
					 | 
				
			||||||
    var params = {'startNumber': startNumber};
 | 
					 | 
				
			||||||
    askAjaxChunk(hookId, 'GET', objectUrl, 'macros', 'history', params);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function askRefField(hookId, objectUrl, fieldName, isBack, innerRef, labelId,
 | 
					 | 
				
			||||||
                       descrId, startNumber, action, actionParams){
 | 
					 | 
				
			||||||
    // Sends an Ajax request for getting the content of a reference field.
 | 
					 | 
				
			||||||
    var startKey = hookId + '_startNumber';
 | 
					 | 
				
			||||||
    var params = {'fieldName': fieldName, 'isBack': isBack,
 | 
					 | 
				
			||||||
                  'innerRef': innerRef, 'labelId': labelId,
 | 
					 | 
				
			||||||
                  'descrId': descrId };
 | 
					 | 
				
			||||||
    params[startKey] =  startNumber;
 | 
					 | 
				
			||||||
    if (action) params['action'] = action;
 | 
					 | 
				
			||||||
    if (actionParams) {
 | 
					 | 
				
			||||||
        for (key in actionParams) { params[key] = actionParams[key]; };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    askAjaxChunk(hookId, 'GET', objectUrl, 'ref', 'showReferenceContent',
 | 
					 | 
				
			||||||
                 params);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Function used by checkbox widgets for having radio-button-like behaviour
 | 
					 | 
				
			||||||
  function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
 | 
					 | 
				
			||||||
    vis = document.getElementById(visibleCheckbox);
 | 
					 | 
				
			||||||
    hidden = document.getElementById(hiddenBoolean);
 | 
					 | 
				
			||||||
    if (vis.checked) hidden.value = 'True';
 | 
					 | 
				
			||||||
    else hidden.value = 'False';
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Functions used for master/slave relationships between widgets
 | 
					 | 
				
			||||||
  function getMasterValue(widget) {
 | 
					 | 
				
			||||||
    // Returns an array of selected options in a select widget
 | 
					 | 
				
			||||||
    res = new Array();
 | 
					 | 
				
			||||||
    if (widget.type == 'checkbox') {
 | 
					 | 
				
			||||||
      var mv = widget.checked + '';
 | 
					 | 
				
			||||||
      mv = mv.charAt(0).toUpperCase() + mv.substr(1);
 | 
					 | 
				
			||||||
      res.push(mv);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else { // SELECT widget
 | 
					 | 
				
			||||||
      for (var i=0; i < widget.options.length; i++) {
 | 
					 | 
				
			||||||
        if (widget.options[i].selected) res.push(widget.options[i].value);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return res;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  function updateSlaves(masterValues, appyTypeId) {
 | 
					 | 
				
			||||||
    // Given the value(s) selected in a master field, this function updates the
 | 
					 | 
				
			||||||
    // state of all corresponding slaves.
 | 
					 | 
				
			||||||
    var slaves = cssQuery('div.slave_' + appyTypeId);
 | 
					 | 
				
			||||||
    for (var i=0; i< slaves.length; i++){
 | 
					 | 
				
			||||||
      slaves[i].style.display = "none";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (var i=0; i < masterValues.length; i++) {
 | 
					 | 
				
			||||||
      var activeSlaves = cssQuery('div.slaveValue_' + appyTypeId + '_' + masterValues[i]);
 | 
					 | 
				
			||||||
      for (var j=0; j < activeSlaves.length; j++){
 | 
					 | 
				
			||||||
        activeSlaves[j].style.display = "";
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Function used for triggering a workflow transition
 | 
					 | 
				
			||||||
  function triggerTransition(transitionId) {
 | 
					 | 
				
			||||||
    var theForm = document.getElementById('triggerTransitionForm');
 | 
					 | 
				
			||||||
    theForm.workflow_action.value = transitionId;
 | 
					 | 
				
			||||||
    theForm.submit();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  function onDeleteObject(objectUid) {
 | 
					 | 
				
			||||||
    if (confirm(delete_confirm)) {
 | 
					 | 
				
			||||||
       f = document.getElementById('deleteForm');
 | 
					 | 
				
			||||||
       f.objectUid.value = objectUid;
 | 
					 | 
				
			||||||
       f.submit();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  function toggleCookie(cookieId) {
 | 
					 | 
				
			||||||
    // What is the state of this boolean (expanded/collapsed) cookie?
 | 
					 | 
				
			||||||
    var state = readCookie(cookieId);
 | 
					 | 
				
			||||||
    if ((state != 'collapsed') && (state != 'expanded')) {
 | 
					 | 
				
			||||||
      // No cookie yet, create it.
 | 
					 | 
				
			||||||
      createCookie(cookieId, 'collapsed');
 | 
					 | 
				
			||||||
      state = 'collapsed';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    var hook = document.getElementById(cookieId); // The hook is the part of
 | 
					 | 
				
			||||||
    // the HTML document that needs to be shown or hidden.
 | 
					 | 
				
			||||||
    var displayValue = 'none';
 | 
					 | 
				
			||||||
    var newState = 'collapsed';
 | 
					 | 
				
			||||||
    var imgSrc = 'skyn/expand.gif';
 | 
					 | 
				
			||||||
    if (state == 'collapsed') {
 | 
					 | 
				
			||||||
      // Show the HTML zone
 | 
					 | 
				
			||||||
      displayValue = 'block';
 | 
					 | 
				
			||||||
      imgSrc = 'skyn/collapse.gif';
 | 
					 | 
				
			||||||
      newState = 'expanded';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // Update the corresponding HTML element
 | 
					 | 
				
			||||||
    hook.style.display = displayValue;
 | 
					 | 
				
			||||||
    var img = document.getElementById(cookieId + '_img');
 | 
					 | 
				
			||||||
    img.src = imgSrc;
 | 
					 | 
				
			||||||
    // Inverse the cookie value
 | 
					 | 
				
			||||||
    createCookie(cookieId, newState);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Function that allows to generate a document from a pod template.
 | 
					 | 
				
			||||||
  function generatePodDocument(contextUid, templateUid, fieldName, podFormat) {
 | 
					 | 
				
			||||||
    var theForm = document.forms["podTemplateForm"];
 | 
					 | 
				
			||||||
    theForm.objectUid.value = contextUid;
 | 
					 | 
				
			||||||
    theForm.templateUid.value = templateUid;
 | 
					 | 
				
			||||||
    theForm.fieldName.value = fieldName;
 | 
					 | 
				
			||||||
    theForm.podFormat.value = podFormat;
 | 
					 | 
				
			||||||
    theForm.askAction.value = "False";
 | 
					 | 
				
			||||||
    var askActionWidget = document.getElementById(contextUid + '_' + fieldName);
 | 
					 | 
				
			||||||
    if (askActionWidget && askActionWidget.checked) {
 | 
					 | 
				
			||||||
        theForm.askAction.value = "True";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    theForm.submit();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Functions for opening and closing a popup
 | 
					 | 
				
			||||||
  function openPopup(popupId) {
 | 
					 | 
				
			||||||
    // Open the popup
 | 
					 | 
				
			||||||
    var popup = document.getElementById(popupId);
 | 
					 | 
				
			||||||
    // Put it at the right place on the screen
 | 
					 | 
				
			||||||
    var scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0;
 | 
					 | 
				
			||||||
    popup.style.top = (scrollTop + 150) + 'px';
 | 
					 | 
				
			||||||
    popup.style.display = "block";
 | 
					 | 
				
			||||||
    // Show the greyed zone
 | 
					 | 
				
			||||||
    var greyed = document.getElementById('appyGrey');
 | 
					 | 
				
			||||||
    greyed.style.top = scrollTop + 'px';
 | 
					 | 
				
			||||||
    greyed.style.display = "block";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  function closePopup(popupId) {
 | 
					 | 
				
			||||||
    // Close the popup
 | 
					 | 
				
			||||||
    var popup = document.getElementById(popupId);
 | 
					 | 
				
			||||||
    popup.style.display = "none";
 | 
					 | 
				
			||||||
    // Hide the greyed zone
 | 
					 | 
				
			||||||
    var greyed = document.getElementById('appyGrey');
 | 
					 | 
				
			||||||
    greyed.style.display = "none";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Function triggered when an action needs to be confirmed by the user
 | 
					 | 
				
			||||||
  function askConfirm(formId) {
 | 
					 | 
				
			||||||
    // Store the ID of the form to send if the users confirms.
 | 
					 | 
				
			||||||
    var confirmForm = document.getElementById('confirmActionForm');
 | 
					 | 
				
			||||||
    confirmForm.actionFormId.value = formId;
 | 
					 | 
				
			||||||
    openPopup("confirmActionPopup");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // Function triggered when an action confirmed by the user must be performed
 | 
					 | 
				
			||||||
  function doConfirm() {
 | 
					 | 
				
			||||||
    // The user confirmed: retrieve the form to send and send it.
 | 
					 | 
				
			||||||
    var confirmForm = document.getElementById('confirmActionForm');
 | 
					 | 
				
			||||||
    var actionFormId = confirmForm.actionFormId.value;
 | 
					 | 
				
			||||||
    var actionForm = document.getElementById(actionFormId);
 | 
					 | 
				
			||||||
    actionForm.submit();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
-->
 | 
					 | 
				
			||||||
  </script>
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">Global form for deleting an object</tal:comment>
 | 
					 | 
				
			||||||
  <form id="deleteForm" method="post" action="skyn/do">
 | 
					 | 
				
			||||||
    <input type="hidden" name="action" value="Delete"/>
 | 
					 | 
				
			||||||
    <input type="hidden" name="objectUid"/>
 | 
					 | 
				
			||||||
  </form>
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">Global form for generating a document from a pod template.</tal:comment>
 | 
					 | 
				
			||||||
  <form name="podTemplateForm" method="post"
 | 
					 | 
				
			||||||
        tal:attributes="action python: flavour.absolute_url() + '/generateDocument'">
 | 
					 | 
				
			||||||
    <input type="hidden" name="objectUid"/>
 | 
					 | 
				
			||||||
    <tal:comment replace="nothing">templateUid is given if class-wide pod, fieldName and podFormat are given if podField.</tal:comment>
 | 
					 | 
				
			||||||
    <input type="hidden" name="templateUid"/>
 | 
					 | 
				
			||||||
    <input type="hidden" name="fieldName"/>
 | 
					 | 
				
			||||||
    <input type="hidden" name="podFormat"/>
 | 
					 | 
				
			||||||
    <input type="hidden" name="askAction"/>
 | 
					 | 
				
			||||||
  </form>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div metal:define-macro="showPageHeader"
 | 
					 | 
				
			||||||
     tal:define="showCommonInfo python: not isEdit;
 | 
					 | 
				
			||||||
                 hasHistory contextObj/hasHistory;
 | 
					 | 
				
			||||||
                 historyExpanded python: tool.getCookieValue('appyHistory', default='collapsed') == 'expanded';
 | 
					 | 
				
			||||||
                 creator contextObj/Creator"
 | 
					 | 
				
			||||||
     tal:condition="not: contextObj/isTemporary">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <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="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']>1">−
 | 
					 | 
				
			||||||
            <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);
 | 
					 | 
				
			||||||
                           nav request/nav|nothing;
 | 
					 | 
				
			||||||
                           nav python: test(nav, '&nav=%s' % nav, '')"
 | 
					 | 
				
			||||||
               title="Edit" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
 | 
					 | 
				
			||||||
               tal:attributes="onClick python: 'href: window.location=\'%s/skyn/edit?fieldset=%s&phase=%s%s\'' % (contextObj.absolute_url(), editPageName, phase, nav);
 | 
					 | 
				
			||||||
                               src string: $portal_url/skyn/edit.gif"
 | 
					 | 
				
			||||||
               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: contextObj.translate('%s_edit_descr' % contextObj.portal_type)"
 | 
					 | 
				
			||||||
          tal:condition="descrLabel/strip" >
 | 
					 | 
				
			||||||
        <tal:comment replace="nothing">Content type description</tal:comment>
 | 
					 | 
				
			||||||
        <td colspan="2" class="discreet" tal:content="descrLabel"/>
 | 
					 | 
				
			||||||
      </tr>
 | 
					 | 
				
			||||||
      <tr>
 | 
					 | 
				
			||||||
        <td class="documentByLine">
 | 
					 | 
				
			||||||
          <tal:comment replace="nothing">Creator and last modification date</tal:comment>
 | 
					 | 
				
			||||||
            <tal:comment replace="nothing">Plus/minus icon for accessing history</tal:comment>
 | 
					 | 
				
			||||||
            <tal:accessHistory condition="hasHistory">
 | 
					 | 
				
			||||||
            <img align="left" style="cursor:pointer" onClick="javascript:toggleCookie('appyHistory')"
 | 
					 | 
				
			||||||
                 tal:attributes="src python:test(historyExpanded, 'skyn/collapse.gif', 'skyn/expand.gif');"
 | 
					 | 
				
			||||||
                 id="appyHistory_img"/> 
 | 
					 | 
				
			||||||
            <span i18n:translate="label_history" i18n:domain="plone" class="appyHistory"></span> 
 | 
					 | 
				
			||||||
            </tal:accessHistory>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <tal:comment replace="nothing">Show document creator</tal:comment>
 | 
					 | 
				
			||||||
            <tal:creator condition="creator"
 | 
					 | 
				
			||||||
                 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"
 | 
					 | 
				
			||||||
                  tal:omit-tag="not:author" i18n:name="author"/>
 | 
					 | 
				
			||||||
            —
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
            </tal:creator>
 | 
					 | 
				
			||||||
            <tal:comment replace="nothing">Show last modification date</tal:comment>
 | 
					 | 
				
			||||||
            <span i18n:translate="box_last_modified" i18n:domain="plone"></span>
 | 
					 | 
				
			||||||
            <span tal:replace="python:contextObj.restrictedTraverse('@@plone').toLocalizedTime(contextObj.ModificationDate(),long_format=1)"></span>
 | 
					 | 
				
			||||||
        </td>
 | 
					 | 
				
			||||||
        <td valign="top"><metal:pod use-macro="here/skyn/macros/macros/listPodTemplates"/>
 | 
					 | 
				
			||||||
        </td>
 | 
					 | 
				
			||||||
      </tr>
 | 
					 | 
				
			||||||
      <tal:comment replace="nothing">Object history</tal:comment>
 | 
					 | 
				
			||||||
      <tr tal:condition="hasHistory">
 | 
					 | 
				
			||||||
        <td colspan="2">
 | 
					 | 
				
			||||||
          <span id="appyHistory"
 | 
					 | 
				
			||||||
                tal:attributes="style python:test(historyExpanded, 'display:block', 'display:none')">
 | 
					 | 
				
			||||||
          <div tal:define="ajaxHookId python: contextObj.UID() + '_history';"
 | 
					 | 
				
			||||||
               tal:attributes="id ajaxHookId">
 | 
					 | 
				
			||||||
             <script language="javascript" tal:content="python: 'askObjectHistory(\'%s\',\'%s\',0)' % (ajaxHookId, contextObj.absolute_url())">
 | 
					 | 
				
			||||||
             </script>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
        </td>
 | 
					 | 
				
			||||||
      </tr>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <tal:comment replace="nothing">Workflow-related information and actions</tal:comment>
 | 
					 | 
				
			||||||
      <tr tal:condition="python: showWorkflow and contextObj.getWorkflowLabel()">
 | 
					 | 
				
			||||||
        <td colspan="2" class="appyWorkflow">
 | 
					 | 
				
			||||||
          <table width="100%">
 | 
					 | 
				
			||||||
            <tr>
 | 
					 | 
				
			||||||
              <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>
 | 
					 | 
				
			||||||
      </tr>
 | 
					 | 
				
			||||||
    </table>
 | 
					 | 
				
			||||||
    <metal:nav use-macro="here/skyn/navigate/macros/objectNavigate"/>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <tal:comment replace="nothing">Tabs</tal:comment>
 | 
					 | 
				
			||||||
    <ul class="contentViews appyTabs" tal:condition="python: len(appyPages)>1">
 | 
					 | 
				
			||||||
      <li tal:repeat="thePage appyPages"
 | 
					 | 
				
			||||||
          tal:attributes="class python:test(thePage == pageName, 'selected', 'plain')">
 | 
					 | 
				
			||||||
        <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);
 | 
					 | 
				
			||||||
                           nav request/nav|nothing;
 | 
					 | 
				
			||||||
                           nav python: test(nav, '&nav=%s' % nav, '')"
 | 
					 | 
				
			||||||
               title="Edit" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer" class="appyPlusImg"
 | 
					 | 
				
			||||||
               tal:attributes="onClick python: 'href: window.location=\'%s/skyn/edit?fieldset=%s&phase=%s%s\'' % (contextObj.absolute_url(), editPageName, phase, nav);
 | 
					 | 
				
			||||||
                               src string: $portal_url/skyn/edit.gif"
 | 
					 | 
				
			||||||
               tal:condition="python: member.has_permission('Modify portal content', contextObj)"/>
 | 
					 | 
				
			||||||
        </tal:tab>
 | 
					 | 
				
			||||||
      </li>
 | 
					 | 
				
			||||||
    </ul>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div metal:define-macro="showPageFooter">
 | 
					 | 
				
			||||||
  <script language="javascript">
 | 
					 | 
				
			||||||
  <!--
 | 
					 | 
				
			||||||
    // When the current page is loaded, we must set the correct state for all slave fields.
 | 
					 | 
				
			||||||
    var masters = cssQuery('.appyMaster');
 | 
					 | 
				
			||||||
    for (var i=0; i < masters.length; i++) {
 | 
					 | 
				
			||||||
      var cssClasses = masters[i].className.split(' ');
 | 
					 | 
				
			||||||
      for (var j=0; j < cssClasses.length; j++) {
 | 
					 | 
				
			||||||
        if (cssClasses[j].indexOf('master_') == 0) {
 | 
					 | 
				
			||||||
          var appyId = cssClasses[j].split('_')[1];
 | 
					 | 
				
			||||||
          var masterValue = [];
 | 
					 | 
				
			||||||
          if (masters[i].nodeName == 'SPAN'){
 | 
					 | 
				
			||||||
            var idField = masters[i].id;
 | 
					 | 
				
			||||||
            if (idField == '') {
 | 
					 | 
				
			||||||
              masterValue.push(idField);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else {
 | 
					 | 
				
			||||||
              if (idField[0] == '(') {
 | 
					 | 
				
			||||||
                // There are multiple values, split it
 | 
					 | 
				
			||||||
                var subValues = idField.substring(1, idField.length-1).split(',');
 | 
					 | 
				
			||||||
                for (var k=0; k < subValues.length; k++){
 | 
					 | 
				
			||||||
                  var subValue = subValues[k].strip();
 | 
					 | 
				
			||||||
                  masterValue.push(subValue.substring(1, subValue.length-1));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
              else { masterValue.push(masters[i].id);
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          else { masterValue = getMasterValue(masters[i]);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          updateSlaves(masterValue, appyId);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  -->
 | 
					 | 
				
			||||||
  </script>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:queryResults define-macro="queryResult"
 | 
					<metal:queryResults define-macro="queryResult"
 | 
				
			||||||
   tal:define="tool          python: contextObj;
 | 
					   tal:define="tool          python: contextObj;
 | 
				
			||||||
               contentType   request/type_name;
 | 
					               contentType   request/type_name;
 | 
				
			||||||
| 
						 | 
					@ -856,7 +45,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <table tal:define="fieldDescrs python: tool.getResultColumns(objs[0], contentType)"
 | 
					    <table tal:define="fieldDescrs python: tool.getResultColumns(objs[0], contentType)"
 | 
				
			||||||
         class="listing nosort" width="100%" cellpadding="0" cellspacing="0">
 | 
					         class="listing nosort" width="100%" cellpadding="0" cellspacing="0">
 | 
				
			||||||
    <tal:comment replace="nothing">Every item in fieldDescr is a FieldDescr instance,
 | 
					    <tal:comment replace="nothing">Every item in fieldDescrs is an Appy type (dict version),
 | 
				
			||||||
      excepted for workflow state (which is not a field): in this case it is simply the
 | 
					      excepted for workflow state (which is not a field): in this case it is simply the
 | 
				
			||||||
      string "workflow_state".</tal:comment>
 | 
					      string "workflow_state".</tal:comment>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -871,12 +60,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
 | 
					      <tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
 | 
				
			||||||
      <tal:columnHeader repeat="fieldDescr fieldDescrs">
 | 
					      <tal:columnHeader repeat="fieldDescr fieldDescrs">
 | 
				
			||||||
       <th tal:define="fieldName  fieldDescr/atField/getName|string:workflow_state;
 | 
					       <th tal:define="fieldName  fieldDescr/name|string:workflow_state;
 | 
				
			||||||
                       sortable   fieldDescr/sortable|nothing;
 | 
					                       sortable   fieldDescr/indexed|nothing;
 | 
				
			||||||
                       filterable fieldDescr/filterable|nothing;">
 | 
					                       filterable fieldDescr/filterable|nothing;">
 | 
				
			||||||
        <tal:comment replace="nothing">Display header for a "standard" field</tal:comment>
 | 
					        <tal:comment replace="nothing">Display header for a "standard" field</tal:comment>
 | 
				
			||||||
        <tal:standardField condition="python: fieldName != 'workflow_state'">
 | 
					        <tal:standardField condition="python: fieldName != 'workflow_state'">
 | 
				
			||||||
          <span tal:replace="python: tool.translate(fieldDescr['atField'].widget.label_msgid)"/>
 | 
					          <span tal:replace="python: tool.translate(fieldDescr['labelId'])"/>
 | 
				
			||||||
        </tal:standardField>
 | 
					        </tal:standardField>
 | 
				
			||||||
        <tal:comment replace="nothing">Display header for the workflow state</tal:comment>
 | 
					        <tal:comment replace="nothing">Display header for the workflow state</tal:comment>
 | 
				
			||||||
        <tal:workflowState condition="python: fieldName == 'workflow_state'">
 | 
					        <tal:workflowState condition="python: fieldName == 'workflow_state'">
 | 
				
			||||||
| 
						 | 
					@ -906,23 +95,22 @@
 | 
				
			||||||
        tal:content="obj/Title" tal:attributes="href python: obj.getUrl() + '/?' + navInfo"></a></td>
 | 
					        tal:content="obj/Title" tal:attributes="href python: obj.getUrl() + '/?' + navInfo"></a></td>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
 | 
					      <tal:comment replace="nothing">Columns corresponding to other fields</tal:comment>
 | 
				
			||||||
      <tal:otherFields repeat="fieldDescr fieldDescrs">
 | 
					      <tal:otherFields repeat="widget fieldDescrs">
 | 
				
			||||||
        <tal:standardField condition="python: fieldDescr != 'workflowState'">
 | 
					        <tal:standardField condition="python: widget != 'workflowState'">
 | 
				
			||||||
          <td tal:condition="fieldDescr/atField"
 | 
					          <td tal:condition="python: '_wrong' not in widget"
 | 
				
			||||||
              tal:attributes="id python:'field_%s' % fieldDescr['atField'].getName()">
 | 
					              tal:attributes="id python:'field_%s' % widget['name']">
 | 
				
			||||||
            <tal:field define="contextObj python:obj;
 | 
					            <tal:field define="contextObj python:obj;
 | 
				
			||||||
                               isEdit python:False;
 | 
					                               layoutType  python:'cell';
 | 
				
			||||||
                               showLabel python:False;
 | 
					 | 
				
			||||||
                               innerRef python:True"
 | 
					                               innerRef python:True"
 | 
				
			||||||
                       condition="python: contextObj.showField(fieldDescr)">
 | 
					                       condition="python: contextObj.showField(widget['name'], 'view')">
 | 
				
			||||||
              <metal:field use-macro="here/skyn/macros/macros/showArchetypesField"/>
 | 
					              <metal:field use-macro="here/skyn/widgets/show/macros/field"/>
 | 
				
			||||||
            </tal:field>
 | 
					            </tal:field>
 | 
				
			||||||
          </td>
 | 
					          </td>
 | 
				
			||||||
          <td tal:condition="not: fieldDescr/atField" style="color:red">Field
 | 
					          <td tal:condition="python: '_wrong' in widget" style="color:red">Field
 | 
				
			||||||
            <span tal:replace="fieldDescr/name"/> not found.
 | 
					            <span tal:replace="widget/name"/> not found.
 | 
				
			||||||
          </td>
 | 
					          </td>
 | 
				
			||||||
        </tal:standardField>
 | 
					        </tal:standardField>
 | 
				
			||||||
        <tal:workflowState condition="python: fieldDescr == 'workflowState'">
 | 
					        <tal:workflowState condition="python: widget == 'workflowState'">
 | 
				
			||||||
          <td id="field_workflow_state" tal:content="python: tool.translate(obj.getWorkflowLabel())"></td>
 | 
					          <td id="field_workflow_state" tal:content="python: tool.translate(obj.getWorkflowLabel())"></td>
 | 
				
			||||||
        </tal:workflowState>
 | 
					        </tal:workflowState>
 | 
				
			||||||
      </tal:otherFields>
 | 
					      </tal:otherFields>
 | 
				
			||||||
| 
						 | 
					@ -969,70 +157,3 @@
 | 
				
			||||||
  </tal:noResult>
 | 
					  </tal:noResult>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</metal:queryResults>
 | 
					</metal:queryResults>
 | 
				
			||||||
 | 
					 | 
				
			||||||
<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 contextObj/getAppyPhases|nothing"
 | 
					 | 
				
			||||||
           tal:condition="python: phases and (len(phases)>1)" cellspacing="1" cellpadding="0">
 | 
					 | 
				
			||||||
      <tal:phase repeat="phase phases">
 | 
					 | 
				
			||||||
        <tr>
 | 
					 | 
				
			||||||
          <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' % (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/skyn/nextPhase.png"/></td>
 | 
					 | 
				
			||||||
        </tr>
 | 
					 | 
				
			||||||
      </tal:phase>
 | 
					 | 
				
			||||||
    </table>
 | 
					 | 
				
			||||||
</metal:phases>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:states define-macro="states"
 | 
					 | 
				
			||||||
              tal:define="showAllStatesInPhase python: flavour.getAttr('showAllStatesInPhaseFor' + contextObj.meta_type);
 | 
					 | 
				
			||||||
                          states python: contextObj.getAppyStates(phase, currentOnly=not showAllStatesInPhase)"
 | 
					 | 
				
			||||||
              tal:condition="python: test(showAllStatesInPhase, len(states)>1, True)">
 | 
					 | 
				
			||||||
  <table>
 | 
					 | 
				
			||||||
    <tr>
 | 
					 | 
				
			||||||
      <tal:state repeat="stateInfo states">
 | 
					 | 
				
			||||||
        <td tal:attributes="class python: 'appyState step' + stateInfo['stateStatus']"
 | 
					 | 
				
			||||||
            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/skyn/nextState.png"/>
 | 
					 | 
				
			||||||
        </td>
 | 
					 | 
				
			||||||
      </tal:state>
 | 
					 | 
				
			||||||
    </tr>
 | 
					 | 
				
			||||||
  </table>
 | 
					 | 
				
			||||||
</metal:states>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:transitions define-macro="transitions"
 | 
					 | 
				
			||||||
                   tal:define="transitions contextObj/getAppyTransitions"
 | 
					 | 
				
			||||||
                   tal:condition="transitions">
 | 
					 | 
				
			||||||
  <form id="triggerTransitionForm" method="post"
 | 
					 | 
				
			||||||
        tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'">
 | 
					 | 
				
			||||||
    <input type="hidden" name="action" 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'+contextObj.meta_type)"
 | 
					 | 
				
			||||||
            align="right" tal:condition="showCommentsField">
 | 
					 | 
				
			||||||
          <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" class="context"
 | 
					 | 
				
			||||||
                 tal:attributes="value python: tool.translate(transition['name']);
 | 
					 | 
				
			||||||
                                 onClick python: 'javascript: triggerTransition(\'%s\')' % transition['id'];"/>
 | 
					 | 
				
			||||||
        </td>
 | 
					 | 
				
			||||||
    </tr>
 | 
					 | 
				
			||||||
    </table>
 | 
					 | 
				
			||||||
  </form>
 | 
					 | 
				
			||||||
</metal:transitions>
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/next.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 951 B  | 
							
								
								
									
										728
									
								
								gen/plone25/skin/page.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,728 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro contains global page-related Javascripts.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<div metal:define-macro="prologue">
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Global elements used in every page.</tal:comment>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Javascript messages</tal:comment>
 | 
				
			||||||
 | 
					  <script language="javascript" tal:content="tool/getJavascriptMessages"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">"Static" javascripts</tal:comment>
 | 
				
			||||||
 | 
					  <script language="javascript">
 | 
				
			||||||
 | 
					  <!--
 | 
				
			||||||
 | 
					  var isIe = (navigator.appName == "Microsoft Internet Explorer");
 | 
				
			||||||
 | 
					  // AJAX machinery
 | 
				
			||||||
 | 
					  var xhrObjects = new Array(); // An array of XMLHttpRequest objects
 | 
				
			||||||
 | 
					  function XhrObject() { // Wraps a XmlHttpRequest object
 | 
				
			||||||
 | 
					    this.freed = 1; // Is this xhr object already dealing with a request or not?
 | 
				
			||||||
 | 
					    this.xhr = false;
 | 
				
			||||||
 | 
					    if (window.XMLHttpRequest) this.xhr = new XMLHttpRequest();
 | 
				
			||||||
 | 
					    else this.xhr = new ActiveXObject("Microsoft.XMLHTTP");
 | 
				
			||||||
 | 
					    this.hook = '';  /* The ID of the HTML element in the page that will be
 | 
				
			||||||
 | 
					                        replaced by result of executing the Ajax request. */
 | 
				
			||||||
 | 
					    this.onGet = ''; /* The name of a Javascript function to call once we
 | 
				
			||||||
 | 
					                        receive the result. */
 | 
				
			||||||
 | 
					    this.info = {};  /* An associative array for putting anything else. */
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function getAjaxChunk(pos) {
 | 
				
			||||||
 | 
					    // This function is the callback called by the AJAX machinery (see function
 | 
				
			||||||
 | 
					    // askAjaxChunk below) when an Ajax response is available.
 | 
				
			||||||
 | 
					    // First, find back the correct XMLHttpRequest object
 | 
				
			||||||
 | 
					    if ( (typeof(xhrObjects[pos]) != 'undefined') &&
 | 
				
			||||||
 | 
					         (xhrObjects[pos].freed == 0)) {
 | 
				
			||||||
 | 
					      var hook = xhrObjects[pos].hook;
 | 
				
			||||||
 | 
					      if (xhrObjects[pos].xhr.readyState == 1) {
 | 
				
			||||||
 | 
					        // The request has been initialized: display the waiting radar
 | 
				
			||||||
 | 
					        var hookElem = document.getElementById(hook);
 | 
				
			||||||
 | 
					        if (hookElem) hookElem.innerHTML = "<div align=\"center\"><img src=\"skyn/waiting.gif\"/><\/div>";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (xhrObjects[pos].xhr.readyState == 4) {
 | 
				
			||||||
 | 
					        // We have received the HTML chunk
 | 
				
			||||||
 | 
					        var hookElem = document.getElementById(hook);
 | 
				
			||||||
 | 
					        if (hookElem && (xhrObjects[pos].xhr.status == 200)) {
 | 
				
			||||||
 | 
					          hookElem.innerHTML = xhrObjects[pos].xhr.responseText;
 | 
				
			||||||
 | 
					          // Call a custom Javascript function if required
 | 
				
			||||||
 | 
					          if (xhrObjects[pos].onGet) {
 | 
				
			||||||
 | 
					            xhrObjects[pos].onGet(xhrObjects[pos], hookElem);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        xhrObjects[pos].freed = 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function askAjaxChunk(hook,mode,url,page,macro,params,beforeSend,onGet) {
 | 
				
			||||||
 | 
					    /* This function will ask to get a chunk of HTML on the server through a
 | 
				
			||||||
 | 
					       XMLHttpRequest. p_mode can be 'GET' or 'POST'. p_url is the URL of a
 | 
				
			||||||
 | 
					       given server object. On this URL we will call the page "ajax.pt" that
 | 
				
			||||||
 | 
					       will call a specific p_macro in a given p_page with some additional
 | 
				
			||||||
 | 
					       p_params (must be an associative array) if required.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       p_hook is the ID of the HTML element that will be filled with the HTML
 | 
				
			||||||
 | 
					       result from the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       p_beforeSend is a Javascript function to call before sending the request.
 | 
				
			||||||
 | 
					       This function will get 2 args: the XMLHttpRequest object and the
 | 
				
			||||||
 | 
					       p_params. This method can return, in a string, additional parameters to
 | 
				
			||||||
 | 
					       send, ie: "¶m1=blabla¶m2=blabla".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       p_onGet is a Javascript function to call when we will receive the answer.
 | 
				
			||||||
 | 
					       This function will get 2 args, too: the XMLHttpRequest object and the
 | 
				
			||||||
 | 
					       HTML node element into which the result has been inserted.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    // First, get a non-busy XMLHttpRequest object.
 | 
				
			||||||
 | 
					    var pos = -1;
 | 
				
			||||||
 | 
					    for (var i=0; i < xhrObjects.length; i++) {
 | 
				
			||||||
 | 
					      if (xhrObjects[i].freed == 1) { pos = i; break; }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (pos == -1) {
 | 
				
			||||||
 | 
					      pos = xhrObjects.length;
 | 
				
			||||||
 | 
					      xhrObjects[pos] = new XhrObject();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    xhrObjects[pos].hook = hook;
 | 
				
			||||||
 | 
					    xhrObjects[pos].onGet = onGet;
 | 
				
			||||||
 | 
					    if (xhrObjects[pos].xhr) {
 | 
				
			||||||
 | 
					      var rq = xhrObjects[pos];
 | 
				
			||||||
 | 
					      rq.freed = 0;
 | 
				
			||||||
 | 
					      // Construct parameters
 | 
				
			||||||
 | 
					      var paramsFull = 'page=' + page + '¯o=' + macro;
 | 
				
			||||||
 | 
					      if (params) {
 | 
				
			||||||
 | 
					        for (var paramName in params)
 | 
				
			||||||
 | 
					          paramsFull = paramsFull + '&' + paramName + '=' + params[paramName];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Call beforeSend if required
 | 
				
			||||||
 | 
					      if (beforeSend) {
 | 
				
			||||||
 | 
					         var res = beforeSend(rq, params);
 | 
				
			||||||
 | 
					         if (res) paramsFull = paramsFull + res;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Construct the URL to call
 | 
				
			||||||
 | 
					      var urlFull = url + '/skyn/ajax';
 | 
				
			||||||
 | 
					      if (mode == 'GET') {
 | 
				
			||||||
 | 
					        urlFull = urlFull + '?' + paramsFull;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Perform the asynchronous HTTP GET or POST
 | 
				
			||||||
 | 
					      rq.xhr.open(mode, urlFull, true);
 | 
				
			||||||
 | 
					      if (mode == 'POST') {
 | 
				
			||||||
 | 
					        // Set the correct HTTP headers
 | 
				
			||||||
 | 
					        rq.xhr.setRequestHeader(
 | 
				
			||||||
 | 
					          "Content-Type", "application/x-www-form-urlencoded");
 | 
				
			||||||
 | 
					        rq.xhr.setRequestHeader("Content-length", paramsFull.length);
 | 
				
			||||||
 | 
					        rq.xhr.setRequestHeader("Connection", "close");
 | 
				
			||||||
 | 
					        rq.xhr.onreadystatechange = function(){ getAjaxChunk(pos); }
 | 
				
			||||||
 | 
					        rq.xhr.send(paramsFull);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else if (mode == 'GET') {
 | 
				
			||||||
 | 
					        rq.xhr.onreadystatechange = function() { getAjaxChunk(pos); }
 | 
				
			||||||
 | 
					        if (window.XMLHttpRequest) { rq.xhr.send(null); }
 | 
				
			||||||
 | 
					        else if (window.ActiveXObject) { rq.xhr.send(); }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* The functions below wrap askAjaxChunk for getting specific content through
 | 
				
			||||||
 | 
					     an Ajax request. */
 | 
				
			||||||
 | 
					  function askQueryResult(hookId, objectUrl, contentType, flavourNumber,
 | 
				
			||||||
 | 
					              searchName, startNumber, sortKey, sortOrder, filterKey) {
 | 
				
			||||||
 | 
					    // Sends an Ajax request for getting the result of a query.
 | 
				
			||||||
 | 
					    var params = {'type_name': contentType, 'flavourNumber': flavourNumber,
 | 
				
			||||||
 | 
					                  'search': searchName, 'startNumber': startNumber};
 | 
				
			||||||
 | 
					    if (sortKey) params['sortKey'] = sortKey;
 | 
				
			||||||
 | 
					    if (sortOrder) params['sortOrder'] = sortOrder;
 | 
				
			||||||
 | 
					    if (filterKey) {
 | 
				
			||||||
 | 
					      var filterWidget = document.getElementById(hookId + '_' + filterKey);
 | 
				
			||||||
 | 
					      if (filterWidget && filterWidget.value) {
 | 
				
			||||||
 | 
					        params['filterKey'] = filterKey;
 | 
				
			||||||
 | 
					        params['filterValue'] = filterWidget.value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    askAjaxChunk(hookId,'GET',objectUrl,'macros','queryResult',params);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function askObjectHistory(hookId, objectUrl, startNumber) {
 | 
				
			||||||
 | 
					    // Sends an Ajax request for getting the history of an object
 | 
				
			||||||
 | 
					    var params = {'startNumber': startNumber};
 | 
				
			||||||
 | 
					    askAjaxChunk(hookId, 'GET', objectUrl, 'page', 'objectHistory', params);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function askRefField(hookId, objectUrl, fieldName, innerRef, startNumber,
 | 
				
			||||||
 | 
					                       action, actionParams){
 | 
				
			||||||
 | 
					    // Sends an Ajax request for getting the content of a reference field.
 | 
				
			||||||
 | 
					    var startKey = hookId + '_startNumber';
 | 
				
			||||||
 | 
					    var params = {'fieldName': fieldName, 'innerRef': innerRef, };
 | 
				
			||||||
 | 
					    params[startKey] =  startNumber;
 | 
				
			||||||
 | 
					    if (action) params['action'] = action;
 | 
				
			||||||
 | 
					    if (actionParams) {
 | 
				
			||||||
 | 
					        for (key in actionParams) { params[key] = actionParams[key]; };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/ref', 'viewContent',params);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Function used by checkbox widgets for having radio-button-like behaviour
 | 
				
			||||||
 | 
					  function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
 | 
				
			||||||
 | 
					    vis = document.getElementById(visibleCheckbox);
 | 
				
			||||||
 | 
					    hidden = document.getElementById(hiddenBoolean);
 | 
				
			||||||
 | 
					    if (vis.checked) hidden.value = 'True';
 | 
				
			||||||
 | 
					    else hidden.value = 'False';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Functions used for master/slave relationships between widgets
 | 
				
			||||||
 | 
					  function getMasterValue(widget) {
 | 
				
			||||||
 | 
					    // Returns an array of selected options in a select widget
 | 
				
			||||||
 | 
					    res = new Array();
 | 
				
			||||||
 | 
					    if (widget.type == 'checkbox') {
 | 
				
			||||||
 | 
					      var mv = widget.checked + '';
 | 
				
			||||||
 | 
					      mv = mv.charAt(0).toUpperCase() + mv.substr(1);
 | 
				
			||||||
 | 
					      res.push(mv);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else { // SELECT widget
 | 
				
			||||||
 | 
					      for (var i=0; i < widget.options.length; i++) {
 | 
				
			||||||
 | 
					        if (widget.options[i].selected) res.push(widget.options[i].value);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  function updateSlaves(masterValues, appyTypeId) {
 | 
				
			||||||
 | 
					    // Given the value(s) selected in a master field, this function updates the
 | 
				
			||||||
 | 
					    // state of all corresponding slaves.
 | 
				
			||||||
 | 
					    var slaves = cssQuery('table.slave_' + appyTypeId);
 | 
				
			||||||
 | 
					    for (var i=0; i< slaves.length; i++){
 | 
				
			||||||
 | 
					      slaves[i].style.display = "none";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (var i=0; i < masterValues.length; i++) {
 | 
				
			||||||
 | 
					      var activeSlaves = cssQuery('table.slaveValue_' + appyTypeId + '_' + masterValues[i]);
 | 
				
			||||||
 | 
					      for (var j=0; j < activeSlaves.length; j++){
 | 
				
			||||||
 | 
					        activeSlaves[j].style.display = "";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Function used for triggering a workflow transition
 | 
				
			||||||
 | 
					  function triggerTransition(transitionId) {
 | 
				
			||||||
 | 
					    var theForm = document.getElementById('triggerTransitionForm');
 | 
				
			||||||
 | 
					    theForm.workflow_action.value = transitionId;
 | 
				
			||||||
 | 
					    theForm.submit();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  function onDeleteObject(objectUid) {
 | 
				
			||||||
 | 
					    if (confirm(delete_confirm)) {
 | 
				
			||||||
 | 
					       f = document.getElementById('deleteForm');
 | 
				
			||||||
 | 
					       f.objectUid.value = objectUid;
 | 
				
			||||||
 | 
					       f.submit();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  function toggleCookie(cookieId) {
 | 
				
			||||||
 | 
					    // What is the state of this boolean (expanded/collapsed) cookie?
 | 
				
			||||||
 | 
					    var state = readCookie(cookieId);
 | 
				
			||||||
 | 
					    if ((state != 'collapsed') && (state != 'expanded')) {
 | 
				
			||||||
 | 
					      // No cookie yet, create it.
 | 
				
			||||||
 | 
					      createCookie(cookieId, 'collapsed');
 | 
				
			||||||
 | 
					      state = 'collapsed';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var hook = document.getElementById(cookieId); // The hook is the part of
 | 
				
			||||||
 | 
					    // the HTML document that needs to be shown or hidden.
 | 
				
			||||||
 | 
					    var displayValue = 'none';
 | 
				
			||||||
 | 
					    var newState = 'collapsed';
 | 
				
			||||||
 | 
					    var imgSrc = 'skyn/expand.gif';
 | 
				
			||||||
 | 
					    if (state == 'collapsed') {
 | 
				
			||||||
 | 
					      // Show the HTML zone
 | 
				
			||||||
 | 
					      displayValue = 'block';
 | 
				
			||||||
 | 
					      imgSrc = 'skyn/collapse.gif';
 | 
				
			||||||
 | 
					      newState = 'expanded';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Update the corresponding HTML element
 | 
				
			||||||
 | 
					    hook.style.display = displayValue;
 | 
				
			||||||
 | 
					    var img = document.getElementById(cookieId + '_img');
 | 
				
			||||||
 | 
					    img.src = imgSrc;
 | 
				
			||||||
 | 
					    // Inverse the cookie value
 | 
				
			||||||
 | 
					    createCookie(cookieId, newState);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Function that allows to generate a document from a pod template.
 | 
				
			||||||
 | 
					  function generatePodDocument(contextUid, templateUid, fieldName, podFormat) {
 | 
				
			||||||
 | 
					    var theForm = document.forms["podTemplateForm"];
 | 
				
			||||||
 | 
					    theForm.objectUid.value = contextUid;
 | 
				
			||||||
 | 
					    theForm.templateUid.value = templateUid;
 | 
				
			||||||
 | 
					    theForm.fieldName.value = fieldName;
 | 
				
			||||||
 | 
					    theForm.podFormat.value = podFormat;
 | 
				
			||||||
 | 
					    theForm.askAction.value = "False";
 | 
				
			||||||
 | 
					    var askActionWidget = document.getElementById(contextUid + '_' + fieldName);
 | 
				
			||||||
 | 
					    if (askActionWidget && askActionWidget.checked) {
 | 
				
			||||||
 | 
					        theForm.askAction.value = "True";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    theForm.submit();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Functions for opening and closing a popup
 | 
				
			||||||
 | 
					  function openPopup(popupId) {
 | 
				
			||||||
 | 
					    // Open the popup
 | 
				
			||||||
 | 
					    var popup = document.getElementById(popupId);
 | 
				
			||||||
 | 
					    // Put it at the right place on the screen
 | 
				
			||||||
 | 
					    var scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0;
 | 
				
			||||||
 | 
					    popup.style.top = (scrollTop + 150) + 'px';
 | 
				
			||||||
 | 
					    popup.style.display = "block";
 | 
				
			||||||
 | 
					    // Show the greyed zone
 | 
				
			||||||
 | 
					    var greyed = document.getElementById('appyGrey');
 | 
				
			||||||
 | 
					    greyed.style.top = scrollTop + 'px';
 | 
				
			||||||
 | 
					    greyed.style.display = "block";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  function closePopup(popupId) {
 | 
				
			||||||
 | 
					    // Close the popup
 | 
				
			||||||
 | 
					    var popup = document.getElementById(popupId);
 | 
				
			||||||
 | 
					    popup.style.display = "none";
 | 
				
			||||||
 | 
					    // Hide the greyed zone
 | 
				
			||||||
 | 
					    var greyed = document.getElementById('appyGrey');
 | 
				
			||||||
 | 
					    greyed.style.display = "none";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Function triggered when an action needs to be confirmed by the user
 | 
				
			||||||
 | 
					  function askConfirm(formId) {
 | 
				
			||||||
 | 
					    // Store the ID of the form to send if the users confirms.
 | 
				
			||||||
 | 
					    var confirmForm = document.getElementById('confirmActionForm');
 | 
				
			||||||
 | 
					    confirmForm.actionFormId.value = formId;
 | 
				
			||||||
 | 
					    openPopup("confirmActionPopup");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Function triggered when an action confirmed by the user must be performed
 | 
				
			||||||
 | 
					  function doConfirm() {
 | 
				
			||||||
 | 
					    // The user confirmed: retrieve the form to send and send it.
 | 
				
			||||||
 | 
					    var confirmForm = document.getElementById('confirmActionForm');
 | 
				
			||||||
 | 
					    var actionFormId = confirmForm.actionFormId.value;
 | 
				
			||||||
 | 
					    var actionForm = document.getElementById(actionFormId);
 | 
				
			||||||
 | 
					    actionForm.submit();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Function that shows or hides a tab. p_action is 'show' or 'hide'.
 | 
				
			||||||
 | 
					  function manageTab(tabId, action) {
 | 
				
			||||||
 | 
					    // Manage the tab content (show it or hide it)
 | 
				
			||||||
 | 
					    var content = document.getElementById('tabcontent_' + tabId);
 | 
				
			||||||
 | 
					    if (action == 'show')   { content.style.display = 'table-row'; }
 | 
				
			||||||
 | 
					    else                    { content.style.display = 'none'; }
 | 
				
			||||||
 | 
					    // Manage the tab itself (show as selected or unselected)
 | 
				
			||||||
 | 
					    var left = document.getElementById('tab_' + tabId + '_left');
 | 
				
			||||||
 | 
					    var tab = document.getElementById('tab_' + tabId);
 | 
				
			||||||
 | 
					    var right = document.getElementById('tab_' + tabId + '_right');
 | 
				
			||||||
 | 
					    if (action == 'show') {
 | 
				
			||||||
 | 
					        left.src  = "skyn/tabLeft.png";
 | 
				
			||||||
 | 
					        tab.style.backgroundImage = "url(skyn/tabBg.png)";
 | 
				
			||||||
 | 
					        right.src = "skyn/tabRight.png";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (action == 'hide') {
 | 
				
			||||||
 | 
					        left.src  = "skyn/tabLeftu.png";
 | 
				
			||||||
 | 
					        tab.style.backgroundImage = "url(skyn/tabBgu.png)";
 | 
				
			||||||
 | 
					        right.src = "skyn/tabRightu.png";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Function used for displaying/hiding content of a tab
 | 
				
			||||||
 | 
					  function showTab(tabId) {
 | 
				
			||||||
 | 
					    // 1st, show the tab to show
 | 
				
			||||||
 | 
					    manageTab(tabId, 'show');
 | 
				
			||||||
 | 
					    // Compute the number of tabs.
 | 
				
			||||||
 | 
					    var idParts = tabId.split('_');
 | 
				
			||||||
 | 
					    var prefix = idParts[0] + '_';
 | 
				
			||||||
 | 
					    // Store the currently selected tab in a cookie.
 | 
				
			||||||
 | 
					    createCookie('tab_' + idParts[0], tabId);
 | 
				
			||||||
 | 
					    var nbOfTabs = idParts[2]*1;
 | 
				
			||||||
 | 
					    // Then, hide the other tabs.
 | 
				
			||||||
 | 
					    for (var i=0; i<nbOfTabs; i++) {
 | 
				
			||||||
 | 
					       var idTab = prefix + (i+1) + '_' + nbOfTabs;
 | 
				
			||||||
 | 
					       if (idTab != tabId) {
 | 
				
			||||||
 | 
					         manageTab(idTab, 'hide');
 | 
				
			||||||
 | 
					       }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Function that initializes the state of a tab
 | 
				
			||||||
 | 
					  function initTab(cookieId, defaultValue) {
 | 
				
			||||||
 | 
					    var toSelect = readCookie(cookieId);
 | 
				
			||||||
 | 
					    if (!toSelect) { showTab(defaultValue) }
 | 
				
			||||||
 | 
					    else { showTab(toSelect); }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					  </script>
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Global form for deleting an object</tal:comment>
 | 
				
			||||||
 | 
					  <form id="deleteForm" method="post" action="skyn/do">
 | 
				
			||||||
 | 
					    <input type="hidden" name="action" value="Delete"/>
 | 
				
			||||||
 | 
					    <input type="hidden" name="objectUid"/>
 | 
				
			||||||
 | 
					  </form>
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Global form for generating a document from a pod template.</tal:comment>
 | 
				
			||||||
 | 
					  <form name="podTemplateForm" method="post"
 | 
				
			||||||
 | 
					        tal:attributes="action python: flavour.absolute_url() + '/generateDocument'">
 | 
				
			||||||
 | 
					    <input type="hidden" name="objectUid"/>
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">templateUid is given if class-wide pod, fieldName and podFormat are given if podField.</tal:comment>
 | 
				
			||||||
 | 
					    <input type="hidden" name="templateUid"/>
 | 
				
			||||||
 | 
					    <input type="hidden" name="fieldName"/>
 | 
				
			||||||
 | 
					    <input type="hidden" name="podFormat"/>
 | 
				
			||||||
 | 
					    <input type="hidden" name="askAction"/>
 | 
				
			||||||
 | 
					  </form>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro shows the content of page. Because a page is a layouted object,
 | 
				
			||||||
 | 
					  we simply call the macro that displays a layouted object.
 | 
				
			||||||
 | 
					    contextObj         The Zope object for which this page must be shown
 | 
				
			||||||
 | 
					    layoutType         The kind of layout: "view"? "edit"? "cell"?
 | 
				
			||||||
 | 
					    layout             The layout object that will dictate how object content
 | 
				
			||||||
 | 
					                       will be rendered.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:show define-macro="show">
 | 
				
			||||||
 | 
					  <metal:layout use-macro="here/skyn/widgets/show/macros/layout"/>
 | 
				
			||||||
 | 
					</metal:show>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro displays all widgets of a given page. It requires:
 | 
				
			||||||
 | 
					    contextObj         The Zope object for which widgets must be shown
 | 
				
			||||||
 | 
					    page               We show widgets of a given page
 | 
				
			||||||
 | 
					    layoutType         We must know if we must render the widgets in a "view",
 | 
				
			||||||
 | 
					                       "edit" or "cell" layout
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<table metal:define-macro="widgets" cellpadding="0" cellspacing="0">
 | 
				
			||||||
 | 
					  <tr tal:repeat="widget python: contextObj.getGroupedAppyTypes(layoutType, page)">
 | 
				
			||||||
 | 
					    <td tal:condition="python: widget['type'] == 'group'">
 | 
				
			||||||
 | 
					      <metal:call use-macro="portal/skyn/widgets/show/macros/group"/>
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					    <td tal:condition="python: widget['type'] != 'group'">
 | 
				
			||||||
 | 
					      <metal:call use-macro="portal/skyn/widgets/show/macros/field"/>
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro lists the POD templates that are available. It is used by macro "header" below.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<div metal:define-macro="listPodTemplates" class="appyPod" tal:condition="podTemplates"
 | 
				
			||||||
 | 
					     tal:define="podTemplates python: flavour.getAvailablePodTemplates(contextObj, phase);">
 | 
				
			||||||
 | 
					  <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)<=maxShownTemplates"
 | 
				
			||||||
 | 
					          tal:repeat="podTemplate podTemplates">
 | 
				
			||||||
 | 
					      <a style="cursor: pointer"
 | 
				
			||||||
 | 
					         tal:define="podFormat podTemplate/getPodFormat"
 | 
				
			||||||
 | 
					         tal:attributes="onclick python: 'javascript:generatePodDocument(\'%s\',\'%s\', \'\', \'\')' % (contextObj.UID(), podTemplate.UID())" >
 | 
				
			||||||
 | 
					        <img tal:attributes="src string: $portal_url/skyn/$podFormat.png"/>
 | 
				
			||||||
 | 
					        <span tal:replace="podTemplate/Title"/>
 | 
				
			||||||
 | 
					      </a>
 | 
				
			||||||
 | 
					   </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)>maxShownTemplates">
 | 
				
			||||||
 | 
					    <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\', \'\', \'\')' % (contextObj.UID(), podTemplate.UID())" />
 | 
				
			||||||
 | 
					  </select>
 | 
				
			||||||
 | 
					  </tal:podTemplates>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro displays an object's history. It is used by macro "header" below.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:history define-macro="objectHistory"
 | 
				
			||||||
 | 
					      tal:define="startNumber request/startNumber|python:0;
 | 
				
			||||||
 | 
					                  startNumber python: int(startNumber);
 | 
				
			||||||
 | 
					                  historyInfo python: contextObj.getHistory(startNumber);
 | 
				
			||||||
 | 
					                  objs        historyInfo/events;
 | 
				
			||||||
 | 
					                  batchSize   historyInfo/batchSize;
 | 
				
			||||||
 | 
					                  totalNumber historyInfo/totalNumber;
 | 
				
			||||||
 | 
					                  ajaxHookId  python:'appyHistory';
 | 
				
			||||||
 | 
					                  navBaseCall python: 'askObjectHistory(\'%s\',\'%s\',**v**)' % (ajaxHookId, contextObj.absolute_url());
 | 
				
			||||||
 | 
					                  tool        contextObj/getTool">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Table containing the history</tal:comment>
 | 
				
			||||||
 | 
					  <tal:history condition="objs">
 | 
				
			||||||
 | 
					  <metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
 | 
				
			||||||
 | 
					  <table width="100%" class="listing nosort">
 | 
				
			||||||
 | 
					    <tr i18n:domain="plone">
 | 
				
			||||||
 | 
					      <th i18n:translate="listingheader_action"/>
 | 
				
			||||||
 | 
					      <th i18n:translate="listingheader_performed_by"/>
 | 
				
			||||||
 | 
					      <th i18n:translate="listingheader_date_and_time"/>
 | 
				
			||||||
 | 
					      <th i18n:translate="listingheader_comment"/>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    <tal:event repeat="event objs">
 | 
				
			||||||
 | 
					    <tr tal:define="odd repeat/event/odd;
 | 
				
			||||||
 | 
					                    rhComments event/comments|nothing;
 | 
				
			||||||
 | 
					                    state event/review_state|nothing;
 | 
				
			||||||
 | 
					                    isDataChange python: event['action'] == '_datachange_'"
 | 
				
			||||||
 | 
					        tal:attributes="class python:test(odd, 'even', 'odd')" valign="top">
 | 
				
			||||||
 | 
					      <td tal:condition="isDataChange" tal:content="python: tool.translate('data_change')"></td>
 | 
				
			||||||
 | 
					      <td tal:condition="not: isDataChange"
 | 
				
			||||||
 | 
					          tal:content="python: tool.translate(contextObj.getWorkflowLabel(event['action']))"
 | 
				
			||||||
 | 
					          tal:attributes="class string:state-${state}"/>
 | 
				
			||||||
 | 
					      <td tal:define="actorid python:event.get('actor');
 | 
				
			||||||
 | 
					                      actor python:contextObj.portal_membership.getMemberInfo(actorid);
 | 
				
			||||||
 | 
					                      fullname actor/fullname|nothing;
 | 
				
			||||||
 | 
					                      username actor/username|nothing"
 | 
				
			||||||
 | 
					          tal:content="python:fullname or username or actorid"/>
 | 
				
			||||||
 | 
					      <td tal:content="python:contextObj.restrictedTraverse('@@plone').toLocalizedTime(event['time'],long_format=True)"/>
 | 
				
			||||||
 | 
					      <td tal:condition="not: isDataChange"><tal:comment condition="rhComments" tal:content="structure rhComments"/>
 | 
				
			||||||
 | 
					        <tal:noComment condition="not: rhComments" i18n:translate="no_comments" i18n:domain="plone"/></td>
 | 
				
			||||||
 | 
					      <td tal:condition="isDataChange">
 | 
				
			||||||
 | 
					        <tal:comment replace="nothing">
 | 
				
			||||||
 | 
					          Display the previous values of the fields whose value were modified in this change.</tal:comment>
 | 
				
			||||||
 | 
					        <table class="appyChanges" width="100%">
 | 
				
			||||||
 | 
					          <tr>
 | 
				
			||||||
 | 
					            <th align="left" width="30%" tal:content="python: tool.translate('modified_field')"></th>
 | 
				
			||||||
 | 
					            <th align="left" width="70%" tal:content="python: tool.translate('previous_value')"></th>
 | 
				
			||||||
 | 
					          </tr>
 | 
				
			||||||
 | 
					          <tr tal:repeat="change event/changes/items" valign="top">
 | 
				
			||||||
 | 
					            <td tal:content="python: tool.translate(change[1][1])"></td>
 | 
				
			||||||
 | 
					            <td tal:define="appyValue python: contextObj.getFormattedValue(change[0], useParamValue=True, value=change[1][0]);
 | 
				
			||||||
 | 
					                            appyType python:contextObj.getAppyType(change[0], asDict=True);
 | 
				
			||||||
 | 
					                            severalValues python: (appyType['multiplicity'][1] > 1) or (appyType['multiplicity'][1] == None)">
 | 
				
			||||||
 | 
					              <span tal:condition="not: severalValues" tal:replace="appyValue"></span>
 | 
				
			||||||
 | 
					              <ul tal:condition="python: severalValues">
 | 
				
			||||||
 | 
					                <li tal:repeat="av appyValue" tal:content="av"></li>
 | 
				
			||||||
 | 
					              </ul>
 | 
				
			||||||
 | 
					            </td>
 | 
				
			||||||
 | 
					          </tr>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					      </td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    </tal:event>
 | 
				
			||||||
 | 
					  </table>
 | 
				
			||||||
 | 
					  </tal:history>
 | 
				
			||||||
 | 
					</metal:history>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro displays an object's state(s). It is used by macro "header" below.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:states define-macro="states"
 | 
				
			||||||
 | 
					              tal:define="showAllStatesInPhase python: flavour.getAttr('showAllStatesInPhaseFor' + contextObj.meta_type);
 | 
				
			||||||
 | 
					                          states python: contextObj.getAppyStates(phase, currentOnly=not showAllStatesInPhase)"
 | 
				
			||||||
 | 
					              tal:condition="python: test(showAllStatesInPhase, len(states)>1, True)">
 | 
				
			||||||
 | 
					  <table>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					      <tal:state repeat="stateInfo states">
 | 
				
			||||||
 | 
					        <td tal:attributes="class python: 'appyState step' + stateInfo['stateStatus']"
 | 
				
			||||||
 | 
					            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/skyn/nextState.png"/>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					      </tal:state>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					  </table>
 | 
				
			||||||
 | 
					</metal:states>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro displays an object's transitions(s). It is used by macro "header" below.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:transitions define-macro="transitions"
 | 
				
			||||||
 | 
					                   tal:define="transitions contextObj/getAppyTransitions"
 | 
				
			||||||
 | 
					                   tal:condition="transitions">
 | 
				
			||||||
 | 
					  <form id="triggerTransitionForm" method="post"
 | 
				
			||||||
 | 
					        tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'">
 | 
				
			||||||
 | 
					    <input type="hidden" name="action" 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'+contextObj.meta_type)"
 | 
				
			||||||
 | 
					            align="right" tal:condition="showCommentsField">
 | 
				
			||||||
 | 
					          <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" class="context"
 | 
				
			||||||
 | 
					                 tal:attributes="value python: tool.translate(transition['name']);
 | 
				
			||||||
 | 
					                                 onClick python: 'javascript: triggerTransition(\'%s\')' % transition['id'];"/>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    </table>
 | 
				
			||||||
 | 
					  </form>
 | 
				
			||||||
 | 
					</metal:transitions>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					   This macros displays the page header, containing object title,
 | 
				
			||||||
 | 
					   workflow-related info, object history, etc.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<div metal:define-macro="header"
 | 
				
			||||||
 | 
					     tal:define="showCommonInfo python: layoutType == 'view';
 | 
				
			||||||
 | 
					                 hasHistory contextObj/hasHistory;
 | 
				
			||||||
 | 
					                 historyExpanded python: tool.getCookieValue('appyHistory', default='collapsed') == 'expanded';
 | 
				
			||||||
 | 
					                 creator contextObj/Creator"
 | 
				
			||||||
 | 
					     tal:condition="not: contextObj/isTemporary">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <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 and state</tal:comment>
 | 
				
			||||||
 | 
					        <td width="80%">
 | 
				
			||||||
 | 
					          <b class="appyTitle" tal:content="contextObj/title_or_id"></b>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td><metal:actions use-macro="here/document_actions/macros/document_actions"/>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					      <tr tal:define="descrLabel python: contextObj.translate('%s_edit_descr' % contextObj.portal_type)"
 | 
				
			||||||
 | 
					          tal:condition="descrLabel/strip" >
 | 
				
			||||||
 | 
					        <tal:comment replace="nothing">Content type description</tal:comment>
 | 
				
			||||||
 | 
					        <td colspan="2" class="discreet" tal:content="descrLabel"/>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					      <tr>
 | 
				
			||||||
 | 
					        <td class="documentByLine">
 | 
				
			||||||
 | 
					          <tal:comment replace="nothing">Creator and last modification date</tal:comment>
 | 
				
			||||||
 | 
					            <tal:comment replace="nothing">Plus/minus icon for accessing history</tal:comment>
 | 
				
			||||||
 | 
					            <tal:accessHistory condition="hasHistory">
 | 
				
			||||||
 | 
					            <img align="left" style="cursor:pointer" onClick="javascript:toggleCookie('appyHistory')"
 | 
				
			||||||
 | 
					                 tal:attributes="src python:test(historyExpanded, 'skyn/collapse.gif', 'skyn/expand.gif');"
 | 
				
			||||||
 | 
					                 id="appyHistory_img"/> 
 | 
				
			||||||
 | 
					            <span i18n:translate="label_history" i18n:domain="plone" class="appyHistory"></span> 
 | 
				
			||||||
 | 
					            </tal:accessHistory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <tal:comment replace="nothing">Show document creator</tal:comment>
 | 
				
			||||||
 | 
					            <tal:creator condition="creator"
 | 
				
			||||||
 | 
					                 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"
 | 
				
			||||||
 | 
					                  tal:omit-tag="not:author" i18n:name="author"/>
 | 
				
			||||||
 | 
					            —
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					            </tal:creator>
 | 
				
			||||||
 | 
					            <tal:comment replace="nothing">Show last modification date</tal:comment>
 | 
				
			||||||
 | 
					            <span i18n:translate="box_last_modified" i18n:domain="plone"></span>
 | 
				
			||||||
 | 
					            <span tal:replace="python:contextObj.restrictedTraverse('@@plone').toLocalizedTime(contextObj.ModificationDate(),long_format=1)"></span>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td valign="top"><metal:pod use-macro="here/skyn/page/macros/listPodTemplates"/>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					      <tal:comment replace="nothing">Object history</tal:comment>
 | 
				
			||||||
 | 
					      <tr tal:condition="hasHistory">
 | 
				
			||||||
 | 
					        <td colspan="2">
 | 
				
			||||||
 | 
					          <span id="appyHistory"
 | 
				
			||||||
 | 
					                tal:attributes="style python:test(historyExpanded, 'display:block', 'display:none')">
 | 
				
			||||||
 | 
					          <div tal:define="ajaxHookId python: contextObj.UID() + '_history';"
 | 
				
			||||||
 | 
					               tal:attributes="id ajaxHookId">
 | 
				
			||||||
 | 
					             <script language="javascript" tal:content="python: 'askObjectHistory(\'%s\',\'%s\',0)' % (ajaxHookId, contextObj.absolute_url())">
 | 
				
			||||||
 | 
					             </script>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					      <tal:comment replace="nothing">Workflow-related information and actions</tal:comment>
 | 
				
			||||||
 | 
					      <tr tal:condition="python: showWorkflow and contextObj.getWorkflowLabel()">
 | 
				
			||||||
 | 
					        <td colspan="2" class="appyWorkflow">
 | 
				
			||||||
 | 
					          <table width="100%">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					              <td><metal:states use-macro="here/skyn/page/macros/states"/></td>
 | 
				
			||||||
 | 
					              <td align="right"><metal:states use-macro="here/skyn/page/macros/transitions"/></td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					          </table>
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
 | 
					      </tr>
 | 
				
			||||||
 | 
					    </table>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  The page footer.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:footer define-macro="footer">
 | 
				
			||||||
 | 
					<tal:dummy define="messages putils/showPortalMessages"/>
 | 
				
			||||||
 | 
					<script language="javascript">
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					  // When the current page is loaded, we must set the correct state for all slave fields.
 | 
				
			||||||
 | 
					  var masters = cssQuery('.appyMaster');
 | 
				
			||||||
 | 
					  for (var i=0; i < masters.length; i++) {
 | 
				
			||||||
 | 
					    var cssClasses = masters[i].className.split(' ');
 | 
				
			||||||
 | 
					    for (var j=0; j < cssClasses.length; j++) {
 | 
				
			||||||
 | 
					      if (cssClasses[j].indexOf('master_') == 0) {
 | 
				
			||||||
 | 
					        var appyId = cssClasses[j].split('_')[1];
 | 
				
			||||||
 | 
					        var masterValue = [];
 | 
				
			||||||
 | 
					        if (masters[i].nodeName == 'SPAN'){
 | 
				
			||||||
 | 
					          var idField = masters[i].id;
 | 
				
			||||||
 | 
					          if (idField == '') {
 | 
				
			||||||
 | 
					            masterValue.push(idField);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          else {
 | 
				
			||||||
 | 
					            if (idField[0] == '(') {
 | 
				
			||||||
 | 
					              // There are multiple values, split it
 | 
				
			||||||
 | 
					              var subValues = idField.substring(1, idField.length-1).split(',');
 | 
				
			||||||
 | 
					              for (var k=0; k < subValues.length; k++){
 | 
				
			||||||
 | 
					                var subValue = subValues[k].strip();
 | 
				
			||||||
 | 
					                masterValue.push(subValue.substring(1, subValue.length-1));
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else { masterValue.push(masters[i].id);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else { masterValue = getMasterValue(masters[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        updateSlaves(masterValue, appyId);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					</metal:footer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro shows the range of buttons (next, previous, save,...).
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<div metal:define-macro="buttons"
 | 
				
			||||||
 | 
					     tal:define="previousPage   python: contextObj.getPreviousPage(phaseInfo, page);
 | 
				
			||||||
 | 
					                 nextPage       python: contextObj.getNextPage(phaseInfo, page);
 | 
				
			||||||
 | 
					                 isEdit         python: layoutType == 'edit';">
 | 
				
			||||||
 | 
					    <br/>
 | 
				
			||||||
 | 
					    <tal:previousButton condition="previousPage">
 | 
				
			||||||
 | 
					      <tal:button condition="isEdit">
 | 
				
			||||||
 | 
					        <input type="image" class="imageInput" style="cursor:pointer" name="buttonPrevious"
 | 
				
			||||||
 | 
					               title="label_previous" i18n:attributes="title" i18n:domain="plone"
 | 
				
			||||||
 | 
					               tal:attributes="src string:$portal_url/skyn/previous.png"/>
 | 
				
			||||||
 | 
					        <input type="hidden" name="previousPage"  tal:attributes="value previousPage"/>
 | 
				
			||||||
 | 
					      </tal:button>
 | 
				
			||||||
 | 
					      <tal:link condition="not: isEdit">
 | 
				
			||||||
 | 
					        <a tal:attributes="href python: contextObj.getUrl()+'?page=%s' % previousPage">
 | 
				
			||||||
 | 
					          <img tal:attributes="src string:$portal_url/skyn/previous.png"
 | 
				
			||||||
 | 
					               title="label_previous" i18n:attributes="title" i18n:domain="plone"/>
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					      </tal:link>
 | 
				
			||||||
 | 
					    </tal:previousButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <tal:saveButton condition="isEdit">
 | 
				
			||||||
 | 
					      <input type="image" class="imageInput" style="cursor:pointer" name="buttonOk"
 | 
				
			||||||
 | 
					             title="label_save" i18n:attributes="title" i18n:domain="plone"
 | 
				
			||||||
 | 
					             tal:attributes="src string:$portal_url/skyn/save.png"/>
 | 
				
			||||||
 | 
					    </tal:saveButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <tal:cancelButton condition="isEdit">
 | 
				
			||||||
 | 
					      <input type="image" class="imageInput" style="cursor:pointer" name="buttonCancel"
 | 
				
			||||||
 | 
					             title="label_cancel" i18n:attributes="title" i18n:domain="plone"
 | 
				
			||||||
 | 
					             tal:attributes="src string:$portal_url/skyn/cancel.png"/>
 | 
				
			||||||
 | 
					    </tal:cancelButton>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <tal:editLink condition="not:isEdit">
 | 
				
			||||||
 | 
					      <img tal:define="nav request/nav|nothing;
 | 
				
			||||||
 | 
					                       nav python: test(nav, '&nav=%s' % nav, '')"
 | 
				
			||||||
 | 
					           title="Edit" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
 | 
				
			||||||
 | 
					           tal:attributes="onClick python: 'href: window.location=\'%s/skyn/edit?page=%s%s\'' % (contextObj.absolute_url(), page, nav);
 | 
				
			||||||
 | 
					                           src string: $portal_url/skyn/editBig.png"
 | 
				
			||||||
 | 
					           tal:condition="python: member.has_permission('Modify portal content', contextObj)"/>
 | 
				
			||||||
 | 
					    </tal:editLink>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <tal:nextButton condition="nextPage">
 | 
				
			||||||
 | 
					      <tal:button condition="isEdit">
 | 
				
			||||||
 | 
					        <input type="image" class="imageInput" style="cursor:pointer" name="buttonNext"
 | 
				
			||||||
 | 
					               title="label_next" i18n:attributes="title" i18n:domain="plone"
 | 
				
			||||||
 | 
					               tal:attributes="src string:$portal_url/skyn/next.png"/>
 | 
				
			||||||
 | 
					        <input type="hidden" name="nextPage"  tal:attributes="value nextPage"/>
 | 
				
			||||||
 | 
					      </tal:button>
 | 
				
			||||||
 | 
					      <tal:link condition="not: isEdit">
 | 
				
			||||||
 | 
					        <a tal:attributes="href python: contextObj.getUrl()+'?&page=%s' % nextPage">
 | 
				
			||||||
 | 
					          <img tal:attributes="src string:$portal_url/skyn/next.png"
 | 
				
			||||||
 | 
					               title="label_next" i18n:attributes="title" i18n:domain="plone"/>
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					      </tal:link>
 | 
				
			||||||
 | 
					    </tal:nextButton>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro displays the global message on the page.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:message define-macro="message" i18n:domain="plone" >
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Single message from portal_status_message request key</tal:comment>
 | 
				
			||||||
 | 
					  <div tal:define="msg request/portal_status_message | nothing"
 | 
				
			||||||
 | 
					       tal:condition="msg" class="portalMessage" tal:content="msg" i18n:translate=""></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Messages added via plone_utils</tal:comment>
 | 
				
			||||||
 | 
					  <tal:messages define="messages putils/showPortalMessages" condition="messages">
 | 
				
			||||||
 | 
					    <tal:msgs define="type_css_map python: {'info':'portalMessage', 'warn':'portalWarningMessage',
 | 
				
			||||||
 | 
					                                            'stop':'portalStopMessage'};"
 | 
				
			||||||
 | 
					              repeat="msg messages">
 | 
				
			||||||
 | 
					      <div tal:define="mtype msg/type | nothing;"
 | 
				
			||||||
 | 
					           tal:attributes="class python:mtype and type_css_map[mtype] or 'info';"
 | 
				
			||||||
 | 
					           tal:content="structure msg/message | nothing" i18n:translate=""></div>
 | 
				
			||||||
 | 
					    </tal:msgs>
 | 
				
			||||||
 | 
					  </tal:messages>
 | 
				
			||||||
 | 
					</metal:message>
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,8 @@
 | 
				
			||||||
<metal:portletContent define-macro="portletContent"
 | 
					<metal:portletContent define-macro="portletContent"
 | 
				
			||||||
   tal:define="queryUrl           python: '%s/skyn/query' % appFolder.absolute_url();
 | 
					   tal:define="queryUrl           python: '%s/skyn/query' % appFolder.absolute_url();
 | 
				
			||||||
               currentSearch      request/search|nothing;
 | 
					               currentSearch      request/search|nothing;
 | 
				
			||||||
               currentType request/type_name|nothing;">
 | 
					               currentType        request/type_name|nothing;
 | 
				
			||||||
 | 
					               contextObj         python: tool.getPublishedObject(rootClasses)">
 | 
				
			||||||
  <tal:comment replace="nothing">Portlet title, with link to tool.</tal:comment>
 | 
					  <tal:comment replace="nothing">Portlet title, with link to tool.</tal:comment>
 | 
				
			||||||
  <dt class="portletHeader">
 | 
					  <dt class="portletHeader">
 | 
				
			||||||
    <tal:comment replace="nothing">If there is only one flavour, clicking on the portlet
 | 
					    <tal:comment replace="nothing">If there is only one flavour, clicking on the portlet
 | 
				
			||||||
| 
						 | 
					@ -27,6 +28,14 @@
 | 
				
			||||||
    </td>
 | 
					    </td>
 | 
				
			||||||
  </dt>
 | 
					  </dt>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:publishedObject condition="python: contextObj">
 | 
				
			||||||
 | 
					  <dt class="portletAppyItem portletCurrent">
 | 
				
			||||||
 | 
					    <a tal:attributes="href python: contextObj.getUrl() + '?page=main'"
 | 
				
			||||||
 | 
					       tal:content="contextObj/Title"></a>
 | 
				
			||||||
 | 
					  </dt>
 | 
				
			||||||
 | 
					  <dt class="portletAppyItem"><metal:phases use-macro="here/skyn/portlet/macros/phases"/></dt>
 | 
				
			||||||
 | 
					  </tal:publishedObject>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <tal:comment replace="nothing">TODO: implement a widget for selecting the needed flavour.</tal:comment>
 | 
					  <tal:comment replace="nothing">TODO: implement a widget for selecting the needed flavour.</tal:comment>
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  <tal:comment replace="nothing">Create a section for every root class.</tal:comment>
 | 
					  <tal:comment replace="nothing">Create a section for every root class.</tal:comment>
 | 
				
			||||||
| 
						 | 
					@ -34,7 +43,7 @@
 | 
				
			||||||
               define="flavourNumber python:1;
 | 
					               define="flavourNumber python:1;
 | 
				
			||||||
                       flavour python: tool.getFlavour('Dummy_%d' % flavourNumber)">
 | 
					                       flavour python: tool.getFlavour('Dummy_%d' % flavourNumber)">
 | 
				
			||||||
    <tal:comment replace="nothing">Section title, with action icons</tal:comment>
 | 
					    <tal:comment replace="nothing">Section title, with action icons</tal:comment>
 | 
				
			||||||
    <dt tal:attributes="class python:test(repeat['rootClass'].number()==1, 'portletAppyItem', 'portletAppyItem portletSep')">
 | 
					    <dt tal:attributes="class python:test((repeat['rootClass'].number()==1) and not contextObj, 'portletAppyItem', 'portletAppyItem portletSep')">
 | 
				
			||||||
      <table width="100%" cellspacing="0" cellpadding="0" class="no-style-table">
 | 
					      <table width="100%" cellspacing="0" cellpadding="0" class="no-style-table">
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
          <td>
 | 
					          <td>
 | 
				
			||||||
| 
						 | 
					@ -44,7 +53,7 @@
 | 
				
			||||||
          </td>
 | 
					          </td>
 | 
				
			||||||
          <td align="right"
 | 
					          <td align="right"
 | 
				
			||||||
              tal:define="addPermission python: '%s: Add %s' % (appName, rootClass);
 | 
					              tal:define="addPermission python: '%s: Add %s' % (appName, rootClass);
 | 
				
			||||||
                          userMayAdd python: member.has_permission(addPermission, appFolder);
 | 
					                          userMayAdd python: member.has_permission(addPermission, appFolder) and tool.userMayAdd(rootClass);
 | 
				
			||||||
                          createMeans python: tool.getCreateMeans(rootClass)">
 | 
					                          createMeans python: tool.getCreateMeans(rootClass)">
 | 
				
			||||||
            <tal:comment replace="nothing">Create a new object from a web form</tal:comment>
 | 
					            <tal:comment replace="nothing">Create a new object from a web form</tal:comment>
 | 
				
			||||||
            <img style="cursor:pointer"
 | 
					            <img style="cursor:pointer"
 | 
				
			||||||
| 
						 | 
					@ -115,11 +124,6 @@
 | 
				
			||||||
                       href python:'%s?type_name=%s&flavourNumber=%d' % (queryUrl, rootClassesQuery, flavourNumber)"></a>
 | 
					                       href python:'%s?type_name=%s&flavourNumber=%d' % (queryUrl, rootClassesQuery, flavourNumber)"></a>
 | 
				
			||||||
  </dt-->
 | 
					  </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>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">
 | 
					  <tal:comment replace="nothing">
 | 
				
			||||||
    Greyed transparent zone that is deployed on the
 | 
					    Greyed transparent zone that is deployed on the
 | 
				
			||||||
    whole screen when a popup is displayed.
 | 
					    whole screen when a popup is displayed.
 | 
				
			||||||
| 
						 | 
					@ -140,3 +144,52 @@
 | 
				
			||||||
  </form>
 | 
					  </form>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</metal:portletContent>
 | 
					</metal:portletContent>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					   This macro displays, within the portlet, the navigation tree for the
 | 
				
			||||||
 | 
					   currently shown object, made of phases and contained pages.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:phases define-macro="phases">
 | 
				
			||||||
 | 
					<table tal:define="phases   contextObj/getAppyPhases|nothing;
 | 
				
			||||||
 | 
					                   page python: request.get('page', 'main')"
 | 
				
			||||||
 | 
					       tal:condition="python: phases and not ((len(phases)==1) and len(phases[0]['pages'])==1)"
 | 
				
			||||||
 | 
					       cellspacing="1" cellpadding="0" width="100%">
 | 
				
			||||||
 | 
					  <tal:phase repeat="phase phases">
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">The box containing phase-related information</tal:comment>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					      <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()) and (len(phase['pages']) == 1)"
 | 
				
			||||||
 | 
					          tal:attributes="class python: 'appyPhase step' + phase['phaseStatus']">
 | 
				
			||||||
 | 
					        <span class="portletGroup" tal:condition="python: len(phases) > 1">
 | 
				
			||||||
 | 
					        <a tal:attributes="href python: '%s?page=%s' % (contextObj.getUrl(), phase['pages'][0]);"
 | 
				
			||||||
 | 
					           tal:condition="displayLink"
 | 
				
			||||||
 | 
					           tal:content="python: tool.translate(label)"></a>
 | 
				
			||||||
 | 
					        <span tal:condition="not: displayLink" tal:replace="python: tool.translate(label)"/>
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
 | 
					        <table width="100%" cellpadding="0" cellspacing="0"
 | 
				
			||||||
 | 
					               tal:condition="python: len(phase['pages']) > 1">
 | 
				
			||||||
 | 
					          <tr tal:repeat="aPage phase/pages" valign="top">
 | 
				
			||||||
 | 
					            <td tal:attributes="class python: test(aPage == page, 'portletCurrent portletPageItem', 'portletPageItem')">
 | 
				
			||||||
 | 
					              <a tal:attributes="href python: contextObj.getUrl()+'?page=%s' % aPage"
 | 
				
			||||||
 | 
					                 tal:content="structure python: tool.translate('%s_page_%s' % (contextObj.meta_type, aPage))">
 | 
				
			||||||
 | 
					              </a>
 | 
				
			||||||
 | 
					            </td>
 | 
				
			||||||
 | 
					            <td>
 | 
				
			||||||
 | 
					              <img tal:define="nav request/nav|nothing;
 | 
				
			||||||
 | 
					                               nav python: test(nav, '&nav=%s' % nav, '')"
 | 
				
			||||||
 | 
					                   title="Edit" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
 | 
				
			||||||
 | 
					                   tal:attributes="onClick python: 'href: window.location=\'%s/skyn/edit?page=%s%s\'' % (contextObj.absolute_url(), aPage, nav);
 | 
				
			||||||
 | 
					                               src string: $portal_url/skyn/edit.gif"
 | 
				
			||||||
 | 
					                   tal:condition="python: member.has_permission('Modify portal content', contextObj)"/>
 | 
				
			||||||
 | 
					            </td>
 | 
				
			||||||
 | 
					          </tr>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					      </td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">The down arrow pointing to the next phase (if any)</tal:comment>
 | 
				
			||||||
 | 
					    <tr tal:condition="python: phase['name'] != phases[-1]['name']">
 | 
				
			||||||
 | 
					      <td>  <img tal:attributes="src string: $portal_url/skyn/nextPhase.png"/></td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					  </tal:phase>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					</metal:phases>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/previous.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 905 B  | 
| 
						 | 
					@ -20,7 +20,7 @@
 | 
				
			||||||
                 flavourNumber python:int(context.REQUEST.get('flavourNumber'));
 | 
					                 flavourNumber python:int(context.REQUEST.get('flavourNumber'));
 | 
				
			||||||
                 searchName python:context.REQUEST.get('search', '')">
 | 
					                 searchName python:context.REQUEST.get('search', '')">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
 | 
					  <div metal:use-macro="here/skyn/page/macros/prologue"/>
 | 
				
			||||||
  <tal:comment replace="nothing">Query result</tal:comment>
 | 
					  <tal:comment replace="nothing">Query result</tal:comment>
 | 
				
			||||||
  <div id="queryResult"></div>
 | 
					  <div id="queryResult"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/required.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 423 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/save.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
						 | 
					@ -32,13 +32,13 @@
 | 
				
			||||||
    <table class="no-style-table" cellpadding="0" cellspacing="0" width="100%"
 | 
					    <table class="no-style-table" cellpadding="0" cellspacing="0" width="100%"
 | 
				
			||||||
           tal:define="numberOfColumns python: flavour.getAttr('numberOfSearchColumnsFor%s' % contentType)">
 | 
					           tal:define="numberOfColumns python: flavour.getAttr('numberOfSearchColumnsFor%s' % contentType)">
 | 
				
			||||||
      <tr tal:repeat="searchRow python: tool.tabularize(searchableFields, numberOfColumns)" valign="top">
 | 
					      <tr tal:repeat="searchRow python: tool.tabularize(searchableFields, numberOfColumns)" valign="top">
 | 
				
			||||||
        <td tal:repeat="searchField searchRow" tal:attributes="width python:'%d%%' % (100/numberOfColumns)">
 | 
					        <td tal:repeat="widget searchRow" tal:attributes="width python:'%d%%' % (100/numberOfColumns)">
 | 
				
			||||||
          <tal:field condition="searchField">
 | 
					          <tal:field condition="widget">
 | 
				
			||||||
            <tal:showSearchField define="fieldName python:searchField[0];
 | 
					            <tal:show define="name widget/name;
 | 
				
			||||||
                                         appyType python:searchField[1];
 | 
					                                   widgetName python: 'w_%s' % name;
 | 
				
			||||||
                                         widgetName python: 'w_%s' % fieldName">
 | 
					                                   macroPage python: widget['type'].lower()">
 | 
				
			||||||
              <metal:searchField use-macro="python: appFolder.skyn.widgets.macros.get('search%s' % searchField[1]['type'])"/>
 | 
					              <metal:call use-macro="python: appFolder.skyn.widgets.get(macroPage).macros.get('search')"/>
 | 
				
			||||||
            </tal:showSearchField>
 | 
					            </tal:show>
 | 
				
			||||||
          </tal:field><br class="discreet"/>
 | 
					          </tal:field><br class="discreet"/>
 | 
				
			||||||
        </td>
 | 
					        </td>
 | 
				
			||||||
      </tr>
 | 
					      </tr>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/space.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 43 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/tabBg.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 149 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/tabBgu.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 168 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/tabLeft.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 203 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/tabLeftu.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 180 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/tabRight.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 207 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/tabRightu.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 171 B  | 
| 
						 | 
					@ -18,20 +18,19 @@
 | 
				
			||||||
      tal:define="contextObj python:context.getParentNode();
 | 
					      tal:define="contextObj python:context.getParentNode();
 | 
				
			||||||
                  portal_type python:here.getPortalTypeName().lower().replace(' ', '_');
 | 
					                  portal_type python:here.getPortalTypeName().lower().replace(' ', '_');
 | 
				
			||||||
                  errors python:request.get('errors', {});
 | 
					                  errors python:request.get('errors', {});
 | 
				
			||||||
                  isEdit python:False;
 | 
					                  layoutType python:'view';
 | 
				
			||||||
 | 
					                  layout python: contextObj.getPageLayout(layoutType);
 | 
				
			||||||
                  tool contextObj/getTool;
 | 
					                  tool contextObj/getTool;
 | 
				
			||||||
                  flavour python: tool.getFlavour(contextObj);
 | 
					                  flavour python: tool.getFlavour(contextObj);
 | 
				
			||||||
                  appFolder tool/getAppFolder;
 | 
					                  appFolder tool/getAppFolder;
 | 
				
			||||||
                  appName appFolder/id;
 | 
					                  appName appFolder/getId;
 | 
				
			||||||
                  phaseInfo python: contextObj.getAppyPhases(currentOnly=True, forPlone=False);
 | 
					                  page request/page|python:'main';
 | 
				
			||||||
                  phase request/phase|phaseInfo/name;
 | 
					                  phaseInfo python: contextObj.getAppyPhases(page=page);
 | 
				
			||||||
                  appyPages python: contextObj.getAppyPages(phase);
 | 
					                  phase phaseInfo/name;
 | 
				
			||||||
                  pageName python: contextObj.getAppyPage(isEdit, phaseInfo, appyPages);
 | 
					 | 
				
			||||||
                  showWorkflow python: flavour.getAttr('showWorkflowFor' + contextObj.meta_type)">
 | 
					                  showWorkflow python: flavour.getAttr('showWorkflowFor' + contextObj.meta_type)">
 | 
				
			||||||
      <metal:prologue use-macro="here/skyn/macros/macros/pagePrologue"/>
 | 
					      <metal:prologue use-macro="here/skyn/page/macros/prologue"/>
 | 
				
			||||||
      <metal:header   use-macro="here/skyn/macros/macros/showPageHeader"/>
 | 
					      <metal:show     use-macro="here/skyn/page/macros/show"/>
 | 
				
			||||||
      <metal:fields   use-macro="here/skyn/macros/macros/listFields" />
 | 
					      <metal:footer   use-macro="here/skyn/page/macros/footer"/>
 | 
				
			||||||
      <metal:footer   use-macro="here/skyn/macros/macros/showPageFooter"/>
 | 
					 | 
				
			||||||
    </metal:fill>
 | 
					    </metal:fill>
 | 
				
			||||||
  </body>
 | 
					  </body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/warning.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 400 B  | 
							
								
								
									
										
											BIN
										
									
								
								gen/plone25/skin/warning_no.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 319 B  | 
| 
						 | 
					@ -1,142 +0,0 @@
 | 
				
			||||||
<metal:searchInteger define-macro="searchInteger">
 | 
					 | 
				
			||||||
  <label tal:content="python: tool.translate(appyType['label'])"></label><br>  
 | 
					 | 
				
			||||||
  <tal:from define="fromName python: '%s*int' % widgetName">
 | 
					 | 
				
			||||||
    <label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
 | 
					 | 
				
			||||||
    <input type="text" tal:attributes="name fromName" size="4"/>
 | 
					 | 
				
			||||||
  </tal:from>
 | 
					 | 
				
			||||||
  <tal:to define="toName python: '%s_to' % fieldName">
 | 
					 | 
				
			||||||
    <label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
 | 
					 | 
				
			||||||
    <input type="text" tal:attributes="name toName" size="4"/>
 | 
					 | 
				
			||||||
  </tal:to><br/>
 | 
					 | 
				
			||||||
</metal:searchInteger>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchFloat define-macro="searchFloat">
 | 
					 | 
				
			||||||
  <label tal:content="python: tool.translate(appyType['label'])"></label><br>  
 | 
					 | 
				
			||||||
  <tal:from define="fromName python: '%s*float' % widgetName">
 | 
					 | 
				
			||||||
    <label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
 | 
					 | 
				
			||||||
    <input type="text" tal:attributes="name fromName" size="4"/>
 | 
					 | 
				
			||||||
  </tal:from>
 | 
					 | 
				
			||||||
  <tal:to define="toName python: '%s_to' % fieldName">
 | 
					 | 
				
			||||||
    <label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
 | 
					 | 
				
			||||||
    <input type="text" tal:attributes="name toName" size="4"/>
 | 
					 | 
				
			||||||
  </tal:to><br/>
 | 
					 | 
				
			||||||
</metal:searchFloat>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchString define-macro="searchString">
 | 
					 | 
				
			||||||
  <label tal:attributes="for widgetName" tal:content="python: tool.translate(appyType['label'])"></label><br>  
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">Show a simple search field for most String fields.</tal:comment>
 | 
					 | 
				
			||||||
  <tal:simpleSearch condition="not: appyType/isSelect">
 | 
					 | 
				
			||||||
    <input type="text" tal:attributes="name python: '%s*string-%s' % (widgetName, appyType['transform']);
 | 
					 | 
				
			||||||
                                       style python: 'text-transform:%s' % appyType['transform']"/>
 | 
					 | 
				
			||||||
  </tal:simpleSearch>
 | 
					 | 
				
			||||||
  <tal:comment replace="nothing">Show a multi-selection box for fields whose validator defines a list of values, with a "AND/OR" checkbox.</tal:comment>
 | 
					 | 
				
			||||||
  <tal:selectSearch condition="appyType/isSelect">
 | 
					 | 
				
			||||||
    <tal:comment replace="nothing">The "and" / "or" radio buttons</tal:comment>
 | 
					 | 
				
			||||||
    <tal:operator define="operName python: 'o_%s'   % fieldName;
 | 
					 | 
				
			||||||
                          orName   python: '%s_or'  % operName;
 | 
					 | 
				
			||||||
                          andName  python: '%s_and' % operName;"
 | 
					 | 
				
			||||||
                  condition="python: appyType['multiplicity'][1]!=1">
 | 
					 | 
				
			||||||
    <input type="radio" class="noborder" tal:attributes="name operName; id orName" checked="checked" value="or"/>
 | 
					 | 
				
			||||||
    <label tal:attributes="for orName" tal:content="python: tool.translate('search_or')"></label>
 | 
					 | 
				
			||||||
    <input type="radio" class="noborder" tal:attributes="name operName; id andName" value="and"/>
 | 
					 | 
				
			||||||
    <label tal:attributes="for andName" tal:content="python: tool.translate('search_and')"></label><br/>
 | 
					 | 
				
			||||||
    </tal:operator>
 | 
					 | 
				
			||||||
    <tal:comment replace="nothing">The list of values</tal:comment>
 | 
					 | 
				
			||||||
    <select tal:attributes="name widgetName" multiple="multiple" size="5">
 | 
					 | 
				
			||||||
      <option tal:repeat="v python:tool.getSelectValues(appyType)"
 | 
					 | 
				
			||||||
              tal:attributes="value python:v[0]" tal:content="python: v[1]">
 | 
					 | 
				
			||||||
      </option>
 | 
					 | 
				
			||||||
    </select>
 | 
					 | 
				
			||||||
  </tal:selectSearch><br/>
 | 
					 | 
				
			||||||
</metal:searchString>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchBoolean define-macro="searchBoolean"
 | 
					 | 
				
			||||||
                     tal:define="typedWidget python:'%s*bool' % widgetName">
 | 
					 | 
				
			||||||
  <label tal:attributes="for widgetName" tal:content="python: tool.translate(appyType['label'])"></label><br>  
 | 
					 | 
				
			||||||
  <tal:yes define="valueId python:'%s_yes' % fieldName">
 | 
					 | 
				
			||||||
    <input type="radio" class="noborder" value="True" tal:attributes="name typedWidget; id valueId"/>
 | 
					 | 
				
			||||||
    <label tal:attributes="for valueId" i18n:translate="yes" i18n:domain="plone"></label>
 | 
					 | 
				
			||||||
  </tal:yes>
 | 
					 | 
				
			||||||
  <tal:no define="valueId python:'%s_no' % fieldName">
 | 
					 | 
				
			||||||
    <input type="radio" class="noborder" value="False" tal:attributes="name typedWidget; id valueId"/>
 | 
					 | 
				
			||||||
    <label tal:attributes="for valueId" i18n:translate="no" i18n:domain="plone"></label>
 | 
					 | 
				
			||||||
  </tal:no>
 | 
					 | 
				
			||||||
  <tal:whatever define="valueId python:'%s_whatever' % fieldName">
 | 
					 | 
				
			||||||
    <input type="radio" class="noborder" value="" tal:attributes="name typedWidget; id valueId" checked="checked"/>
 | 
					 | 
				
			||||||
    <label tal:attributes="for valueId" tal:content="python: tool.translate('whatever')"></label>
 | 
					 | 
				
			||||||
  </tal:whatever><br/>
 | 
					 | 
				
			||||||
</metal:searchBoolean>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchDate define-macro="searchDate">
 | 
					 | 
				
			||||||
  <label tal:content="python: tool.translate(appyType['label'])"></label>
 | 
					 | 
				
			||||||
  <table cellpadding="0" cellspacing="0">
 | 
					 | 
				
			||||||
    <tal:comment replace="nothing">From</tal:comment>
 | 
					 | 
				
			||||||
    <tr tal:define="fromName python: '%s*date' % widgetName">
 | 
					 | 
				
			||||||
      <td width="10px"> </td>
 | 
					 | 
				
			||||||
      <td>
 | 
					 | 
				
			||||||
        <label tal:content="python: tool.translate('search_from')"></label>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
      <td>
 | 
					 | 
				
			||||||
        <select tal:attributes="name fromName">
 | 
					 | 
				
			||||||
          <option value="">--</option>
 | 
					 | 
				
			||||||
          <option tal:repeat="value python:range(appyType['startYear'], appyType['endYear']+1)"
 | 
					 | 
				
			||||||
                  tal:content="value" tal:attributes="value value"></option>
 | 
					 | 
				
			||||||
        </select> /
 | 
					 | 
				
			||||||
        <select tal:attributes="name python: '%s_from_month' % fieldName">
 | 
					 | 
				
			||||||
          <option value="">--</option>
 | 
					 | 
				
			||||||
          <option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 13)]"
 | 
					 | 
				
			||||||
                  tal:content="python:tool.getMonthName(value)" tal:attributes="value value"></option>
 | 
					 | 
				
			||||||
        </select> /
 | 
					 | 
				
			||||||
        <select tal:attributes="name python: '%s_from_day' % fieldName">
 | 
					 | 
				
			||||||
          <option value="">--</option>
 | 
					 | 
				
			||||||
          <option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 32)]"
 | 
					 | 
				
			||||||
                  tal:content="value" tal:attributes="value value"></option>
 | 
					 | 
				
			||||||
        </select>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
    </tr>
 | 
					 | 
				
			||||||
    <tal:comment replace="nothing">To</tal:comment>
 | 
					 | 
				
			||||||
    <tr>
 | 
					 | 
				
			||||||
      <td></td>
 | 
					 | 
				
			||||||
      <td>
 | 
					 | 
				
			||||||
        <label tal:content="python: tool.translate('search_to')"></label>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
      <td>
 | 
					 | 
				
			||||||
        <select tal:attributes="name python: '%s_to_year' % fieldName">
 | 
					 | 
				
			||||||
          <option value="">--</option>
 | 
					 | 
				
			||||||
          <option tal:repeat="value python:range(appyType['startYear'], appyType['endYear']+1)"
 | 
					 | 
				
			||||||
                 tal:content="value" tal:attributes="value value"></option>
 | 
					 | 
				
			||||||
        </select> /
 | 
					 | 
				
			||||||
        <select tal:attributes="name python: '%s_to_month' % fieldName">
 | 
					 | 
				
			||||||
          <option value="">--</option>
 | 
					 | 
				
			||||||
          <option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 13)]"
 | 
					 | 
				
			||||||
                  tal:content="python:tool.getMonthName(value)" tal:attributes="value value"></option>
 | 
					 | 
				
			||||||
        </select> /
 | 
					 | 
				
			||||||
        <select tal:attributes="name python: '%s_to_day' % fieldName">
 | 
					 | 
				
			||||||
          <option value="">--</option>
 | 
					 | 
				
			||||||
          <option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 32)]"
 | 
					 | 
				
			||||||
                  tal:content="value" tal:attributes="value value"></option>
 | 
					 | 
				
			||||||
        </select>
 | 
					 | 
				
			||||||
      </td>
 | 
					 | 
				
			||||||
    </tr>
 | 
					 | 
				
			||||||
  </table>
 | 
					 | 
				
			||||||
</metal:searchDate>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchFile define-macro="searchFile">
 | 
					 | 
				
			||||||
  <p tal:content="fieldName"></p>
 | 
					 | 
				
			||||||
</metal:searchFile>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchRef define-macro="searchRef">
 | 
					 | 
				
			||||||
  <p tal:content="fieldName"></p>
 | 
					 | 
				
			||||||
</metal:searchRef>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchComputed define-macro="searchComputed">
 | 
					 | 
				
			||||||
  <p tal:content="fieldName"></p>
 | 
					 | 
				
			||||||
</metal:searchComputed>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchAction define-macro="searchAction">
 | 
					 | 
				
			||||||
  <p tal:content="fieldName"></p>
 | 
					 | 
				
			||||||
</metal:searchAction>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<metal:searchInfo define-macro="searchInfo">
 | 
					 | 
				
			||||||
  <p tal:content="fieldName"></p>
 | 
					 | 
				
			||||||
</metal:searchInfo>
 | 
					 | 
				
			||||||
							
								
								
									
										30
									
								
								gen/plone25/skin/widgets/action.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for an Action.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view">
 | 
				
			||||||
 | 
					  <form name="executeAppyAction"
 | 
				
			||||||
 | 
					        tal:define="formId python: '%s_%s' % (contextObj.UID(), name);
 | 
				
			||||||
 | 
					                    label  python: contextObj.translate(widget['labelId'])"
 | 
				
			||||||
 | 
					        tal:attributes="id formId; action python: contextObj.absolute_url()+'/skyn/do'">
 | 
				
			||||||
 | 
					    <input type="hidden" name="action" value="ExecuteAppyAction"/>
 | 
				
			||||||
 | 
					    <input type="hidden" name="objectUid" tal:attributes="value contextObj/UID"/>
 | 
				
			||||||
 | 
					    <input type="hidden" name="fieldName" tal:attributes="value name"/>
 | 
				
			||||||
 | 
					    <input type="button" tal:condition="widget/confirm"
 | 
				
			||||||
 | 
					           tal:attributes="value label;
 | 
				
			||||||
 | 
					                           onClick python: 'javascript:askConfirm(\'%s\')' % formId"/>
 | 
				
			||||||
 | 
					    <input type="submit" name="do" tal:condition="not: widget/confirm"
 | 
				
			||||||
 | 
					           tal:attributes="value label" onClick="javascript:;"/>
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">The previous onClick is simply used to prevent Plone
 | 
				
			||||||
 | 
					      from adding a CSS class that displays a popup when the user triggers the form multiple
 | 
				
			||||||
 | 
					      times.</tal:comment>
 | 
				
			||||||
 | 
					  </form>
 | 
				
			||||||
 | 
					</metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for an Action.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit"></metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for an Action.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/action/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for an Action.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search"></metal:search>
 | 
				
			||||||
							
								
								
									
										39
									
								
								gen/plone25/skin/widgets/boolean.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for a Boolean.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view"><span tal:replace="value"/></metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for an Boolean.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit">
 | 
				
			||||||
 | 
					  <input type="checkbox"
 | 
				
			||||||
 | 
					         tal:attributes="name python: name + '_visible';
 | 
				
			||||||
 | 
					                         id name;
 | 
				
			||||||
 | 
					                         checked python:contextObj.checkboxChecked(name);
 | 
				
			||||||
 | 
					                         onClick python:'toggleCheckbox(\'%s\', \'%s_hidden\');;updateSlaves(getMasterValue(this), \'%s\')' % (name, name, widget['id']);
 | 
				
			||||||
 | 
					                         class python: 'noborder ' + widget['master_css']"/>
 | 
				
			||||||
 | 
					  <input tal:attributes="name name;
 | 
				
			||||||
 | 
					                         id string:${name}_hidden;
 | 
				
			||||||
 | 
					                         value python: test(contextObj.checkboxChecked(name), 'True', 'False')"
 | 
				
			||||||
 | 
					         type="hidden" /> 
 | 
				
			||||||
 | 
					</metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for an Boolean.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/boolean/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for an Boolean.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search"
 | 
				
			||||||
 | 
					              tal:define="typedWidget python:'%s*bool' % widgetName">
 | 
				
			||||||
 | 
					  <label tal:attributes="for widgetName" tal:content="python: tool.translate(widget['labelId'])"></label><br>  
 | 
				
			||||||
 | 
					  <tal:yes define="valueId python:'%s_yes' % name">
 | 
				
			||||||
 | 
					    <input type="radio" class="noborder" value="True" tal:attributes="name typedWidget; id valueId"/>
 | 
				
			||||||
 | 
					    <label tal:attributes="for valueId" i18n:translate="yes" i18n:domain="plone"></label>
 | 
				
			||||||
 | 
					  </tal:yes>
 | 
				
			||||||
 | 
					  <tal:no define="valueId python:'%s_no' % name">
 | 
				
			||||||
 | 
					    <input type="radio" class="noborder" value="False" tal:attributes="name typedWidget; id valueId"/>
 | 
				
			||||||
 | 
					    <label tal:attributes="for valueId" i18n:translate="no" i18n:domain="plone"></label>
 | 
				
			||||||
 | 
					  </tal:no>
 | 
				
			||||||
 | 
					  <tal:whatever define="valueId python:'%s_whatever' % name">
 | 
				
			||||||
 | 
					    <input type="radio" class="noborder" value="" tal:attributes="name typedWidget; id valueId" checked="checked"/>
 | 
				
			||||||
 | 
					    <label tal:attributes="for valueId" tal:content="python: tool.translate('whatever')"></label>
 | 
				
			||||||
 | 
					  </tal:whatever><br/>
 | 
				
			||||||
 | 
					</metal:search>
 | 
				
			||||||
							
								
								
									
										18
									
								
								gen/plone25/skin/widgets/computed.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for a Computed.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view">
 | 
				
			||||||
 | 
					  <span tal:condition="widget/plainText" tal:replace="value"/>
 | 
				
			||||||
 | 
					  <span tal:condition="not: widget/plainText" tal:replace="structure value"/>
 | 
				
			||||||
 | 
					</metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for a Computed.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/computed/macros/view"/>
 | 
				
			||||||
 | 
					</metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for a Computed.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/computed/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for a Computed.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search"></metal:search>
 | 
				
			||||||
							
								
								
									
										132
									
								
								gen/plone25/skin/widgets/date.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,132 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for a Date.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view"><span tal:replace="value"/></metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for an Date.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit"
 | 
				
			||||||
 | 
					            tal:define="years python:range(widget['startYear'], widget['endYear']+1);
 | 
				
			||||||
 | 
					                        dummyName python: '_d_ummy_%s' % name">
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">This field is not used but required by the Javascript popup.</tal:comment>
 | 
				
			||||||
 | 
					  <input type="hidden" tal:attributes="name dummyName; id dummyName"/>
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Day</tal:comment>
 | 
				
			||||||
 | 
					  <select tal:define="days python:range(1,32)"
 | 
				
			||||||
 | 
					          tal:attributes="name string:${name}_day;
 | 
				
			||||||
 | 
					                          id   string:${name}_day;">
 | 
				
			||||||
 | 
					    <option value="">-</option>
 | 
				
			||||||
 | 
					    <tal:days repeat="day days">
 | 
				
			||||||
 | 
					      <option tal:define="zDay python: str(day).zfill(2)"
 | 
				
			||||||
 | 
					              tal:attributes="value zDay;
 | 
				
			||||||
 | 
					                              selected python:contextObj.dateValueSelected(name, 'day', day)"
 | 
				
			||||||
 | 
					              tal:content="zDay"></option>
 | 
				
			||||||
 | 
					    </tal:days>
 | 
				
			||||||
 | 
					  </select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Month</tal:comment>
 | 
				
			||||||
 | 
					  <select tal:define="months python:range(1,13)"
 | 
				
			||||||
 | 
					          tal:attributes="name string:${name}_month;
 | 
				
			||||||
 | 
					                          id   string:${name}_month;">
 | 
				
			||||||
 | 
					    <option value="">-</option>
 | 
				
			||||||
 | 
					    <tal:months repeat="month months">
 | 
				
			||||||
 | 
					      <option tal:define="zMonth python: str(month).zfill(2)"
 | 
				
			||||||
 | 
					              tal:attributes="value zMonth;
 | 
				
			||||||
 | 
					                              selected python:contextObj.dateValueSelected(name, 'month', month)"
 | 
				
			||||||
 | 
					              tal:content="zMonth"></option>
 | 
				
			||||||
 | 
					    </tal:months>
 | 
				
			||||||
 | 
					  </select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Year</tal:comment>
 | 
				
			||||||
 | 
					  <select tal:attributes="name string:${name}_year;
 | 
				
			||||||
 | 
					                          id   string:${name}_year;">
 | 
				
			||||||
 | 
					    <option value="">-</option>
 | 
				
			||||||
 | 
					    <option tal:repeat="year years"
 | 
				
			||||||
 | 
					            tal:attributes="value year;
 | 
				
			||||||
 | 
					                            selected python:contextObj.dateValueSelected(name, 'year', year)"
 | 
				
			||||||
 | 
					            tal:content="year"></option>
 | 
				
			||||||
 | 
					  </select>
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">The icon for displaying the date chooser</tal:comment>
 | 
				
			||||||
 | 
					  <a tal:attributes="onclick python: 'return showJsCalendar(\'%s_month\', \'%s\', \'%s_year\', \'%s_month\', \'%s_day\', null, null, %d, %d)' % (name, dummyName, name, name, name, years[0], years[-1])"><img tal:attributes="src string: $portal_url/popup_calendar.gif"/></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:hour condition="python: widget['format'] == 0">
 | 
				
			||||||
 | 
					    <select tal:define="hours python:range(0,24);"
 | 
				
			||||||
 | 
					            tal:attributes="name string:${name}_hour;
 | 
				
			||||||
 | 
					                            id   string:${name}_hour;">
 | 
				
			||||||
 | 
					      <option value="">-</option>
 | 
				
			||||||
 | 
					      <tal:hours repeat="hour hours">
 | 
				
			||||||
 | 
					        <option tal:define="zHour python: str(hour).zfill(2)"
 | 
				
			||||||
 | 
					                tal:attributes="value zHour;
 | 
				
			||||||
 | 
					                                selected python:contextObj.dateValueSelected(name, 'hour', hour)"
 | 
				
			||||||
 | 
					                tal:content="zHour"></option>
 | 
				
			||||||
 | 
					      </tal:hours>
 | 
				
			||||||
 | 
					    </select> :
 | 
				
			||||||
 | 
					    <select tal:define="minutes python:range(0,60,5);"
 | 
				
			||||||
 | 
					            tal:attributes="name string:${name}_minute;
 | 
				
			||||||
 | 
					                            id   string:${name}_minute;">
 | 
				
			||||||
 | 
					      <option value="">-</option>
 | 
				
			||||||
 | 
					      <tal:minutes repeat="minute minutes">
 | 
				
			||||||
 | 
					        <option tal:define="zMinute python: str(minute).zfill(2)"
 | 
				
			||||||
 | 
					                tal:attributes="value zMinute;
 | 
				
			||||||
 | 
					                                selected python:contextObj.dateValueSelected(name, 'minute', minute)"
 | 
				
			||||||
 | 
					                tal:content="zMinute"></option>
 | 
				
			||||||
 | 
					      </tal:minutes>
 | 
				
			||||||
 | 
					    </select>
 | 
				
			||||||
 | 
					  </tal:hour>
 | 
				
			||||||
 | 
					</metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for an Date.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/date/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for an Date.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search">
 | 
				
			||||||
 | 
					  <label tal:content="python: tool.translate(widget['labelId'])"></label>
 | 
				
			||||||
 | 
					  <table cellpadding="0" cellspacing="0">
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">From</tal:comment>
 | 
				
			||||||
 | 
					    <tr tal:define="fromName python: '%s*date' % widgetName">
 | 
				
			||||||
 | 
					      <td width="10px"> </td>
 | 
				
			||||||
 | 
					      <td>
 | 
				
			||||||
 | 
					        <label tal:content="python: tool.translate('search_from')"></label>
 | 
				
			||||||
 | 
					      </td>
 | 
				
			||||||
 | 
					      <td>
 | 
				
			||||||
 | 
					        <select tal:attributes="name fromName">
 | 
				
			||||||
 | 
					          <option value="">--</option>
 | 
				
			||||||
 | 
					          <option tal:repeat="value python:range(widget['startYear'], widget['endYear']+1)"
 | 
				
			||||||
 | 
					                  tal:content="value" tal:attributes="value value"></option>
 | 
				
			||||||
 | 
					        </select> /
 | 
				
			||||||
 | 
					        <select tal:attributes="name python: '%s_from_month' % name">
 | 
				
			||||||
 | 
					          <option value="">--</option>
 | 
				
			||||||
 | 
					          <option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 13)]"
 | 
				
			||||||
 | 
					                  tal:content="python:tool.getMonthName(value)" tal:attributes="value value"></option>
 | 
				
			||||||
 | 
					        </select> /
 | 
				
			||||||
 | 
					        <select tal:attributes="name python: '%s_from_day' % name">
 | 
				
			||||||
 | 
					          <option value="">--</option>
 | 
				
			||||||
 | 
					          <option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 32)]"
 | 
				
			||||||
 | 
					                  tal:content="value" tal:attributes="value value"></option>
 | 
				
			||||||
 | 
					        </select>
 | 
				
			||||||
 | 
					      </td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">To</tal:comment>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					      <td></td>
 | 
				
			||||||
 | 
					      <td>
 | 
				
			||||||
 | 
					        <label tal:content="python: tool.translate('search_to')"></label>
 | 
				
			||||||
 | 
					      </td>
 | 
				
			||||||
 | 
					      <td>
 | 
				
			||||||
 | 
					        <select tal:attributes="name python: '%s_to_year' % name">
 | 
				
			||||||
 | 
					          <option value="">--</option>
 | 
				
			||||||
 | 
					          <option tal:repeat="value python:range(widget['startYear'], widget['endYear']+1)"
 | 
				
			||||||
 | 
					                 tal:content="value" tal:attributes="value value"></option>
 | 
				
			||||||
 | 
					        </select> /
 | 
				
			||||||
 | 
					        <select tal:attributes="name python: '%s_to_month' % name">
 | 
				
			||||||
 | 
					          <option value="">--</option>
 | 
				
			||||||
 | 
					          <option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 13)]"
 | 
				
			||||||
 | 
					                  tal:content="python:tool.getMonthName(value)" tal:attributes="value value"></option>
 | 
				
			||||||
 | 
					        </select> /
 | 
				
			||||||
 | 
					        <select tal:attributes="name python: '%s_to_day' % name">
 | 
				
			||||||
 | 
					          <option value="">--</option>
 | 
				
			||||||
 | 
					          <option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 32)]"
 | 
				
			||||||
 | 
					                  tal:content="value" tal:attributes="value value"></option>
 | 
				
			||||||
 | 
					        </select>
 | 
				
			||||||
 | 
					      </td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					  </table>
 | 
				
			||||||
 | 
					</metal:search>
 | 
				
			||||||
							
								
								
									
										73
									
								
								gen/plone25/skin/widgets/file.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,73 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for a File.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view"
 | 
				
			||||||
 | 
					            tal:define="empty python: not value or not value.size;
 | 
				
			||||||
 | 
					                        imageSrc string:${contextObj/absolute_url}/download?name=$name">
 | 
				
			||||||
 | 
					  <tal:file condition="python: not empty and not widget['isImage']">
 | 
				
			||||||
 | 
					    <img tal:define="icon value/getBestIcon"
 | 
				
			||||||
 | 
					         tal:condition="icon" tal:attributes="src string: $portal_url/$icon"/>
 | 
				
			||||||
 | 
					    <a tal:attributes="href imageSrc"
 | 
				
			||||||
 | 
					       tal:content="value/filename">
 | 
				
			||||||
 | 
					    </a>  -
 | 
				
			||||||
 | 
					    <i class="discreet" tal:content="python:'%sKb' % (value.size / 1024)"></i>
 | 
				
			||||||
 | 
					  </tal:file>
 | 
				
			||||||
 | 
					  <tal:image condition="python: not empty and widget['isImage']">
 | 
				
			||||||
 | 
					    <img tal:attributes="src python: imageSrc" />
 | 
				
			||||||
 | 
					  </tal:image>
 | 
				
			||||||
 | 
					  <tal:nothing tal:condition="empty">-</tal:nothing>
 | 
				
			||||||
 | 
					</metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for an File.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit">
 | 
				
			||||||
 | 
					<tal:showFile condition="python: value and value.size">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/file/macros/view"/><br/>
 | 
				
			||||||
 | 
					</tal:showFile>
 | 
				
			||||||
 | 
					<tal:editButtons condition="python: value and value.size">
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Keep the file untouched.</tal:comment>
 | 
				
			||||||
 | 
					  <input class="noborder" type="radio" value="nochange"
 | 
				
			||||||
 | 
					         tal:attributes="checked python:test(value.size!=0, 'checked', None);
 | 
				
			||||||
 | 
					                         name string:${name}_delete;
 | 
				
			||||||
 | 
					                         id string:${name}_nochange;
 | 
				
			||||||
 | 
					                         onclick string:document.getElementById('${name}_file').disabled=true;"/>
 | 
				
			||||||
 | 
					  <label tal:attributes="for string:${name}_nochange"
 | 
				
			||||||
 | 
					         i18n:translate="nochange_file" i18n:domain="plone">
 | 
				
			||||||
 | 
					  </label>
 | 
				
			||||||
 | 
					  <br/>
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Delete the file.</tal:comment>
 | 
				
			||||||
 | 
					  <tal:delete condition="not: widget/required">
 | 
				
			||||||
 | 
					  <input class="noborder" type="radio" value="delete"
 | 
				
			||||||
 | 
					         tal:attributes="name string:${name}_delete;
 | 
				
			||||||
 | 
					                         id string:${name}_delete;
 | 
				
			||||||
 | 
					                         onclick string:document.getElementById('${name}_file').disabled=true;"/>
 | 
				
			||||||
 | 
					  <label tal:attributes="for string:${name}_delete"
 | 
				
			||||||
 | 
					         i18n:translate="delete_file" i18n:domain="plone">
 | 
				
			||||||
 | 
					  </label>
 | 
				
			||||||
 | 
					  <br/>
 | 
				
			||||||
 | 
					  </tal:delete>
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Replace with a new file.</tal:comment>
 | 
				
			||||||
 | 
					  <input class="noborder" type="radio" value=""
 | 
				
			||||||
 | 
					         tal:attributes="checked python:test(value.size==0, 'checked', None);
 | 
				
			||||||
 | 
					                         name string:${name}_delete;
 | 
				
			||||||
 | 
					                         id string:${name}_upload;
 | 
				
			||||||
 | 
					                         onclick string:document.getElementById('${name}_file').disabled=false"/>
 | 
				
			||||||
 | 
					  <label tal:attributes="for string:${name}_upload;"
 | 
				
			||||||
 | 
					         i18n:translate="upload_file" i18n:domain="plone">
 | 
				
			||||||
 | 
					  </label>
 | 
				
			||||||
 | 
					  <br/>
 | 
				
			||||||
 | 
					</tal:editButtons>
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">The upload field.</tal:comment>
 | 
				
			||||||
 | 
					<input type="file" size="30"
 | 
				
			||||||
 | 
					       tal:attributes="name string:${name}_file;
 | 
				
			||||||
 | 
					                       id string:${name}_file;"/>
 | 
				
			||||||
 | 
					<script type="text/javascript" 
 | 
				
			||||||
 | 
					        tal:define="isDisabled python:test(value and value.size, 'true', 'false')"
 | 
				
			||||||
 | 
					        tal:content="string: document.getElementById('${name}_file').disabled=$isDisabled;">
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					</metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for an File.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/file/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for an File.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search"></metal:search>
 | 
				
			||||||
							
								
								
									
										29
									
								
								gen/plone25/skin/widgets/float.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for a Float.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view">
 | 
				
			||||||
 | 
					  <span tal:content="value"
 | 
				
			||||||
 | 
					        tal:attributes="id value; class widget/master_css"></span>
 | 
				
			||||||
 | 
					</metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for an Float.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit">
 | 
				
			||||||
 | 
					  <input tal:attributes="id name; name name; size widget/width;
 | 
				
			||||||
 | 
					                         value python: test(inRequest, requestValue, value)" type="text"/>
 | 
				
			||||||
 | 
					</metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for an Float.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/float/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for an Float.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search">
 | 
				
			||||||
 | 
					  <label tal:content="python: tool.translate(widget['labelId'])"></label><br>  
 | 
				
			||||||
 | 
					  <tal:from define="fromName python: '%s*float' % widgetName">
 | 
				
			||||||
 | 
					    <label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
 | 
				
			||||||
 | 
					    <input type="text" tal:attributes="name fromName" size="4"/>
 | 
				
			||||||
 | 
					  </tal:from>
 | 
				
			||||||
 | 
					  <tal:to define="toName python: '%s_to' % name">
 | 
				
			||||||
 | 
					    <label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
 | 
				
			||||||
 | 
					    <input type="text" tal:attributes="name toName" size="4"/>
 | 
				
			||||||
 | 
					  </tal:to><br/>
 | 
				
			||||||
 | 
					</metal:search>
 | 
				
			||||||
							
								
								
									
										11
									
								
								gen/plone25/skin/widgets/info.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for an Info.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view"><tal:comment replace="nothing">Shows nothing more.</tal:comment></metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for an Info.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit"></metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for an Info.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell"></metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for an Info.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search"></metal:search>
 | 
				
			||||||
							
								
								
									
										28
									
								
								gen/plone25/skin/widgets/integer.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for an Integer.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view">
 | 
				
			||||||
 | 
					  <span tal:content="value" tal:attributes="id value; class widget/master_css"></span>
 | 
				
			||||||
 | 
					</metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for an Integer.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit">
 | 
				
			||||||
 | 
					  <input tal:attributes="id name; name name; size widget/width;
 | 
				
			||||||
 | 
					                         value python: test(inRequest, requestValue, value)" type="text"/>
 | 
				
			||||||
 | 
					</metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for an Integer.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/integer/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for an Integer.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search">
 | 
				
			||||||
 | 
					  <label tal:content="python: tool.translate(widget['labelId'])"></label><br>  
 | 
				
			||||||
 | 
					  <tal:from define="fromName python: '%s*int' % widgetName">
 | 
				
			||||||
 | 
					    <label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
 | 
				
			||||||
 | 
					    <input type="text" tal:attributes="name fromName" size="4"/>
 | 
				
			||||||
 | 
					  </tal:from>
 | 
				
			||||||
 | 
					  <tal:to define="toName python: '%s_to' % name">
 | 
				
			||||||
 | 
					    <label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
 | 
				
			||||||
 | 
					    <input type="text" tal:attributes="name toName" size="4"/>
 | 
				
			||||||
 | 
					  </tal:to><br/>
 | 
				
			||||||
 | 
					</metal:search>
 | 
				
			||||||
							
								
								
									
										26
									
								
								gen/plone25/skin/widgets/pod.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for a Pod.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view">
 | 
				
			||||||
 | 
					  <tal:askAction condition="widget/askAction"
 | 
				
			||||||
 | 
					                 define="doLabel   python:'%s_askaction' % widget['labelId'];
 | 
				
			||||||
 | 
					                         chekboxId python: '%s_%s' % (contextObj.UID(), name)">
 | 
				
			||||||
 | 
					    <input type="checkbox" tal:attributes="name doLabel; id chekboxId"/>
 | 
				
			||||||
 | 
					    <label tal:attributes="for chekboxId" class="discreet"
 | 
				
			||||||
 | 
					           tal:content="python: tool.translate(doLabel)"></label>
 | 
				
			||||||
 | 
					  </tal:askAction>
 | 
				
			||||||
 | 
					  <img tal:repeat="podFormat python:flavour.getPodInfo(contextObj, name)['formats']"
 | 
				
			||||||
 | 
					       tal:attributes="src string: $portal_url/skyn/${podFormat}.png;
 | 
				
			||||||
 | 
					                       onClick python: 'javascript:generatePodDocument(\'%s\',\'\',\'%s\',\'%s\')' % (contextObj.UID(), name, podFormat);
 | 
				
			||||||
 | 
					                       title podFormat/capitalize"
 | 
				
			||||||
 | 
					       style="cursor:pointer"/>
 | 
				
			||||||
 | 
					</metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for a Pod.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit"></metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for a Pod.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/pod/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for a Pod.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search"></metal:search>
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
<tal:comment replace="nothing"> We begin with some sub-macros used within
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
  macro "showReference" defined below.</tal:comment>
 | 
					  We begin with some sub-macros used within macro "show" defined below.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<metal:objectTitle define-macro="objectTitle">
 | 
					<metal:objectTitle define-macro="objectTitle">
 | 
				
			||||||
  <tal:comment replace="nothing">Displays the title of a referenced object, with a link on
 | 
					  <tal:comment replace="nothing">Displays the title of a referenced object, with a link on
 | 
				
			||||||
| 
						 | 
					@ -9,7 +10,7 @@
 | 
				
			||||||
    from one object to the next/previous on skyn/view.</tal:comment>
 | 
					    from one object to the next/previous on skyn/view.</tal:comment>
 | 
				
			||||||
  <a tal:define="viewUrl obj/getUrl;
 | 
					  <a tal:define="viewUrl obj/getUrl;
 | 
				
			||||||
                 navInfo python:'nav=ref.%s.%s.%d.%d' % (contextObj.UID(), fieldName, repeat['obj'].number()+startNumber, totalNumber);
 | 
					                 navInfo python:'nav=ref.%s.%s.%d.%d' % (contextObj.UID(), fieldName, repeat['obj'].number()+startNumber, totalNumber);
 | 
				
			||||||
                 fullUrl python: test(isBack, viewUrl + '/?pageName=%s&phase=%s' % (appyType['page'], appyType['phase']), viewUrl + '/?' + navInfo)"
 | 
					                 fullUrl python: test(appyType['isBack'], viewUrl + '/?page=%s' % appyType['page'], viewUrl + '/?' + navInfo)"
 | 
				
			||||||
     tal:attributes="href fullUrl" tal:content="obj/Title"></a>
 | 
					     tal:attributes="href fullUrl" tal:content="obj/Title"></a>
 | 
				
			||||||
</metal:objectTitle>
 | 
					</metal:objectTitle>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,42 +78,28 @@
 | 
				
			||||||
                       onClick python: ajaxBaseCall.replace('**v**', 'True')"/>
 | 
					                       onClick python: ajaxBaseCall.replace('**v**', 'True')"/>
 | 
				
			||||||
</metal:sortIcons>
 | 
					</metal:sortIcons>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<tal:comment replace="nothing">
 | 
					<tal:comment replace="nothing">View macro for a Ref.</tal:comment>
 | 
				
			||||||
  This macro shows a reference field. More precisely, it shows nothing, but calls
 | 
					<div metal:define-macro="view"
 | 
				
			||||||
  a Javascript function that will asynchonously call (via a XmlHttpRequest object) the
 | 
					     tal:define= "innerRef   innerRef|python:False;
 | 
				
			||||||
  macro 'showReferenceContent' defined below, that will really show content.
 | 
					                  ajaxHookId python: contextObj.UID() + name"
 | 
				
			||||||
  It requires:
 | 
					     tal:attributes = "id ajaxHookId">
 | 
				
			||||||
   - isBack (bool) Is the reference a backward or forward reference?
 | 
					 | 
				
			||||||
   - fieldName (string) The name of the reference field (if it is a forward reference)
 | 
					 | 
				
			||||||
                        or the name of the Archetypes relationship (if it is a backward reference)
 | 
					 | 
				
			||||||
   - innerRef (bool) Are we rendering a reference within a reference or not?
 | 
					 | 
				
			||||||
   - contextObj (object) the object from which the reference starts
 | 
					 | 
				
			||||||
   - labelId (string) the i18n id of the reference field label
 | 
					 | 
				
			||||||
   - descrId (string) the i18n id of the reference field description
 | 
					 | 
				
			||||||
</tal:comment>
 | 
					 | 
				
			||||||
<div metal:define-macro="showReference"
 | 
					 | 
				
			||||||
     tal:define="ajaxHookId   python: contextObj.UID() + fieldName"
 | 
					 | 
				
			||||||
     tal:attributes="id ajaxHookId">
 | 
					 | 
				
			||||||
  <script language="javascript"
 | 
					  <script language="javascript"
 | 
				
			||||||
          tal:content="python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',0)' % (ajaxHookId, contextObj.absolute_url(), fieldName, isBack, innerRef, labelId, descrId)">
 | 
					          tal:content="python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',0)' % (ajaxHookId, contextObj.absolute_url(), name, innerRef)">
 | 
				
			||||||
  </script>
 | 
					  </script>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<tal:comment replace="nothing">
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
   This macro is called by a XmlHttpRequest for displaying the paginated referred objects
 | 
					   This macro is called by a XmlHttpRequest for displaying the paginated
 | 
				
			||||||
   of a reference field.
 | 
					   referred objects of a reference field.
 | 
				
			||||||
</tal:comment>
 | 
					</tal:comment>
 | 
				
			||||||
<div metal:define-macro="showReferenceContent"
 | 
					<div metal:define-macro="viewContent"
 | 
				
			||||||
     tal:define="fieldName request/fieldName;
 | 
					     tal:define="fieldName request/fieldName;
 | 
				
			||||||
                 isBack python: test(request['isBack']=='True', True, False);
 | 
					                 appyType python: contextObj.getAppyType(fieldName, asDict=True);
 | 
				
			||||||
                 innerRef python: test(request['innerRef']=='True', True, False);
 | 
					                 innerRef python: test(request['innerRef']=='True', True, False);
 | 
				
			||||||
                 labelId request/labelId;
 | 
					 | 
				
			||||||
                 descrId request/descrId;
 | 
					 | 
				
			||||||
                 ajaxHookId python: contextObj.UID()+fieldName;
 | 
					                 ajaxHookId python: contextObj.UID()+fieldName;
 | 
				
			||||||
                 startNumber python: int(request.get('%s_startNumber' % ajaxHookId, 0));
 | 
					                 startNumber python: int(request.get('%s_startNumber' % ajaxHookId, 0));
 | 
				
			||||||
                 appyType python: contextObj.getAppyType(fieldName, not isBack);
 | 
					 | 
				
			||||||
                 tool contextObj/getTool;
 | 
					                 tool contextObj/getTool;
 | 
				
			||||||
                 refObjects python:contextObj.getAppyRefs(fieldName, not isBack, startNumber);
 | 
					                 refObjects python:contextObj.getAppyRefs(appyType, startNumber);
 | 
				
			||||||
                 objs refObjects/objects;
 | 
					                 objs refObjects/objects;
 | 
				
			||||||
                 totalNumber refObjects/totalNumber;
 | 
					                 totalNumber refObjects/totalNumber;
 | 
				
			||||||
                 batchSize refObjects/batchSize;
 | 
					                 batchSize refObjects/batchSize;
 | 
				
			||||||
| 
						 | 
					@ -120,14 +107,14 @@
 | 
				
			||||||
                 flavour python:tool.getFlavour(contextObj);
 | 
					                 flavour python:tool.getFlavour(contextObj);
 | 
				
			||||||
                 linkedPortalType python:flavour.getPortalType(appyType['klass']);
 | 
					                 linkedPortalType python:flavour.getPortalType(appyType['klass']);
 | 
				
			||||||
                 addPermission python: '%s: Add %s' % (tool.getAppName(), linkedPortalType);
 | 
					                 addPermission python: '%s: Add %s' % (tool.getAppName(), linkedPortalType);
 | 
				
			||||||
                 canWrite python: not isBack and member.has_permission(contextObj.getField(fieldName).write_permission, contextObj);
 | 
					                 canWrite python: not appyType['isBack'] and member.has_permission(appyType['writePermission'], contextObj);
 | 
				
			||||||
                 multiplicity python:test(isBack, appyType['backd']['multiplicity'], appyType['multiplicity']);
 | 
					                 multiplicity appyType/multiplicity;
 | 
				
			||||||
                 maxReached python:(multiplicity[1] != None) and (len(objs) >= multiplicity[1]);
 | 
					                 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) and canWrite;
 | 
					                 showPlusIcon python:not appyType['isBack'] and appyType['add'] and not maxReached and member.has_permission(addPermission, folder) and canWrite;
 | 
				
			||||||
                 atMostOneRef python: (multiplicity[1] == 1) and (len(objs)<=1);
 | 
					                 atMostOneRef python: (multiplicity[1] == 1) and (len(objs)<=1);
 | 
				
			||||||
                 label python: tool.translate(labelId);
 | 
					                 label python: tool.translate(appyType['labelId']);
 | 
				
			||||||
                 description python: tool.translate(descrId);
 | 
					                 description python: tool.translate(appyType['descrId']);
 | 
				
			||||||
                 navBaseCall python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, contextObj.absolute_url(), fieldName, isBack, innerRef, labelId, descrId)">
 | 
					                 navBaseCall python: 'askRefField(\'%s\',\'%s\',\'%s\',\'%s\',**v**)' % (ajaxHookId, contextObj.absolute_url(), fieldName, innerRef)">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <tal:comment replace="nothing">This macro displays the Reference widget on a "consult" page.
 | 
					  <tal:comment replace="nothing">This macro displays the Reference widget on a "consult" page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -139,20 +126,20 @@
 | 
				
			||||||
    <tal:comment replace="nothing">Display a simplified widget if maximum number of
 | 
					    <tal:comment replace="nothing">Display a simplified widget if maximum number of
 | 
				
			||||||
      referenced objects is 1.</tal:comment>
 | 
					      referenced objects is 1.</tal:comment>
 | 
				
			||||||
    <table class="no-style-table" cellpadding="0" cellspacing="0"><tr valign="top">
 | 
					    <table class="no-style-table" cellpadding="0" cellspacing="0"><tr valign="top">
 | 
				
			||||||
      <td><span class="appyLabel" tal:condition="not: innerRef" tal:content="label"></span></td>
 | 
					      <td><span class="appyLabel" tal:condition="not: innerRef" tal:content="structure label"></span></td>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <tal:comment replace="nothing">If there is no object...</tal:comment>
 | 
					      <tal:comment replace="nothing">If there is no object...</tal:comment>
 | 
				
			||||||
      <tal:noObject condition="not:objs">
 | 
					      <tal:noObject condition="not:objs">
 | 
				
			||||||
        <td tal:content="python: tool.translate('no_ref')"></td>
 | 
					        <td tal:content="python: tool.translate('no_ref')"></td>
 | 
				
			||||||
        <td><metal:plusIcon use-macro="here/skyn/ref/macros/plusIcon"/></td>
 | 
					        <td><metal:plusIcon use-macro="portal/skyn/widgets/ref/macros/plusIcon"/></td>
 | 
				
			||||||
      </tal:noObject>
 | 
					      </tal:noObject>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <tal:comment replace="nothing">If there is an object...</tal:comment>
 | 
					      <tal:comment replace="nothing">If there is an object...</tal:comment>
 | 
				
			||||||
      <tal:objectIsPresent condition="python: len(objs) == 1">
 | 
					      <tal:objectIsPresent condition="python: len(objs) == 1">
 | 
				
			||||||
        <tal:obj repeat="obj objs">
 | 
					        <tal:obj repeat="obj objs">
 | 
				
			||||||
          <td><metal:showObjectTitle use-macro="here/skyn/ref/macros/objectTitle" /></td>
 | 
					          <td><metal:showObjectTitle use-macro="portal/skyn/widgets/ref/macros/objectTitle" /></td>
 | 
				
			||||||
          <td tal:condition="not: isBack">
 | 
					          <td tal:condition="not: appyType/isBack">
 | 
				
			||||||
            <metal:showObjectActions use-macro="here/skyn/ref/macros/objectActions" />
 | 
					            <metal:showObjectActions use-macro="portal/skyn/widgets/ref/macros/objectActions" />
 | 
				
			||||||
          </td>
 | 
					          </td>
 | 
				
			||||||
        </tal:obj>
 | 
					        </tal:obj>
 | 
				
			||||||
      </tal:objectIsPresent>
 | 
					      </tal:objectIsPresent>
 | 
				
			||||||
| 
						 | 
					@ -165,12 +152,12 @@
 | 
				
			||||||
      <legend tal:condition="python: not innerRef or showPlusIcon">
 | 
					      <legend tal:condition="python: not innerRef or showPlusIcon">
 | 
				
			||||||
        <span tal:condition="not: innerRef" tal:content="label"/>
 | 
					        <span tal:condition="not: innerRef" tal:content="label"/>
 | 
				
			||||||
        (<span tal:replace="totalNumber"/>)
 | 
					        (<span tal:replace="totalNumber"/>)
 | 
				
			||||||
        <metal:plusIcon use-macro="here/skyn/ref/macros/plusIcon"/>
 | 
					        <metal:plusIcon use-macro="portal/skyn/widgets/ref/macros/plusIcon"/>
 | 
				
			||||||
      </legend>
 | 
					      </legend>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <tal:comment replace="nothing">Object description</tal:comment>
 | 
					      <tal:comment replace="nothing">Object description</tal:comment>
 | 
				
			||||||
      <p tal:condition="python: not innerRef and description.strip()"
 | 
					      <!--p tal:condition="python: not innerRef and description.strip()"
 | 
				
			||||||
         tal:content="description" class="discreet" ></p>
 | 
					         tal:content="description" class="discreet" ></p-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <tal:comment replace="nothing">Appy (top) navigation</tal:comment>
 | 
					      <tal:comment replace="nothing">Appy (top) navigation</tal:comment>
 | 
				
			||||||
      <metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
 | 
					      <metal:nav use-macro="here/skyn/navigate/macros/appyNavigate"/>
 | 
				
			||||||
| 
						 | 
					@ -184,35 +171,29 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <tal:comment replace="nothing">Show backward reference(s)</tal:comment>
 | 
					        <tal:comment replace="nothing">Show backward reference(s)</tal:comment>
 | 
				
			||||||
        <table class="no-style-table" cellspacing="0" cellpadding="0"
 | 
					        <table class="no-style-table" cellspacing="0" cellpadding="0"
 | 
				
			||||||
               tal:condition="python: isBack and objs">
 | 
					               tal:condition="python: appyType['isBack'] and objs">
 | 
				
			||||||
          <tr tal:repeat="obj objs">
 | 
					          <tr tal:repeat="obj objs">
 | 
				
			||||||
            <td><metal:showObjectTitle use-macro="here/skyn/ref/macros/objectTitle" />
 | 
					            <td><metal:showObjectTitle use-macro="portal/skyn/widgets/ref/macros/objectTitle" />
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
          </tr>
 | 
					          </tr>
 | 
				
			||||||
        </table>
 | 
					        </table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <tal:comment replace="nothing">Show forward reference(s)</tal:comment>
 | 
					        <tal:comment replace="nothing">Show forward reference(s)</tal:comment>
 | 
				
			||||||
        <table tal:attributes="class python:test(innerRef, '', 'listing nosort');
 | 
					        <table tal:attributes="class python:test(innerRef, '', 'listing nosort');
 | 
				
			||||||
                               width python:test(innerRef, '100%', test(appyType['wide'], '100%', ''))"
 | 
					                               width python:test(innerRef, '100%', appyType['layouts']['view']['width']);"
 | 
				
			||||||
               align="right" tal:condition="python: not isBack and objs" cellpadding="0" cellspacing="0">
 | 
					               align="right" tal:condition="python: not appyType['isBack'] and objs" cellpadding="0" cellspacing="0">
 | 
				
			||||||
 | 
					          <tal:widgets define="widgets python: objs[0].getAppyTypesFromNames(appyType['shownInfo'])">
 | 
				
			||||||
          <tr tal:condition="appyType/showHeaders">
 | 
					          <tr tal:condition="appyType/showHeaders">
 | 
				
			||||||
            <th tal:condition="python: 'title' not in appyType['shownInfo']"
 | 
					            <th tal:condition="python: 'title' not in appyType['shownInfo']"
 | 
				
			||||||
                tal:define="shownField python:'title'">
 | 
					                tal:define="shownField python:'title'">
 | 
				
			||||||
              <span tal:content="python: tool.translate('ref_name')"></span>
 | 
					              <span tal:content="python: tool.translate('ref_name')"></span>
 | 
				
			||||||
              <metal:sortIcons use-macro="here/skyn/ref/macros/sortIcons" />
 | 
					              <metal:sortIcons use-macro="portal/skyn/widgets/ref/macros/sortIcons" />
 | 
				
			||||||
            </th>
 | 
					            </th>
 | 
				
			||||||
            <th tal:repeat="shownField appyType/shownInfo">
 | 
					            <th tal:repeat="widget widgets">
 | 
				
			||||||
              <tal:showHeader condition="python: objs[0].getField(shownField)">
 | 
					              <tal:header define="shownField widget/name">
 | 
				
			||||||
                <tal:titleHeader condition="python: shownField == 'title'">
 | 
					                <span tal:content="python: tool.translate(widget['labelId'])"></span>
 | 
				
			||||||
                  <span tal:content="python: tool.translate('ref_name')"></span>
 | 
					                <metal:sortIcons use-macro="portal/skyn/widgets/ref/macros/sortIcons" />
 | 
				
			||||||
                  <metal:sortIcons use-macro="here/skyn/ref/macros/sortIcons" />
 | 
					              </tal:header>
 | 
				
			||||||
                </tal:titleHeader>
 | 
					 | 
				
			||||||
                <tal:otherHeader condition="python: shownField != 'title'"
 | 
					 | 
				
			||||||
                                 define="labelId python: objs[0].getField(shownField).widget.label_msgid">
 | 
					 | 
				
			||||||
                  <span tal:content="python: tool.translate(labelId)"></span>
 | 
					 | 
				
			||||||
                  <metal:sortIcons use-macro="here/skyn/ref/macros/sortIcons" />
 | 
					 | 
				
			||||||
                </tal:otherHeader>
 | 
					 | 
				
			||||||
              </tal:showHeader>
 | 
					 | 
				
			||||||
            </th>
 | 
					            </th>
 | 
				
			||||||
            <th tal:content="python: tool.translate('ref_actions')"></th>
 | 
					            <th tal:content="python: tool.translate('ref_actions')"></th>
 | 
				
			||||||
          </tr>
 | 
					          </tr>
 | 
				
			||||||
| 
						 | 
					@ -222,41 +203,27 @@
 | 
				
			||||||
            <tal:comment replace="nothing">Object title, shown here if not specified somewhere
 | 
					            <tal:comment replace="nothing">Object title, shown here if not specified somewhere
 | 
				
			||||||
              else in appyType.shownInfo.</tal:comment>
 | 
					              else in appyType.shownInfo.</tal:comment>
 | 
				
			||||||
            <td tal:condition="python: 'title' not in appyType['shownInfo']"><metal:showObjectTitle
 | 
					            <td tal:condition="python: 'title' not in appyType['shownInfo']"><metal:showObjectTitle
 | 
				
			||||||
                use-macro="here/skyn/ref/macros/objectTitle"/> 
 | 
					                use-macro="portal/skyn/widgets/ref/macros/objectTitle"/> 
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
            <tal:comment replace="nothing">Additional fields that must be shown</tal:comment>
 | 
					            <tal:comment replace="nothing">Additional fields that must be shown</tal:comment>
 | 
				
			||||||
            <td tal:repeat="shownField appyType/shownInfo">
 | 
					            <td tal:repeat="widget widgets">
 | 
				
			||||||
              <tal:showTitle condition="python: shownField == 'title'">
 | 
					              <tal:showTitle condition="python: widget['name'] == 'title'">
 | 
				
			||||||
                <metal:showObjectTitle use-macro="here/skyn/ref/macros/objectTitle"/>
 | 
					                <metal:showObjectTitle use-macro="portal/skyn/widgets/ref/macros/objectTitle"/>
 | 
				
			||||||
              </tal:showTitle>
 | 
					              </tal:showTitle>
 | 
				
			||||||
              <tal:showOtherField define="appyType python: obj.getAppyType(shownField);
 | 
					              <tal:showOtherField define="contextObj python:obj;
 | 
				
			||||||
                                          field python:obj.getField(shownField);
 | 
					                                          layoutType python: 'cell';
 | 
				
			||||||
                                          contextObj python:obj;"
 | 
					                                          innerRef python:True"
 | 
				
			||||||
                                  condition="python: appyType and (shownField != 'title')">
 | 
					                                  condition="python: widget['name'] != 'title'">
 | 
				
			||||||
                <tal:showNormalField condition="python: appyType['type'] not in ('Ref', 'Computed', 'Action')">
 | 
					                <metal:showField use-macro="portal/skyn/widgets/show/macros/field" />
 | 
				
			||||||
                  <metal:viewField use-macro="python: obj.widget(shownField, 'view', use_label=0)"/>
 | 
					 | 
				
			||||||
                </tal:showNormalField>
 | 
					 | 
				
			||||||
                <tal:showRef condition="python: appyType['type'] == 'Ref'">
 | 
					 | 
				
			||||||
                  <tal:ref tal:define="isBack python:appyType['isBack'];
 | 
					 | 
				
			||||||
                                       fieldName python: test(isBack, field.relationship, field.getName());
 | 
					 | 
				
			||||||
                                       innerRef python:True">
 | 
					 | 
				
			||||||
                    <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/skyn/macros/macros/showActionField" />
 | 
					 | 
				
			||||||
                </tal:showAction>
 | 
					 | 
				
			||||||
              </tal:showOtherField> 
 | 
					              </tal:showOtherField> 
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
            <tal:comment replace="nothing">Actions</tal:comment>
 | 
					            <tal:comment replace="nothing">Actions</tal:comment>
 | 
				
			||||||
            <td align="right">
 | 
					            <td align="right">
 | 
				
			||||||
              <metal:showObjectActions use-macro="here/skyn/ref/macros/objectActions" />
 | 
					              <metal:showObjectActions use-macro="portal/skyn/widgets/ref/macros/objectActions" />
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
          </tr>
 | 
					          </tr>
 | 
				
			||||||
          </tal:row>
 | 
					          </tal:row>
 | 
				
			||||||
 | 
					          </tal:widgets>
 | 
				
			||||||
        </table>
 | 
					        </table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        </td></tr>
 | 
					        </td></tr>
 | 
				
			||||||
| 
						 | 
					@ -272,18 +239,17 @@
 | 
				
			||||||
  </tal:anyNumberOfReferences>
 | 
					  </tal:anyNumberOfReferences>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div metal:define-macro="editReference"
 | 
					<tal:comment replace="nothing">Edit macro for an Ref.</tal:comment>
 | 
				
			||||||
     tal:define="refPortalType python:here.getAppyRefPortalType(field.getName());
 | 
					<div define-macro="edit"
 | 
				
			||||||
                 appyType python:here.getAppyType(field.getName());
 | 
					     tal:condition="widget/link"
 | 
				
			||||||
 | 
					     tal:define="refPortalType python: contextObj.getAppyRefPortalType(name);
 | 
				
			||||||
                 allBrains python:here.uid_catalog(portal_type=refPortalType);
 | 
					                 allBrains python:here.uid_catalog(portal_type=refPortalType);
 | 
				
			||||||
                 brains python:here.callAppySelect(appyType['select'], allBrains);
 | 
					                 brains python:contextObj.callAppySelect(widget['select'], allBrains);
 | 
				
			||||||
                 refUids python: [o.UID() for o in here.getAppyRefs(field.getName())['objects']];
 | 
					                 refUids python: [o.UID() for o in here.getAppyRefs(name)['objects']];
 | 
				
			||||||
                 isMultiple python:test(appyType['multiplicity'][1]!=1, 'multiple', '');
 | 
					                 isMultiple python:test(widget['multiplicity'][1]!=1, 'multiple', '');
 | 
				
			||||||
                 appyFieldName python: 'appy_ref_%s' % field.getName();
 | 
					                 appyFieldName python: 'appy_ref_%s' % name;
 | 
				
			||||||
                 inError python:test(errors.has_key(field.getName()), True, False);
 | 
					                 inError python:test(errors.has_key(name), True, False);
 | 
				
			||||||
                 defaultValue python: contextObj.getDefault(field.getName());
 | 
					                 isBeingCreated python: contextObj.isTemporary() or ('/portal_factory/' in contextObj.absolute_url())"
 | 
				
			||||||
                 defaultValueUID defaultValue/UID|nothing;
 | 
					 | 
				
			||||||
                 isBeingCreated python: contextObj.portal_factory.isTemporary(contextObj) or ('/portal_factory/' in contextObj.absolute_url())"
 | 
					 | 
				
			||||||
     tal:attributes="class python:'appyRefEdit field' + test(inError, ' error', '')">
 | 
					     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>
 | 
					  <tal:comment replace="nothing">This macro displays the Reference widget on an "edit" page</tal:comment>
 | 
				
			||||||
| 
						 | 
					@ -301,3 +267,11 @@
 | 
				
			||||||
                        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)"/>
 | 
					                        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>
 | 
					  </select>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for a Ref.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/ref/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for a Ref.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search"></metal:search>
 | 
				
			||||||
							
								
								
									
										203
									
								
								gen/plone25/skin/widgets/show.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,203 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro shows the content of a layouted object, like a page or widget.
 | 
				
			||||||
 | 
					  It requires:
 | 
				
			||||||
 | 
					    contextObj         The Zope object on which we are working
 | 
				
			||||||
 | 
					    layoutType         The kind of layout: "view"? "edit"? "cell"?
 | 
				
			||||||
 | 
					    layout             The layout object that will dictate how object content
 | 
				
			||||||
 | 
					                       will be rendered.
 | 
				
			||||||
 | 
					  Options:
 | 
				
			||||||
 | 
					    contextMacro       The base on folder containing the macros to call for
 | 
				
			||||||
 | 
					                       rendering the elements within the layout.
 | 
				
			||||||
 | 
					                       Defaults to portal.skyn
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:show define-macro="layout"
 | 
				
			||||||
 | 
					            tal:define="contextMacro contextMacro| python: portal.skyn">
 | 
				
			||||||
 | 
					 <table tal:attributes="cellpadding  layout/cellpadding;
 | 
				
			||||||
 | 
					                        cellspacing  layout/cellspacing;
 | 
				
			||||||
 | 
					                        width        layout/width;
 | 
				
			||||||
 | 
					                        align        layout/align;
 | 
				
			||||||
 | 
					                        class        layout/css_class;
 | 
				
			||||||
 | 
					                        style        layout/style">
 | 
				
			||||||
 | 
					   <tal:comment replace="nothing">The table header row</tal:comment>
 | 
				
			||||||
 | 
					   <tr tal:condition="layout/headerRow" tal:attributes="valign layout/headerRow/valign">
 | 
				
			||||||
 | 
					     <th tal:repeat="cell layout/headerRow/cells"
 | 
				
			||||||
 | 
					         tal:attributes="align cell/align; width cell/width;">
 | 
				
			||||||
 | 
					     </th>
 | 
				
			||||||
 | 
					   </tr>
 | 
				
			||||||
 | 
					   <tal:comment replace="nothing">The table content</tal:comment>
 | 
				
			||||||
 | 
					   <tr tal:repeat="row layout/rows" tal:attributes="valign row/valign">
 | 
				
			||||||
 | 
					     <td tal:repeat="cell row/cells"
 | 
				
			||||||
 | 
					         tal:attributes="align cell/align; colspan cell/colspan;
 | 
				
			||||||
 | 
					                         style python: test(repeat['cell'].end, '', 'padding-right: 0.4em')">
 | 
				
			||||||
 | 
					       <tal:content repeat="elem cell/content">
 | 
				
			||||||
 | 
					         <tal:field condition="python: elem == '?'">
 | 
				
			||||||
 | 
					           <metal:call use-macro="python: contextMacro.get(widget['type'].lower()).macros.get(layoutType)"/>
 | 
				
			||||||
 | 
					         </tal:field>
 | 
				
			||||||
 | 
					         <tal:other condition="python: elem != '?'">
 | 
				
			||||||
 | 
					           <metal:call use-macro="python: contextMacro.get(elem[0]).macros.get(elem[1])"/>
 | 
				
			||||||
 | 
					         </tal:other>
 | 
				
			||||||
 | 
					         <img tal:condition="not: repeat/elem/end" tal:attributes="src string: $portal_url/skyn/space.gif"/>
 | 
				
			||||||
 | 
					       </tal:content>
 | 
				
			||||||
 | 
					     </td>
 | 
				
			||||||
 | 
					   </tr>
 | 
				
			||||||
 | 
					 </table>
 | 
				
			||||||
 | 
					</metal:show>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro displays the widget corresponding to a given field. It requires:
 | 
				
			||||||
 | 
					    contextObj         The Zope object for which this widget must be rendered
 | 
				
			||||||
 | 
					    page               The page where the widget lies
 | 
				
			||||||
 | 
					    layoutType         "edit"? "view"? "cell?"
 | 
				
			||||||
 | 
					    widget             The widget to render
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:field define-macro="field"
 | 
				
			||||||
 | 
					       tal:define="contextMacro    python: portal.skyn.widgets;
 | 
				
			||||||
 | 
					                   layout          python: widget['layouts'][layoutType];
 | 
				
			||||||
 | 
					                   name            widget/name;
 | 
				
			||||||
 | 
					                   value           python: contextObj.getFormattedValue(name);
 | 
				
			||||||
 | 
					                   requestValue    python: request.get(name, None);
 | 
				
			||||||
 | 
					                   inRequest       python: request.has_key(name);
 | 
				
			||||||
 | 
					                   errors          errors | python: ();
 | 
				
			||||||
 | 
					                   inError         python: test(widget['name'] in errors, True, False)">
 | 
				
			||||||
 | 
					  <metal:layout use-macro="here/skyn/widgets/show/macros/layout"/>
 | 
				
			||||||
 | 
					</metal:field>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro displays the widget corresponding to a group of widgets.
 | 
				
			||||||
 | 
					  It requires:
 | 
				
			||||||
 | 
					    contextObj         The Zope object for which this widget must be rendered
 | 
				
			||||||
 | 
					    page               The page where the widget lies
 | 
				
			||||||
 | 
					    layoutType         "edit"? "view"? "cell?"
 | 
				
			||||||
 | 
					    widget             The widget to render
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<metal:group define-macro="group">
 | 
				
			||||||
 | 
					  <fieldset tal:condition="python: widget['style'] == 'fieldset'">
 | 
				
			||||||
 | 
					    <legend tal:condition="widget/hasLabel">
 | 
				
			||||||
 | 
					      <i tal:content="structure python: contextObj.translate(widget['labelId'])"></i>
 | 
				
			||||||
 | 
					      <tal:help condition="widget/hasHelp">
 | 
				
			||||||
 | 
					        <metal:call use-macro="portal/skyn/widgets/show/macros/help"/>
 | 
				
			||||||
 | 
					      </tal:help>
 | 
				
			||||||
 | 
					    </legend>
 | 
				
			||||||
 | 
					    <div tal:condition="widget/hasDescr" class="discreet" 
 | 
				
			||||||
 | 
					         tal:content="structure python: contextObj.translate(widget['descrId'])"></div>
 | 
				
			||||||
 | 
					    <metal:content use-macro="portal/skyn/widgets/show/macros/groupContent"/>
 | 
				
			||||||
 | 
					  </fieldset>
 | 
				
			||||||
 | 
					  <tal:asSection condition="python: widget['style'] not in ('fieldset', 'tabs')">
 | 
				
			||||||
 | 
					    <metal:content use-macro="portal/skyn/widgets/show/macros/groupContent"/>
 | 
				
			||||||
 | 
					  </tal:asSection>
 | 
				
			||||||
 | 
					  <tal:asTabs condition="python: widget['style'] == 'tabs'">
 | 
				
			||||||
 | 
					  <table cellpadding="0" cellspacing="0" tal:attributes="width python: test(widget['wide'], '100%', '')">
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">First row: the tabs.</tal:comment>
 | 
				
			||||||
 | 
					    <tr><td style="border-bottom: 1px solid #ff8040">
 | 
				
			||||||
 | 
					      <table cellpadding="0" cellspacing="0" style="position:relative; bottom:-1px;">
 | 
				
			||||||
 | 
					        <tr valign="bottom">
 | 
				
			||||||
 | 
					          <tal:tab repeat="widgetRow widget/widgets">
 | 
				
			||||||
 | 
					          <tal:id define="tabId python:'tab_%s_%d_%d' % (widget['name'], repeat['widgetRow'].number(), len(widget['widgets']))">
 | 
				
			||||||
 | 
					          <td><img tal:attributes="src string: $portal_url/skyn/tabLeft.png;
 | 
				
			||||||
 | 
					                                   id python: '%s_left' % tabId"/><td>
 | 
				
			||||||
 | 
					          <td tal:attributes="style python:'background-image: url(%s/skyn/tabBg.png)' % portal_url;
 | 
				
			||||||
 | 
					                              id tabId">
 | 
				
			||||||
 | 
					            <a style="cursor:pointer"
 | 
				
			||||||
 | 
					               tal:content="python: tool.translate('%s_col%d' % (widget['labelId'], repeat['widgetRow'].number()))"
 | 
				
			||||||
 | 
					               tal:attributes="onClick python: 'javascript:showTab(\'%s_%d_%d\')' % (widget['name'], repeat['widgetRow'].number(), len(widget['widgets']))"></a>
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <td><img tal:attributes="src string: $portal_url/skyn/tabRight.png;
 | 
				
			||||||
 | 
					                                   id python: '%s_right' % tabId"/><td>
 | 
				
			||||||
 | 
					          </tal:id>
 | 
				
			||||||
 | 
					          </tal:tab>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					      </table>
 | 
				
			||||||
 | 
					    </td></tr>
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">Other rows: the widgets.</tal:comment>
 | 
				
			||||||
 | 
					    <tr tal:repeat="widgetRow widget/widgets"
 | 
				
			||||||
 | 
					        tal:attributes="id python: 'tabcontent_%s_%d_%d' % (widget['name'], repeat['widgetRow'].number(), len(widget['widgets']));
 | 
				
			||||||
 | 
					                        style python: test(repeat['widgetRow'].number()==1, 'display:table-row', 'display:none')">
 | 
				
			||||||
 | 
					      <td tal:define="widget python: widgetRow[0]">
 | 
				
			||||||
 | 
					        <tal:group condition="python: widget['type'] == 'group'">
 | 
				
			||||||
 | 
					          <metal:call use-macro="portal/skyn/widgets/show/macros/group"/>
 | 
				
			||||||
 | 
					        </tal:group>
 | 
				
			||||||
 | 
					        <tal:field condition="python: widget['type'] != 'group'">
 | 
				
			||||||
 | 
					          <metal:call use-macro="portal/skyn/widgets/show/macros/field"/>
 | 
				
			||||||
 | 
					        </tal:field>
 | 
				
			||||||
 | 
					      </td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					  </table>
 | 
				
			||||||
 | 
					  <script language="javascript"
 | 
				
			||||||
 | 
					          tal:content="python: 'initTab(\'tab_%s\', \'%s_1_%d\')' % (widget['name'], widget['name'], len(widget['widgets']))"></script>
 | 
				
			||||||
 | 
					  </tal:asTabs>
 | 
				
			||||||
 | 
					</metal:group>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">
 | 
				
			||||||
 | 
					  This macro displays the content of a group of widgets.
 | 
				
			||||||
 | 
					  It is exclusively called by macro "group" above.
 | 
				
			||||||
 | 
					</tal:comment>
 | 
				
			||||||
 | 
					<table metal:define-macro="groupContent" align="center"
 | 
				
			||||||
 | 
					       tal:attributes="width python: test(widget['wide'], '100%', '')">
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Display the title of the group if it is not rendered a fieldset.</tal:comment>
 | 
				
			||||||
 | 
					  <tr tal:condition="python: (widget['style'] != 'fieldset') and widget['hasLabel']">
 | 
				
			||||||
 | 
					    <td tal:attributes="colspan python: len(widget['columnsWidths']);
 | 
				
			||||||
 | 
					                        class widget/style">
 | 
				
			||||||
 | 
					      <span tal:replace="structure python: contextObj.translate(widget['labelId'])"/>
 | 
				
			||||||
 | 
					      <tal:help condition="widget/hasHelp">
 | 
				
			||||||
 | 
					        <metal:call use-macro="portal/skyn/widgets/show/macros/help"/>
 | 
				
			||||||
 | 
					      </tal:help>
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr tal:condition="python: (widget['style'] != 'fieldset') and widget['hasDescr']">
 | 
				
			||||||
 | 
					    <td tal:attributes="colspan python: len(widget['columnsWidths'])" class="discreet"
 | 
				
			||||||
 | 
					        tal:content="structure python: contextObj.translate(widget['descrId'])">
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tr> <tal:comment replace="nothing">The column headers</tal:comment>
 | 
				
			||||||
 | 
					    <th tal:repeat="colNb python:range(len(widget['columnsWidths']))"
 | 
				
			||||||
 | 
					        tal:attributes="width python:widget['columnsWidths'][colNb];
 | 
				
			||||||
 | 
					                        align python:widget['columnsAligns'][colNb]"
 | 
				
			||||||
 | 
					        tal:content="structure python: test(widget['hasHeaders'], contextObj.translate('%s_col%d' % (widget['labelId'], colNb+1)), '')">
 | 
				
			||||||
 | 
					    </th>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">The rows of widgets</tal:comment>
 | 
				
			||||||
 | 
					  <tr valign="top" tal:repeat="widgetRow widget/widgets">
 | 
				
			||||||
 | 
					    <td tal:repeat="widget widgetRow"
 | 
				
			||||||
 | 
					        tal:attributes="colspan widget/colspan|python:1;
 | 
				
			||||||
 | 
					                        style python: test(repeat['widget'].number() != len(widgetRow), 'padding-right: 0.6em', '')">
 | 
				
			||||||
 | 
					      <tal:showWidget condition="widget">
 | 
				
			||||||
 | 
					        <tal:group condition="python: widget['type'] == 'group'">
 | 
				
			||||||
 | 
					          <metal:call use-macro="portal/skyn/widgets/show/macros/group"/>
 | 
				
			||||||
 | 
					        </tal:group>
 | 
				
			||||||
 | 
					        <tal:field condition="python: widget['type'] != 'group'">
 | 
				
			||||||
 | 
					          <metal:call use-macro="portal/skyn/widgets/show/macros/field"/>
 | 
				
			||||||
 | 
					        </tal:field>
 | 
				
			||||||
 | 
					      </tal:showWidget>
 | 
				
			||||||
 | 
					    </td>
 | 
				
			||||||
 | 
					  </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Displays a field label.</tal:comment>
 | 
				
			||||||
 | 
					<tal:label metal:define-macro="label" condition="widget/hasLabel">
 | 
				
			||||||
 | 
					  <label tal:attributes="for widget/name"
 | 
				
			||||||
 | 
					         tal:condition="python: widget['type'] not in ('Action', 'Ref')"
 | 
				
			||||||
 | 
					         tal:content="structure python: contextObj.translate(widget['labelId'])"></label>
 | 
				
			||||||
 | 
					</tal:label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Displays a field description.</tal:comment>
 | 
				
			||||||
 | 
					<tal:description metal:define-macro="description" condition="widget/hasDescr">
 | 
				
			||||||
 | 
					  <span class="discreet" tal:content="structure python: contextObj.translate(widget['descrId'])"></span>
 | 
				
			||||||
 | 
					</tal:description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Displays a field help.</tal:comment>
 | 
				
			||||||
 | 
					<tal:help metal:define-macro="help">
 | 
				
			||||||
 | 
					  <acronym tal:attributes="title python: contextObj.translate(widget['helpId'])">
 | 
				
			||||||
 | 
					    <img tal:attributes="src string: $portal_url/skyn/help.png"/>
 | 
				
			||||||
 | 
					  </acronym>
 | 
				
			||||||
 | 
					</tal:help>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Displays validation-error-related info about a field.</tal:comment>
 | 
				
			||||||
 | 
					<tal:validation metal:define-macro="validation">
 | 
				
			||||||
 | 
					  <acronym tal:condition="inError" tal:attributes="title python: errors[name]">
 | 
				
			||||||
 | 
					    <img tal:attributes="src string: $portal_url/skyn/warning.png"/>
 | 
				
			||||||
 | 
					  </acronym>
 | 
				
			||||||
 | 
					  <img tal:condition="not: inError" tal:attributes="src string: $portal_url/skyn/warning_no.png"/>
 | 
				
			||||||
 | 
					</tal:validation>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Displays the fact that a field is required.</tal:comment>
 | 
				
			||||||
 | 
					<tal:required metal:define-macro="required"><img tal:attributes="src string: $portal_url/skyn/required.png"/></tal:required>
 | 
				
			||||||
							
								
								
									
										102
									
								
								gen/plone25/skin/widgets/string.pt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,102 @@
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">View macro for a String.</tal:comment>
 | 
				
			||||||
 | 
					<metal:view define-macro="view"
 | 
				
			||||||
 | 
					       tal:define="fmt widget/format;
 | 
				
			||||||
 | 
					                   maxMult python: widget['multiplicity'][1];
 | 
				
			||||||
 | 
					                   severalValues python: (maxMult == None) or (maxMult > 1)">
 | 
				
			||||||
 | 
					  <span tal:condition="python: fmt in (0, 3)"
 | 
				
			||||||
 | 
					        tal:attributes="class widget/master_css;
 | 
				
			||||||
 | 
					                        id python: contextObj.getFormattedValue(name, forMasterId=True)">
 | 
				
			||||||
 | 
					    <ul class="appyList" tal:condition="python: value and severalValues">
 | 
				
			||||||
 | 
					      <li class="appyBullet" tal:repeat="sv value"><i tal:content="structure sv"></i></li>
 | 
				
			||||||
 | 
					    </ul>
 | 
				
			||||||
 | 
					    <tal:singleValue condition="python: value and not severalValues">
 | 
				
			||||||
 | 
					      <span tal:condition="python: fmt != 3" tal:replace="structure value"/>
 | 
				
			||||||
 | 
					      <span tal:condition="python: fmt == 3">********</span>
 | 
				
			||||||
 | 
					    </tal:singleValue>
 | 
				
			||||||
 | 
					  </span>
 | 
				
			||||||
 | 
					  <tal:formattedString condition="python: fmt not in (0, 3)">
 | 
				
			||||||
 | 
					    <span tal:condition="python: value and (fmt == 1)"
 | 
				
			||||||
 | 
					          tal:replace="structure python: value.replace('\n', '<br>')"/>
 | 
				
			||||||
 | 
					    <span tal:condition="python: value and (fmt == 2)" tal:replace="structure value"/>
 | 
				
			||||||
 | 
					  </tal:formattedString>
 | 
				
			||||||
 | 
					</metal:view>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Edit macro for a String.</tal:comment>
 | 
				
			||||||
 | 
					<metal:edit define-macro="edit"
 | 
				
			||||||
 | 
					            tal:define="fmt widget/format;
 | 
				
			||||||
 | 
					                        isSelect widget/isSelect;
 | 
				
			||||||
 | 
					                        isMaster widget/slaves;
 | 
				
			||||||
 | 
					                        isOneLine python: fmt in (0,3)">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <tal:choice condition="isSelect">
 | 
				
			||||||
 | 
					  <select tal:define="possibleValues python:contextObj.getPossibleValues(name, withTranslations=True, withBlankValue=True)"
 | 
				
			||||||
 | 
					          tal:attributes="name name;
 | 
				
			||||||
 | 
					                          id name;
 | 
				
			||||||
 | 
					                          multiple python: test(widget['multiplicity'][1] != 1, 'multiple', '');
 | 
				
			||||||
 | 
					                          onchange python: test(isMaster, 'javascript:updateSlaves(getMasterValue(this), \'%s\')' % widget['id'], '');
 | 
				
			||||||
 | 
					                          class    widget/master_css">
 | 
				
			||||||
 | 
					    <option tal:repeat="possibleValue possibleValues"
 | 
				
			||||||
 | 
					            tal:attributes="value python: possibleValue[0];
 | 
				
			||||||
 | 
					                            selected python:contextObj.fieldValueSelected(name, possibleValue[0])"
 | 
				
			||||||
 | 
					            tal:content="python:tool.truncateValue(possibleValue[1], widget)"></option>
 | 
				
			||||||
 | 
					  </select>
 | 
				
			||||||
 | 
					  </tal:choice>
 | 
				
			||||||
 | 
					  <tal:line condition="python: isOneLine and not isSelect">
 | 
				
			||||||
 | 
					    <input tal:attributes="id name; name name; size widget/width;
 | 
				
			||||||
 | 
					                           value python: test(inRequest, requestValue, value)" type="text"/>
 | 
				
			||||||
 | 
					  </tal:line>
 | 
				
			||||||
 | 
					  <tal:textarea condition="python: fmt == 1">
 | 
				
			||||||
 | 
					    <textarea tal:attributes="id name; name name;
 | 
				
			||||||
 | 
					                              cols widget/width;
 | 
				
			||||||
 | 
					                              rows widget/height;"
 | 
				
			||||||
 | 
					              tal:content="python: test(inRequest, requestValue, value)">
 | 
				
			||||||
 | 
					    </textarea>
 | 
				
			||||||
 | 
					    <input type="hidden" value="text/plain" originalvalue="text/plain"
 | 
				
			||||||
 | 
					           tal:attributes="name python: '%s_text_format' % name"/>
 | 
				
			||||||
 | 
					  </tal:textarea>
 | 
				
			||||||
 | 
					  <tal:rich condition="python: fmt == 2">
 | 
				
			||||||
 | 
					    <tal:editor define="editor python: member.getProperty('wysiwyg_editor','').lower();
 | 
				
			||||||
 | 
					                        macrosFile python: path('nocall:here/%s_wysiwyg_support' % editor);
 | 
				
			||||||
 | 
					                        fieldName name;
 | 
				
			||||||
 | 
					                        inputname name;
 | 
				
			||||||
 | 
					                        inputvalue python: test(inRequest, requestValue, value);
 | 
				
			||||||
 | 
					                        dummy python: request.set('%s_text_format' % name, 'text/html')">
 | 
				
			||||||
 | 
					     <metal:box use-macro="macrosFile/macros/wysiwygEditorBox"/>
 | 
				
			||||||
 | 
					    </tal:editor>
 | 
				
			||||||
 | 
					  </tal:rich>
 | 
				
			||||||
 | 
					</metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Cell macro for a String.</tal:comment>
 | 
				
			||||||
 | 
					<metal:cell define-macro="cell">
 | 
				
			||||||
 | 
					  <metal:call use-macro="portal/skyn/widgets/string/macros/view"/>
 | 
				
			||||||
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<tal:comment replace="nothing">Search macro for a String.</tal:comment>
 | 
				
			||||||
 | 
					<metal:search define-macro="search">
 | 
				
			||||||
 | 
					  <label tal:attributes="for widgetName" tal:content="python: tool.translate(widget['labelId'])"></label><br>  
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Show a simple search field for most String fields.</tal:comment>
 | 
				
			||||||
 | 
					  <tal:simpleSearch condition="not: widget/isSelect">
 | 
				
			||||||
 | 
					    <input type="text" tal:attributes="name python: '%s*string-%s' % (widgetName, widget['transform']);
 | 
				
			||||||
 | 
					                                       style python: 'text-transform:%s' % widget['transform']"/>
 | 
				
			||||||
 | 
					  </tal:simpleSearch>
 | 
				
			||||||
 | 
					  <tal:comment replace="nothing">Show a multi-selection box for fields whose
 | 
				
			||||||
 | 
					    validator defines a list of values, with a "AND/OR" checkbox.</tal:comment>
 | 
				
			||||||
 | 
					  <tal:selectSearch condition="widget/isSelect">
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">The "and" / "or" radio buttons</tal:comment>
 | 
				
			||||||
 | 
					    <tal:operator define="operName python: 'o_%s'   % fieldName;
 | 
				
			||||||
 | 
					                          orName   python: '%s_or'  % operName;
 | 
				
			||||||
 | 
					                          andName  python: '%s_and' % operName;"
 | 
				
			||||||
 | 
					                  condition="python: widget['multiplicity'][1]!=1">
 | 
				
			||||||
 | 
					    <input type="radio" class="noborder" tal:attributes="name operName; id orName" checked="checked" value="or"/>
 | 
				
			||||||
 | 
					    <label tal:attributes="for orName" tal:content="python: tool.translate('search_or')"></label>
 | 
				
			||||||
 | 
					    <input type="radio" class="noborder" tal:attributes="name operName; id andName" value="and"/>
 | 
				
			||||||
 | 
					    <label tal:attributes="for andName" tal:content="python: tool.translate('search_and')"></label><br/>
 | 
				
			||||||
 | 
					    </tal:operator>
 | 
				
			||||||
 | 
					    <tal:comment replace="nothing">The list of values</tal:comment>
 | 
				
			||||||
 | 
					    <select tal:attributes="name widgetName" multiple="multiple" size="5">
 | 
				
			||||||
 | 
					      <option tal:repeat="v python:tool.getPossibleValues(name, withTranslations=True, withBlankValue=False, className=contentType)"
 | 
				
			||||||
 | 
					              tal:attributes="value python:v[0]" tal:content="python: v[1]">
 | 
				
			||||||
 | 
					      </option>
 | 
				
			||||||
 | 
					    </select>
 | 
				
			||||||
 | 
					  </tal:selectSearch><br/>
 | 
				
			||||||
 | 
					</metal:search>
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,6 @@ class <!genClassName!>(<!parents!>):
 | 
				
			||||||
    suppl_views = ()
 | 
					    suppl_views = ()
 | 
				
			||||||
    typeDescription = '<!genClassName!>'
 | 
					    typeDescription = '<!genClassName!>'
 | 
				
			||||||
    typeDescMsgId = '<!genClassName!>_edit_descr'
 | 
					    typeDescMsgId = '<!genClassName!>_edit_descr'
 | 
				
			||||||
    _at_rename_after_creation = True
 | 
					 | 
				
			||||||
    i18nDomain = '<!applicationName!>'
 | 
					    i18nDomain = '<!applicationName!>'
 | 
				
			||||||
    schema = fullSchema
 | 
					    schema = fullSchema
 | 
				
			||||||
    wrapperClass = <!genClassName!>_Wrapper
 | 
					    wrapperClass = <!genClassName!>_Wrapper
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,11 +6,9 @@ import Products.<!applicationName!>.config
 | 
				
			||||||
from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
 | 
					from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
 | 
				
			||||||
from Extensions.appyWrappers import <!wrapperClass!>
 | 
					from Extensions.appyWrappers import <!wrapperClass!>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
predefinedSchema = Schema((<!predefinedFields!>
 | 
					 | 
				
			||||||
),)
 | 
					 | 
				
			||||||
schema = Schema((<!fields!>
 | 
					schema = Schema((<!fields!>
 | 
				
			||||||
),)
 | 
					),)
 | 
				
			||||||
fullSchema = OrderedBaseFolderSchema.copy() + predefinedSchema.copy() + schema.copy()
 | 
					fullSchema = OrderedBaseFolderSchema.copy() + schema.copy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class <!flavourName!>(OrderedBaseFolder, FlavourMixin):
 | 
					class <!flavourName!>(OrderedBaseFolder, FlavourMixin):
 | 
				
			||||||
    '''Configuration flavour class for <!applicationName!>.'''
 | 
					    '''Configuration flavour class for <!applicationName!>.'''
 | 
				
			||||||
| 
						 | 
					@ -32,10 +30,8 @@ class <!flavourName!>(OrderedBaseFolder, FlavourMixin):
 | 
				
			||||||
    schema = fullSchema
 | 
					    schema = fullSchema
 | 
				
			||||||
    allMetaTypes = <!metaTypes!>
 | 
					    allMetaTypes = <!metaTypes!>
 | 
				
			||||||
    wrapperClass = <!wrapperClass!>
 | 
					    wrapperClass = <!wrapperClass!>
 | 
				
			||||||
    _at_rename_after_creation = True
 | 
					 | 
				
			||||||
    for elem in dir(FlavourMixin):
 | 
					    for elem in dir(FlavourMixin):
 | 
				
			||||||
        if not elem.startswith('__'): security.declarePublic(elem)
 | 
					        if not elem.startswith('__'): security.declarePublic(elem)
 | 
				
			||||||
<!commonMethods!>
 | 
					<!commonMethods!>
 | 
				
			||||||
<!predefinedMethods!>
 | 
					 | 
				
			||||||
<!methods!>
 | 
					<!methods!>
 | 
				
			||||||
registerType(<!flavourName!>, '<!applicationName!>')
 | 
					registerType(<!flavourName!>, '<!applicationName!>')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,6 @@ class <!applicationName!>PodTemplate(BaseContent, PodTemplateMixin):
 | 
				
			||||||
    suppl_views = ()
 | 
					    suppl_views = ()
 | 
				
			||||||
    typeDescription = "<!applicationName!>PodTemplate"
 | 
					    typeDescription = "<!applicationName!>PodTemplate"
 | 
				
			||||||
    typeDescMsgId = '<!applicationName!>_edit_descr'
 | 
					    typeDescMsgId = '<!applicationName!>_edit_descr'
 | 
				
			||||||
    _at_rename_after_creation = True
 | 
					 | 
				
			||||||
    wrapperClass = <!wrapperClass!>
 | 
					    wrapperClass = <!wrapperClass!>
 | 
				
			||||||
    schema = fullSchema
 | 
					    schema = fullSchema
 | 
				
			||||||
    for elem in dir(PodTemplateMixin):
 | 
					    for elem in dir(PodTemplateMixin):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@
 | 
				
			||||||
                     flavour python: tool.getFlavour(tool);"
 | 
					                     flavour python: tool.getFlavour(tool);"
 | 
				
			||||||
         tal:condition="tool/showPortlet">
 | 
					         tal:condition="tool/showPortlet">
 | 
				
			||||||
      <metal:block metal:use-macro="here/global_defines/macros/defines" />
 | 
					      <metal:block metal:use-macro="here/global_defines/macros/defines" />
 | 
				
			||||||
      <metal:prologue use-macro="here/skyn/macros/macros/pagePrologue"/>
 | 
					      <metal:prologue use-macro="here/skyn/page/macros/prologue"/>
 | 
				
			||||||
      <dl tal:define="rootClasses tool/getRootClasses;
 | 
					      <dl tal:define="rootClasses tool/getRootClasses;
 | 
				
			||||||
                      appName string:<!applicationName!>;
 | 
					                      appName string:<!applicationName!>;
 | 
				
			||||||
                      appFolder tool/getAppFolder;
 | 
					                      appFolder tool/getAppFolder;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,23 +4,16 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#portal-breadcrumbs { display: none; }
 | 
					#portal-breadcrumbs { display: none; }
 | 
				
			||||||
#importedElem { color: grey; font-style: italic; }
 | 
					#importedElem { color: grey; font-style: italic; }
 | 
				
			||||||
 | 
					label         { font-weight: bold;  font-style: italic; }
 | 
				
			||||||
 | 
					.discreet     { font-size: 94%; }
 | 
				
			||||||
.appyList     { line-height: 1.1em; margin: 0 0 0.5em 1.2em;  padding: 0; }
 | 
					.appyList     { line-height: 1.1em; margin: 0 0 0.5em 1.2em;  padding: 0; }
 | 
				
			||||||
.appyBullet   { margin: 0; }
 | 
					.appyBullet   { margin: 0; }
 | 
				
			||||||
.appyPod      { float:right; }
 | 
					.appyPod      { float:right; }
 | 
				
			||||||
.appyNav      { padding: 0.4em 0 0.4em 0; }
 | 
					.appyNav      { padding: 0.4em 0 0.4em 0; }
 | 
				
			||||||
.appyFocus    { color: #900101; }
 | 
					.appyFocus    { color: #900101; }
 | 
				
			||||||
.appyTabs { margin-bottom: 1em; }
 | 
					 | 
				
			||||||
.appyTabs li a { border-bottom:1px solid transparent; font-size: 90%; }
 | 
					 | 
				
			||||||
.appyTabs li a:visited { color: #578308; }
 | 
					 | 
				
			||||||
.appyTitle    { padding-top: 0.5em; font-size: 110%; }
 | 
					.appyTitle    { padding-top: 0.5em; font-size: 110%; }
 | 
				
			||||||
.appyLabel { font-weight: bold; padding-right: 0.4em; }
 | 
					 | 
				
			||||||
.appyRefEdit  { line-height: 1.5em; }
 | 
					.appyRefEdit  { line-height: 1.5em; }
 | 
				
			||||||
 | 
					.appyWorkflow { text-align: center; background-color: &dtml-globalBackgroundColor;;}
 | 
				
			||||||
.appyWorkflow {
 | 
					 | 
				
			||||||
  text-align: center;
 | 
					 | 
				
			||||||
  background-color: &dtml-globalBackgroundColor;;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.appyPlusImg {
 | 
					.appyPlusImg {
 | 
				
			||||||
  vertical-align: top;
 | 
					  vertical-align: top;
 | 
				
			||||||
| 
						 | 
					@ -30,10 +23,9 @@
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.appyPhase {
 | 
					.appyPhase {
 | 
				
			||||||
  border-style: solid;
 | 
					  border-style: dashed;
 | 
				
			||||||
  border-width: thin;
 | 
					  border-width: thin;
 | 
				
			||||||
  text-align: center;
 | 
					  padding: 0 0.1em 0 1em;
 | 
				
			||||||
  padding: 0 1em 0 1.3em;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.appyState {
 | 
					.appyState {
 | 
				
			||||||
| 
						 | 
					@ -75,14 +67,14 @@
 | 
				
			||||||
  background-color: #cde2a7;
 | 
					  background-color: #cde2a7;
 | 
				
			||||||
  background-image: url(&dtml-portal_url;/skyn/done.png);
 | 
					  background-image: url(&dtml-portal_url;/skyn/done.png);
 | 
				
			||||||
  background-repeat: no-repeat;
 | 
					  background-repeat: no-repeat;
 | 
				
			||||||
  background-position: center left;
 | 
					  background-position: -1px 4px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.stepCurrent {
 | 
					.stepCurrent {
 | 
				
			||||||
  background-color: #ffce7b;
 | 
					  background-color: #eef3f5;
 | 
				
			||||||
  background-image: url(&dtml-portal_url;/skyn/current.png);
 | 
					  background-image: url(&dtml-portal_url;/skyn/current.png);
 | 
				
			||||||
  background-repeat: no-repeat;
 | 
					  background-repeat: no-repeat;
 | 
				
			||||||
  background-position: center left;
 | 
					  background-position: -1px 4px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.stepFuture {
 | 
					.stepFuture {
 | 
				
			||||||
| 
						 | 
					@ -104,13 +96,7 @@
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* With fields layout in columns, standard error frame is too large */
 | 
					/* With fields layout in columns, standard error frame is too large */
 | 
				
			||||||
.error {
 | 
					.odd {  background-color: white; }
 | 
				
			||||||
  padding: 0.4em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.odd {
 | 
					 | 
				
			||||||
  background-color: white;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Table styles */
 | 
					/* Table styles */
 | 
				
			||||||
.no-style-table {
 | 
					.no-style-table {
 | 
				
			||||||
| 
						 | 
					@ -125,18 +111,41 @@
 | 
				
			||||||
  margin: 0 !important;
 | 
					  margin: 0 !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Minor layout changes in fieldsets and tables */
 | 
					 | 
				
			||||||
fieldset {
 | 
					fieldset {
 | 
				
			||||||
  margin: 0 0 0 0;
 | 
					 | 
				
			||||||
  line-height: 1em;
 | 
					  line-height: 1em;
 | 
				
			||||||
 | 
					  border: 2px solid #8CACBB;
 | 
				
			||||||
 | 
					  margin: 0.5em 0em 0.5em 0em;
 | 
				
			||||||
 | 
					  padding: 0 0.7em 0.5em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.fieldset {
 | 
					th {
 | 
				
			||||||
  line-height: 1em;
 | 
					  font-style: italic;
 | 
				
			||||||
 | 
					  font-weight: normal;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
/* Group fieldsets */
 | 
					
 | 
				
			||||||
.appyGroup {
 | 
					.section1 {
 | 
				
			||||||
  border-width: 2px;
 | 
					  font-size: 120%;
 | 
				
			||||||
 | 
					  margin: 0.45em 0em 0.1em 0;
 | 
				
			||||||
 | 
					  padding: 0.3em 0em 0.2em 0.1em;
 | 
				
			||||||
 | 
					  background-color: #eef3f5;
 | 
				
			||||||
 | 
					  border-top: 1px solid #8CACBB;
 | 
				
			||||||
 | 
					  border-bottom: 1px solid #8CACBB;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.section2 {
 | 
				
			||||||
 | 
					  font-size: 110%;
 | 
				
			||||||
 | 
					  font-style: italic;
 | 
				
			||||||
 | 
					  margin: 0.45em 0em 0.1em 0;
 | 
				
			||||||
 | 
					  border-bottom: 2px solid #8CACBB;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.section3 {
 | 
				
			||||||
 | 
					  font-size: 100%;
 | 
				
			||||||
 | 
					  font-style: italic;
 | 
				
			||||||
 | 
					  margin: 0.45em 0em 0.1em 0;
 | 
				
			||||||
 | 
					  background-color: #efeae8;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  color: grey;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.imageInput {
 | 
					.imageInput {
 | 
				
			||||||
| 
						 | 
					@ -169,6 +178,7 @@ fieldset {
 | 
				
			||||||
  padding-left: 0.3em;
 | 
					  padding-left: 0.3em;
 | 
				
			||||||
  padding-top: 0.3em;
 | 
					  padding-top: 0.3em;
 | 
				
			||||||
  padding-bottom: 0em;
 | 
					  padding-bottom: 0em;
 | 
				
			||||||
 | 
					  border-top : 1px solid #8CACBB;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.vertical td {
 | 
					.vertical td {
 | 
				
			||||||
| 
						 | 
					@ -212,9 +222,6 @@ fieldset {
 | 
				
			||||||
  font-weight: normal;
 | 
					  font-weight: normal;
 | 
				
			||||||
  text-transform: none;
 | 
					  text-transform: none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.portletSep {
 | 
					 | 
				
			||||||
  border-top: 1px dashed #8cacbb;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.portletSearch {
 | 
					.portletSearch {
 | 
				
			||||||
  padding: 0 0 0 0.6em;
 | 
					  padding: 0 0 0 0.6em;
 | 
				
			||||||
  font-style: normal;
 | 
					  font-style: normal;
 | 
				
			||||||
| 
						 | 
					@ -225,13 +232,11 @@ fieldset {
 | 
				
			||||||
  font-weight: bold;
 | 
					  font-weight: bold;
 | 
				
			||||||
  font-style: normal;
 | 
					  font-style: normal;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.portletGroupItem {
 | 
					.portletSep       {  border-top: 1px dashed #8cacbb; }
 | 
				
			||||||
  padding-left: 0.8em;
 | 
					.portletGroupItem { padding-left: 0.8em; font-style: italic; }
 | 
				
			||||||
  font-style: italic;
 | 
					.portletPageItem  { font-style: italic; }
 | 
				
			||||||
}
 | 
					.portletCurrent   { font-weight: bold; }
 | 
				
			||||||
.portletCurrent {
 | 
					
 | 
				
			||||||
  font-weight: bold;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
div.appyGrey {
 | 
					div.appyGrey {
 | 
				
			||||||
  display: none;
 | 
					  display: none;
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,11 +7,9 @@ import Products.<!applicationName!>.config
 | 
				
			||||||
from appy.gen.plone25.mixins.ToolMixin import ToolMixin
 | 
					from appy.gen.plone25.mixins.ToolMixin import ToolMixin
 | 
				
			||||||
from Extensions.appyWrappers import AbstractWrapper, <!wrapperClass!>
 | 
					from Extensions.appyWrappers import AbstractWrapper, <!wrapperClass!>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
predefinedSchema = Schema((<!predefinedFields!>
 | 
					 | 
				
			||||||
),)
 | 
					 | 
				
			||||||
schema = Schema((<!fields!>
 | 
					schema = Schema((<!fields!>
 | 
				
			||||||
),)
 | 
					),)
 | 
				
			||||||
fullSchema = OrderedBaseFolderSchema.copy() + predefinedSchema.copy() + schema.copy()
 | 
					fullSchema = OrderedBaseFolderSchema.copy() + schema.copy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class <!toolName!>(UniqueObject, OrderedBaseFolder, ToolMixin):
 | 
					class <!toolName!>(UniqueObject, OrderedBaseFolder, ToolMixin):
 | 
				
			||||||
    '''Tool for <!applicationName!>.'''
 | 
					    '''Tool for <!applicationName!>.'''
 | 
				
			||||||
| 
						 | 
					@ -32,7 +30,6 @@ class <!toolName!>(UniqueObject, OrderedBaseFolder, ToolMixin):
 | 
				
			||||||
    typeDescMsgId = '<!toolName!>_edit_descr'
 | 
					    typeDescMsgId = '<!toolName!>_edit_descr'
 | 
				
			||||||
    i18nDomain = '<!applicationName!>'
 | 
					    i18nDomain = '<!applicationName!>'
 | 
				
			||||||
    wrapperClass = <!wrapperClass!>
 | 
					    wrapperClass = <!wrapperClass!>
 | 
				
			||||||
    _at_rename_after_creation = True
 | 
					 | 
				
			||||||
    schema = fullSchema
 | 
					    schema = fullSchema
 | 
				
			||||||
    schema["id"].widget.visible = False
 | 
					    schema["id"].widget.visible = False
 | 
				
			||||||
    schema["title"].widget.visible = False
 | 
					    schema["title"].widget.visible = False
 | 
				
			||||||
| 
						 | 
					@ -47,6 +44,5 @@ class <!toolName!>(UniqueObject, OrderedBaseFolder, ToolMixin):
 | 
				
			||||||
        OrderedBaseFolder.__init__(self, '<!toolInstanceName!>')
 | 
					        OrderedBaseFolder.__init__(self, '<!toolInstanceName!>')
 | 
				
			||||||
        self.setTitle('<!applicationName!>')
 | 
					        self.setTitle('<!applicationName!>')
 | 
				
			||||||
<!commonMethods!>
 | 
					<!commonMethods!>
 | 
				
			||||||
<!predefinedMethods!>
 | 
					 | 
				
			||||||
<!methods!>
 | 
					<!methods!>
 | 
				
			||||||
registerType(<!toolName!>, '<!applicationName!>')
 | 
					registerType(<!toolName!>, '<!applicationName!>')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,8 +45,9 @@ def initialize(context):
 | 
				
			||||||
<!imports!>
 | 
					<!imports!>
 | 
				
			||||||
    # I need to do those imports here; else, types and add permissions will not
 | 
					    # I need to do those imports here; else, types and add permissions will not
 | 
				
			||||||
    # be registered.
 | 
					    # be registered.
 | 
				
			||||||
 | 
					    classes = [<!classes!>]
 | 
				
			||||||
    ZopeInstaller(context, PROJECTNAME,
 | 
					    ZopeInstaller(context, PROJECTNAME,
 | 
				
			||||||
        <!applicationName!>Tool.<!applicationName!>Tool,
 | 
					        <!applicationName!>Tool.<!applicationName!>Tool,
 | 
				
			||||||
        DEFAULT_ADD_CONTENT_PERMISSION, ADD_CONTENT_PERMISSIONS,
 | 
					        DEFAULT_ADD_CONTENT_PERMISSION, ADD_CONTENT_PERMISSIONS,
 | 
				
			||||||
        logger, globals()).install()
 | 
					        logger, globals(), classes).install()
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
from appy.gen import *
 | 
					from appy.gen import *
 | 
				
			||||||
from appy.gen.plone25.wrappers import AbstractWrapper, FileWrapper
 | 
					from appy.gen.plone25.wrappers import AbstractWrapper
 | 
				
			||||||
from appy.gen.plone25.wrappers.ToolWrapper import ToolWrapper
 | 
					from appy.gen.plone25.wrappers.ToolWrapper import ToolWrapper
 | 
				
			||||||
from appy.gen.plone25.wrappers.FlavourWrapper import FlavourWrapper
 | 
					from appy.gen.plone25.wrappers.FlavourWrapper import FlavourWrapper
 | 
				
			||||||
from appy.gen.plone25.wrappers.PodTemplateWrapper import PodTemplateWrapper
 | 
					from appy.gen.plone25.wrappers.PodTemplateWrapper import PodTemplateWrapper
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,8 @@
 | 
				
			||||||
<!codeHeader!>
 | 
					<!codeHeader!>
 | 
				
			||||||
import os, os.path, sys
 | 
					import os, os.path, sys, copy
 | 
				
			||||||
try: # New CMF
 | 
					import appy.gen
 | 
				
			||||||
    from Products.CMFCore.permissions import setDefaultRoles
 | 
					from Products.CMFCore.permissions import setDefaultRoles
 | 
				
			||||||
except ImportError: # Old CMF
 | 
					import Extensions.appyWrappers as wraps
 | 
				
			||||||
    from Products.CMFCore.CMFCorePermissions import setDefaultRoles
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import Extensions.appyWrappers
 | 
					 | 
				
			||||||
<!imports!>
 | 
					<!imports!>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
# The following imports are here for allowing mixin classes to access those
 | 
					# The following imports are here for allowing mixin classes to access those
 | 
				
			||||||
| 
						 | 
					@ -17,7 +14,6 @@ from OFS.Image import File
 | 
				
			||||||
from DateTime import DateTime
 | 
					from DateTime import DateTime
 | 
				
			||||||
from Products.CMFCore.utils import getToolByName
 | 
					from Products.CMFCore.utils import getToolByName
 | 
				
			||||||
from Products.CMFPlone.PloneBatch import Batch
 | 
					from Products.CMFPlone.PloneBatch import Batch
 | 
				
			||||||
from Products.Archetypes.utils import DisplayList
 | 
					 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
logger = logging.getLogger('<!applicationName!>')
 | 
					logger = logging.getLogger('<!applicationName!>')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,9 +28,7 @@ setDefaultRoles(DEFAULT_ADD_CONTENT_PERMISSION, tuple(defaultAddRoles))
 | 
				
			||||||
product_globals = globals()
 | 
					product_globals = globals()
 | 
				
			||||||
applicationRoles = [<!roles!>]
 | 
					applicationRoles = [<!roles!>]
 | 
				
			||||||
rootClasses = [<!rootClasses!>]
 | 
					rootClasses = [<!rootClasses!>]
 | 
				
			||||||
referers = {
 | 
					
 | 
				
			||||||
<!referers!>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
# In the following dict, we keep one instance for every Appy workflow defined
 | 
					# In the following dict, we keep one instance for every Appy workflow defined
 | 
				
			||||||
# in the application. Those prototypical instances will be used for executing
 | 
					# in the application. Those prototypical instances will be used for executing
 | 
				
			||||||
# user-defined actions and transitions. For each instance, we add a special
 | 
					# user-defined actions and transitions. For each instance, we add a special
 | 
				
			||||||
| 
						 | 
					@ -44,6 +38,9 @@ workflowInstances = {}
 | 
				
			||||||
<!workflowInstancesInit!>
 | 
					<!workflowInstancesInit!>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# In the following dict, we store, for every Appy class, the ordered list of
 | 
					# In the following dict, we store, for every Appy class, the ordered list of
 | 
				
			||||||
# attributes (included inherited attributes).
 | 
					# appy types (included inherited ones).
 | 
				
			||||||
attributes = {<!attributes!>}
 | 
					attributes = {<!attributes!>}
 | 
				
			||||||
 | 
					# In the followinf dict, we store, for every Appy class, a dict of appy types
 | 
				
			||||||
 | 
					# keyed by their names.
 | 
				
			||||||
 | 
					attributesDict = {<!attributesDict!>}
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,5 @@
 | 
				
			||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" i18n:domain="plone">
 | 
					<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" i18n:domain="plone">
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
<tal:message i18n:domain="plone" metal:define-macro="portal_message">
 | 
					  <tal:message metal:define-macro="portal_message"></tal:message>
 | 
				
			||||||
    <tal:comment replace="nothing">Single message from portal_status_message request key</tal:comment>
 | 
					 | 
				
			||||||
    <div tal:define="msg request/portal_status_message | nothing"
 | 
					 | 
				
			||||||
         tal:condition="msg" class="portalMessage" tal:content="msg" i18n:translate=""></div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <tal:comment replace="nothing">Messages added via plone_utils</tal:comment>
 | 
					 | 
				
			||||||
    <tal:messages define="messages putils/showPortalMessages" condition="messages">
 | 
					 | 
				
			||||||
      <tal:msgs define="type_css_map python: {'info':'portalMessage', 'warn':'portalWarningMessage',
 | 
					 | 
				
			||||||
                                              'stop':'portalStopMessage'};"
 | 
					 | 
				
			||||||
                repeat="msg messages">
 | 
					 | 
				
			||||||
        <div tal:define="mtype msg/type | nothing;"
 | 
					 | 
				
			||||||
             tal:attributes="class python:mtype and type_css_map[mtype] or 'info';"
 | 
					 | 
				
			||||||
             tal:content="structure msg/message | nothing" i18n:translate=""></div>
 | 
					 | 
				
			||||||
      </tal:msgs>
 | 
					 | 
				
			||||||
    </tal:messages>
 | 
					 | 
				
			||||||
</tal:message>
 | 
					 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,11 +33,4 @@ def updateRolesForPermission(permission, roles, obj):
 | 
				
			||||||
            existingRoles = perm.getRoles()
 | 
					            existingRoles = perm.getRoles()
 | 
				
			||||||
    allRoles = set(existingRoles).union(roles)
 | 
					    allRoles = set(existingRoles).union(roles)
 | 
				
			||||||
    obj.manage_permission(permission, tuple(allRoles), acquire=0)
 | 
					    obj.manage_permission(permission, tuple(allRoles), acquire=0)
 | 
				
			||||||
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					 | 
				
			||||||
from appy.gen.utils import AppyRequest
 | 
					 | 
				
			||||||
def getAppyRequest(zopeRequest, obj=None):
 | 
					 | 
				
			||||||
    '''This method creates a nice (Appy) object representation of a
 | 
					 | 
				
			||||||
       dictionary-like Zope REQUEST object.'''
 | 
					 | 
				
			||||||
    return AppyRequest(zopeRequest, obj)
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class FlavourWrapper:
 | 
					from appy.gen.plone25.wrappers import AbstractWrapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class FlavourWrapper(AbstractWrapper):
 | 
				
			||||||
    def onEdit(self, created):
 | 
					    def onEdit(self, created):
 | 
				
			||||||
        if created:
 | 
					        if created:
 | 
				
			||||||
            nbOfFlavours = len(self.tool.flavours)
 | 
					            nbOfFlavours = len(self.tool.flavours)
 | 
				
			||||||
| 
						 | 
					@ -8,8 +10,7 @@ class FlavourWrapper:
 | 
				
			||||||
                self.number = nbOfFlavours
 | 
					                self.number = nbOfFlavours
 | 
				
			||||||
                self.o.registerPortalTypes()
 | 
					                self.o.registerPortalTypes()
 | 
				
			||||||
        # Call the custom flavour "onEdit" method if it exists
 | 
					        # Call the custom flavour "onEdit" method if it exists
 | 
				
			||||||
        customFlavour = self.__class__.__bases__[1]
 | 
					        if len(self.__class__.__bases__) > 1:
 | 
				
			||||||
        if customFlavour.__name__ != 'Flavour':
 | 
					 | 
				
			||||||
            # There is a custom flavour
 | 
					            # There is a custom flavour
 | 
				
			||||||
            if customFlavour.__dict__.has_key('onEdit'):
 | 
					            if customFlavour.__dict__.has_key('onEdit'):
 | 
				
			||||||
                customFlavour.__dict__['onEdit'](self, created)
 | 
					                customFlavour.__dict__['onEdit'](self, created)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,6 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class PodTemplateWrapper: pass
 | 
					from appy.gen.plone25.wrappers import AbstractWrapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class PodTemplateWrapper(AbstractWrapper): pass
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,32 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ToolWrapper:
 | 
					from appy.gen.plone25.wrappers import AbstractWrapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					_PY = 'Please specify a file corresponding to a Python interpreter ' \
 | 
				
			||||||
 | 
					      '(ie "/usr/bin/python").'
 | 
				
			||||||
 | 
					FILE_NOT_FOUND = 'Path "%s" was not found.'
 | 
				
			||||||
 | 
					VALUE_NOT_FILE = 'Path "%s" is not a file. ' + _PY
 | 
				
			||||||
 | 
					NO_PYTHON = "Name '%s' does not starts with 'python'. " + _PY
 | 
				
			||||||
 | 
					NOT_UNO_ENABLED_PYTHON = '"%s" is not a UNO-enabled Python interpreter. ' \
 | 
				
			||||||
 | 
					                         'To check if a Python interpreter is UNO-enabled, ' \
 | 
				
			||||||
 | 
					                         'launch it and type "import uno". If you have no ' \
 | 
				
			||||||
 | 
					                         'ImportError exception it is ok.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class ToolWrapper(AbstractWrapper):
 | 
				
			||||||
 | 
					    def validPythonWithUno(self, value):
 | 
				
			||||||
 | 
					        '''This method represents the validator for field unoEnabledPython.'''
 | 
				
			||||||
 | 
					        if value:
 | 
				
			||||||
 | 
					            if not os.path.exists(value):
 | 
				
			||||||
 | 
					                return FILE_NOT_FOUND % value
 | 
				
			||||||
 | 
					            if not os.path.isfile(value):
 | 
				
			||||||
 | 
					                return VALUE_NOT_FILE % value
 | 
				
			||||||
 | 
					            if not os.path.basename(value).startswith('python'):
 | 
				
			||||||
 | 
					                return NO_PYTHON % value
 | 
				
			||||||
 | 
					            if os.system('%s -c "import uno"' % value):
 | 
				
			||||||
 | 
					                return NOT_UNO_ENABLED_PYTHON % value
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getInitiator(self):
 | 
					    def getInitiator(self):
 | 
				
			||||||
        '''Retrieves the object that triggered the creation of the object
 | 
					        '''Retrieves the object that triggered the creation of the object
 | 
				
			||||||
           being currently created (if any).'''
 | 
					           being currently created (if any).'''
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
import os, os.path, time, mimetypes, random
 | 
					import os, os.path, time, mimetypes, random
 | 
				
			||||||
import appy.pod
 | 
					import appy.pod
 | 
				
			||||||
from appy.gen import Search
 | 
					from appy.gen import Search
 | 
				
			||||||
from appy.gen.utils import sequenceTypes
 | 
					from appy.gen.utils import sequenceTypes, FileWrapper
 | 
				
			||||||
from appy.shared.utils import getOsTempFolder, executeCommand, normalizeString
 | 
					from appy.shared.utils import getOsTempFolder, executeCommand, normalizeString
 | 
				
			||||||
from appy.shared.xml_parser import XmlMarshaller
 | 
					from appy.shared.xml_parser import XmlMarshaller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,9 +32,9 @@ class AbstractWrapper:
 | 
				
			||||||
              v MIME type of the file.'''
 | 
					              v MIME type of the file.'''
 | 
				
			||||||
        ploneFileClass = self.o.getProductConfig().File
 | 
					        ploneFileClass = self.o.getProductConfig().File
 | 
				
			||||||
        if isinstance(v, ploneFileClass):
 | 
					        if isinstance(v, ploneFileClass):
 | 
				
			||||||
            exec "self.o.set%s%s(v)" % (name[0].upper(), name[1:])
 | 
					            setattr(self.o, name, v)
 | 
				
			||||||
        elif isinstance(v, FileWrapper):
 | 
					        elif isinstance(v, FileWrapper):
 | 
				
			||||||
            setattr(self, name, v._atFile)
 | 
					            setattr(self.o, name, v._atFile)
 | 
				
			||||||
        elif isinstance(v, basestring):
 | 
					        elif isinstance(v, basestring):
 | 
				
			||||||
            f = file(v)
 | 
					            f = file(v)
 | 
				
			||||||
            fileName = os.path.basename(v)
 | 
					            fileName = os.path.basename(v)
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ class AbstractWrapper:
 | 
				
			||||||
            ploneFile = ploneFileClass(fileId, fileName, f)
 | 
					            ploneFile = ploneFileClass(fileId, fileName, f)
 | 
				
			||||||
            ploneFile.filename = fileName
 | 
					            ploneFile.filename = fileName
 | 
				
			||||||
            ploneFile.content_type = mimetypes.guess_type(fileName)[0]
 | 
					            ploneFile.content_type = mimetypes.guess_type(fileName)[0]
 | 
				
			||||||
            setattr(self, name, ploneFile)
 | 
					            setattr(self.o, name, ploneFile)
 | 
				
			||||||
            f.close()
 | 
					            f.close()
 | 
				
			||||||
        elif type(v) in sequenceTypes:
 | 
					        elif type(v) in sequenceTypes:
 | 
				
			||||||
            # It should be a 2-tuple or 3-tuple
 | 
					            # It should be a 2-tuple or 3-tuple
 | 
				
			||||||
| 
						 | 
					@ -61,15 +61,20 @@ class AbstractWrapper:
 | 
				
			||||||
                if not mimeType:
 | 
					                if not mimeType:
 | 
				
			||||||
                    mimeType = mimetypes.guess_type(fileName)[0]
 | 
					                    mimeType = mimetypes.guess_type(fileName)[0]
 | 
				
			||||||
                ploneFile.content_type = mimeType
 | 
					                ploneFile.content_type = mimeType
 | 
				
			||||||
                setattr(self, name, ploneFile)
 | 
					                setattr(self.o, name, ploneFile)
 | 
				
			||||||
    def __setattr__(self, name, v):
 | 
					    def __setattr__(self, name, v):
 | 
				
			||||||
 | 
					        if name == 'title':
 | 
				
			||||||
 | 
					            self.o.setTitle(v)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
        appyType = self.o.getAppyType(name)
 | 
					        appyType = self.o.getAppyType(name)
 | 
				
			||||||
        if not appyType and (name != 'title'):
 | 
					        if not appyType:
 | 
				
			||||||
            raise 'Attribute "%s" does not exist.' % name
 | 
					            raise 'Attribute "%s" does not exist.' % name
 | 
				
			||||||
        if appyType and (appyType['type'] == 'File'):
 | 
					        if appyType.type == 'File':
 | 
				
			||||||
            self._set_file_attribute(name, v)
 | 
					            self._set_file_attribute(name, v)
 | 
				
			||||||
 | 
					        elif appyType.type == 'Ref':
 | 
				
			||||||
 | 
					            raise "Use methods 'link' or 'create' to modify references."
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            exec "self.o.set%s%s(v)" % (name[0].upper(), name[1:])
 | 
					            setattr(self.o, name, v)
 | 
				
			||||||
    def __repr__(self):
 | 
					    def __repr__(self):
 | 
				
			||||||
        return '<%s wrapper at %s>' % (self.klass.__name__, id(self))
 | 
					        return '<%s wrapper at %s>' % (self.klass.__name__, id(self))
 | 
				
			||||||
    def __cmp__(self, other):
 | 
					    def __cmp__(self, other):
 | 
				
			||||||
| 
						 | 
					@ -94,17 +99,18 @@ class AbstractWrapper:
 | 
				
			||||||
        appName = self.o.getProductConfig().PROJECTNAME
 | 
					        appName = self.o.getProductConfig().PROJECTNAME
 | 
				
			||||||
        return self.o.utranslate(self.o.getWorkflowLabel(), domain=appName)
 | 
					        return self.o.utranslate(self.o.getWorkflowLabel(), domain=appName)
 | 
				
			||||||
    stateLabel = property(get_stateLabel)
 | 
					    stateLabel = property(get_stateLabel)
 | 
				
			||||||
    def get_klass(self): return self.__class__.__bases__[1]
 | 
					    def get_klass(self): return self.__class__.__bases__[-1]
 | 
				
			||||||
    klass = property(get_klass)
 | 
					    klass = property(get_klass)
 | 
				
			||||||
    def get_url(self): return self.o.absolute_url()+'/skyn/view'
 | 
					    def get_url(self): return self.o.absolute_url()
 | 
				
			||||||
    url = property(get_url)
 | 
					    url = property(get_url)
 | 
				
			||||||
    def get_history(self):
 | 
					    def get_history(self):
 | 
				
			||||||
        key = self.o.workflow_history.keys()[0]
 | 
					        key = self.o.workflow_history.keys()[0]
 | 
				
			||||||
        return self.o.workflow_history[key]
 | 
					        return self.o.workflow_history[key]
 | 
				
			||||||
    history = property(get_history)
 | 
					    history = property(get_history)
 | 
				
			||||||
    def get_user(self):
 | 
					    def get_user(self): return self.o.portal_membership.getAuthenticatedMember()
 | 
				
			||||||
        return self.o.portal_membership.getAuthenticatedMember()
 | 
					 | 
				
			||||||
    user = property(get_user)
 | 
					    user = property(get_user)
 | 
				
			||||||
 | 
					    def get_fields(self): return self.o.getAllAppyTypes()
 | 
				
			||||||
 | 
					    fields = property(get_fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def link(self, fieldName, obj):
 | 
					    def link(self, fieldName, obj):
 | 
				
			||||||
        '''This method links p_obj to this one through reference field
 | 
					        '''This method links p_obj to this one through reference field
 | 
				
			||||||
| 
						 | 
					@ -178,7 +184,6 @@ class AbstractWrapper:
 | 
				
			||||||
        appyObj = ploneObj.appy()
 | 
					        appyObj = ploneObj.appy()
 | 
				
			||||||
        # Set object attributes
 | 
					        # Set object attributes
 | 
				
			||||||
        for attrName, attrValue in kwargs.iteritems():
 | 
					        for attrName, attrValue in kwargs.iteritems():
 | 
				
			||||||
            setterName = 'set%s%s' % (attrName[0].upper(), attrName[1:])
 | 
					 | 
				
			||||||
            if isinstance(attrValue, AbstractWrapper):
 | 
					            if isinstance(attrValue, AbstractWrapper):
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    refAppyType = getattr(appyObj.__class__.__bases__[-1],
 | 
					                    refAppyType = getattr(appyObj.__class__.__bases__[-1],
 | 
				
			||||||
| 
						 | 
					@ -187,7 +192,7 @@ class AbstractWrapper:
 | 
				
			||||||
                except AttributeError, ae:
 | 
					                except AttributeError, ae:
 | 
				
			||||||
                    pass
 | 
					                    pass
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                getattr(ploneObj, setterName)(attrValue)
 | 
					                setattr(appyObj, attrName, attrValue)
 | 
				
			||||||
        if isField:
 | 
					        if isField:
 | 
				
			||||||
            # Link the object to this one
 | 
					            # Link the object to this one
 | 
				
			||||||
            self.link(fieldName, ploneObj)
 | 
					            self.link(fieldName, ploneObj)
 | 
				
			||||||
| 
						 | 
					@ -375,85 +380,4 @@ class AbstractWrapper:
 | 
				
			||||||
           p_data must be a dictionary whose keys are field names (strings) and
 | 
					           p_data must be a dictionary whose keys are field names (strings) and
 | 
				
			||||||
           whose values are the previous field values.'''
 | 
					           whose values are the previous field values.'''
 | 
				
			||||||
        self.o.addDataChange(data, labels=False)
 | 
					        self.o.addDataChange(data, labels=False)
 | 
				
			||||||
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					 | 
				
			||||||
CONVERSION_ERROR = 'An error occurred while executing command "%s". %s'
 | 
					 | 
				
			||||||
class FileWrapper:
 | 
					 | 
				
			||||||
    '''When you get, from an appy object, the value of a File attribute, you
 | 
					 | 
				
			||||||
       get an instance of this class.'''
 | 
					 | 
				
			||||||
    def __init__(self, atFile):
 | 
					 | 
				
			||||||
        '''This constructor is only used by Appy to create a nice File instance
 | 
					 | 
				
			||||||
           from a Plone/Zope corresponding instance (p_atFile). If you need to
 | 
					 | 
				
			||||||
           create a new file and assign it to a File attribute, use the
 | 
					 | 
				
			||||||
           attribute setter, do not create yourself an instance of this
 | 
					 | 
				
			||||||
           class.'''
 | 
					 | 
				
			||||||
        d = self.__dict__
 | 
					 | 
				
			||||||
        d['_atFile'] = atFile # Not for you!
 | 
					 | 
				
			||||||
        d['name'] = atFile.filename
 | 
					 | 
				
			||||||
        d['content'] = atFile.data
 | 
					 | 
				
			||||||
        d['mimeType'] = atFile.content_type
 | 
					 | 
				
			||||||
        d['size'] = atFile.size # In bytes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __setattr__(self, name, v):
 | 
					 | 
				
			||||||
        d = self.__dict__
 | 
					 | 
				
			||||||
        if name == 'name':
 | 
					 | 
				
			||||||
            self._atFile.filename = v
 | 
					 | 
				
			||||||
            d['name'] = v
 | 
					 | 
				
			||||||
        elif name == 'content':
 | 
					 | 
				
			||||||
            self._atFile.update_data(v, self.mimeType, len(v))
 | 
					 | 
				
			||||||
            d['content'] = v
 | 
					 | 
				
			||||||
            d['size'] = len(v)
 | 
					 | 
				
			||||||
        elif name == 'mimeType':
 | 
					 | 
				
			||||||
            self._atFile.content_type = self.mimeType = v
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            raise 'Impossible to set attribute %s. "Settable" attributes ' \
 | 
					 | 
				
			||||||
                  'are "name", "content" and "mimeType".' % name
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def dump(self, filePath=None, format=None, tool=None):
 | 
					 | 
				
			||||||
        '''Writes the file on disk. If p_filePath is specified, it is the
 | 
					 | 
				
			||||||
           path name where the file will be dumped; folders mentioned in it
 | 
					 | 
				
			||||||
           must exist. If not, the file will be dumped in the OS temp folder.
 | 
					 | 
				
			||||||
           The absolute path name of the dumped file is returned.
 | 
					 | 
				
			||||||
           If an error occurs, the method returns None. If p_format is
 | 
					 | 
				
			||||||
           specified, OpenOffice will be called for converting the dumped file
 | 
					 | 
				
			||||||
           to the desired format. In this case, p_tool, a Appy tool, must be
 | 
					 | 
				
			||||||
           provided. Indeed, any Appy tool contains parameters for contacting
 | 
					 | 
				
			||||||
           OpenOffice in server mode.'''
 | 
					 | 
				
			||||||
        if not filePath:
 | 
					 | 
				
			||||||
            filePath = '%s/file%f.%s' % (getOsTempFolder(), time.time(),
 | 
					 | 
				
			||||||
                normalizeString(self.name))
 | 
					 | 
				
			||||||
        f = file(filePath, 'w')
 | 
					 | 
				
			||||||
        if self.content.__class__.__name__ == 'Pdata':
 | 
					 | 
				
			||||||
            # The file content is splitted in several chunks.
 | 
					 | 
				
			||||||
            f.write(self.content.data)
 | 
					 | 
				
			||||||
            nextPart = self.content.next
 | 
					 | 
				
			||||||
            while nextPart:
 | 
					 | 
				
			||||||
                f.write(nextPart.data)
 | 
					 | 
				
			||||||
                nextPart = nextPart.next
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            # Only one chunk
 | 
					 | 
				
			||||||
            f.write(self.content)
 | 
					 | 
				
			||||||
        f.close()
 | 
					 | 
				
			||||||
        if format:
 | 
					 | 
				
			||||||
            if not tool: return
 | 
					 | 
				
			||||||
            # Convert the dumped file using OpenOffice
 | 
					 | 
				
			||||||
            convScript = '%s/converter.py' % os.path.dirname(appy.pod.__file__)
 | 
					 | 
				
			||||||
            cmd = '%s %s "%s" %s -p%d' % (tool.unoEnabledPython, convScript,
 | 
					 | 
				
			||||||
                filePath, format, tool.openOfficePort)
 | 
					 | 
				
			||||||
            errorMessage = executeCommand(cmd)
 | 
					 | 
				
			||||||
            # Even if we have an "error" message, it could be a simple warning.
 | 
					 | 
				
			||||||
            # So we will continue here and, as a subsequent check for knowing if
 | 
					 | 
				
			||||||
            # an error occurred or not, we will test the existence of the
 | 
					 | 
				
			||||||
            # converted file (see below).
 | 
					 | 
				
			||||||
            os.remove(filePath)
 | 
					 | 
				
			||||||
            # Return the name of the converted file.
 | 
					 | 
				
			||||||
            baseName, ext = os.path.splitext(filePath)
 | 
					 | 
				
			||||||
            if (ext == '.%s' % format):
 | 
					 | 
				
			||||||
                filePath = '%s.res.%s' % (baseName, format)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                filePath = '%s.%s' % (baseName, format)
 | 
					 | 
				
			||||||
            if not os.path.exists(filePath):
 | 
					 | 
				
			||||||
                tool.log(CONVERSION_ERROR % (cmd, errorMessage), type='error')
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
        return filePath
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,35 +4,7 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
from appy.gen.plone25.installer import PloneInstaller as Plone25Installer
 | 
					from appy.gen.plone25.installer import PloneInstaller as Plone25Installer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ZCTextIndexInfo:
 | 
					 | 
				
			||||||
    '''Silly class used for storing information about a ZCTextIndex.'''
 | 
					 | 
				
			||||||
    lexicon_id = "plone_lexicon"
 | 
					 | 
				
			||||||
    index_type = 'Okapi BM25 Rank'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PloneInstaller(Plone25Installer):
 | 
					class PloneInstaller(Plone25Installer):
 | 
				
			||||||
    '''This Plone installer runs every time the generated Plone product is
 | 
					    '''This Plone installer runs every time the generated Plone product is
 | 
				
			||||||
       installed or uninstalled (in the Plone configuration interface).'''
 | 
					       installed or uninstalled (in the Plone configuration panel).'''
 | 
				
			||||||
    @staticmethod
 | 
					 | 
				
			||||||
    def updateIndexes(ploneSite, indexInfo, logger):
 | 
					 | 
				
			||||||
        '''This method creates or updates, in a p_ploneSite, definitions of
 | 
					 | 
				
			||||||
           indexes in its portal_catalog, based on index-related information
 | 
					 | 
				
			||||||
           given in p_indexInfo. p_indexInfo is a dictionary of the form
 | 
					 | 
				
			||||||
           {s_indexName:s_indexType}. Here are some examples of index types:
 | 
					 | 
				
			||||||
           "FieldIndex", "ZCTextIndex", "DateIndex".'''
 | 
					 | 
				
			||||||
        catalog = ploneSite.portal_catalog
 | 
					 | 
				
			||||||
        indexNames = catalog.indexes()
 | 
					 | 
				
			||||||
        for indexName, indexType in indexInfo.iteritems():
 | 
					 | 
				
			||||||
            if indexName not in indexNames:
 | 
					 | 
				
			||||||
                # We need to create this index
 | 
					 | 
				
			||||||
                if indexType != 'ZCTextIndex':
 | 
					 | 
				
			||||||
                    catalog.addIndex(indexName, indexType)
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    catalog.addIndex(indexName,indexType,extra=ZCTextIndexInfo)
 | 
					 | 
				
			||||||
                logger.info('Creating index "%s" of type "%s"...' % \
 | 
					 | 
				
			||||||
                            (indexName, indexType))
 | 
					 | 
				
			||||||
                # Indexing database content based on this index.
 | 
					 | 
				
			||||||
                catalog.reindexIndex(indexName, ploneSite.REQUEST)
 | 
					 | 
				
			||||||
                logger.info('Done.')
 | 
					 | 
				
			||||||
        # TODO: if the index already exists but has not the same type, we
 | 
					 | 
				
			||||||
        # re-create it with the same type and we reindex it.
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								gen/po.py
									
										
									
									
									
								
							
							
						
						| 
						 | 
					@ -69,6 +69,7 @@ class PoMessage:
 | 
				
			||||||
    SEARCH_AND = 'and'
 | 
					    SEARCH_AND = 'and'
 | 
				
			||||||
    WORKFLOW_COMMENT = 'Optional comment'
 | 
					    WORKFLOW_COMMENT = 'Optional comment'
 | 
				
			||||||
    WORKFLOW_STATE = 'state'
 | 
					    WORKFLOW_STATE = 'state'
 | 
				
			||||||
 | 
					    APPY_TITLE = 'Title'
 | 
				
			||||||
    DATA_CHANGE = 'Data change'
 | 
					    DATA_CHANGE = 'Data change'
 | 
				
			||||||
    MODIFIED_FIELD = 'Modified field'
 | 
					    MODIFIED_FIELD = 'Modified field'
 | 
				
			||||||
    PREVIOUS_VALUE = 'Previous value'
 | 
					    PREVIOUS_VALUE = 'Previous value'
 | 
				
			||||||
| 
						 | 
					@ -78,12 +79,13 @@ class PoMessage:
 | 
				
			||||||
    CHOOSE_A_DOC = '[ Documents ]'
 | 
					    CHOOSE_A_DOC = '[ Documents ]'
 | 
				
			||||||
    MIN_REF_VIOLATED = 'You must choose more elements here.'
 | 
					    MIN_REF_VIOLATED = 'You must choose more elements here.'
 | 
				
			||||||
    MAX_REF_VIOLATED = 'Too much elements are selected here.'
 | 
					    MAX_REF_VIOLATED = 'Too much elements are selected here.'
 | 
				
			||||||
    BAD_INT = 'An integer value is expected; do not enter any space.'
 | 
					    BAD_LONG = 'An integer value is expected; do not enter any space.'
 | 
				
			||||||
    BAD_FLOAT = 'A floating-point number is expected; use the dot as decimal ' \
 | 
					    BAD_FLOAT = 'A floating-point number is expected; use the dot as decimal ' \
 | 
				
			||||||
                'separator, not a comma; do not enter any space.'
 | 
					                'separator, not a comma; do not enter any space.'
 | 
				
			||||||
    BAD_EMAIL = 'Please enter a valid email.'
 | 
					    BAD_EMAIL = 'Please enter a valid email.'
 | 
				
			||||||
    BAD_URL = 'Please enter a valid URL.'
 | 
					    BAD_URL = 'Please enter a valid URL.'
 | 
				
			||||||
    BAD_ALPHANUMERIC = 'Please enter a valid alphanumeric value.'
 | 
					    BAD_ALPHANUMERIC = 'Please enter a valid alphanumeric value.'
 | 
				
			||||||
 | 
					    BAD_SELECT_VALUE = 'The value is not among possible values for this field.'
 | 
				
			||||||
    ACTION_OK = 'The action has been successfully executed.'
 | 
					    ACTION_OK = 'The action has been successfully executed.'
 | 
				
			||||||
    ACTION_KO = 'A problem occurred while executing the action.'
 | 
					    ACTION_KO = 'A problem occurred while executing the action.'
 | 
				
			||||||
    FRONT_PAGE_TEXT = 'Welcome to this Appy-powered Plone site.'
 | 
					    FRONT_PAGE_TEXT = 'Welcome to this Appy-powered Plone site.'
 | 
				
			||||||
| 
						 | 
					@ -103,11 +105,16 @@ class PoMessage:
 | 
				
			||||||
    CONFIRM = 'Are you sure ?'
 | 
					    CONFIRM = 'Are you sure ?'
 | 
				
			||||||
    YES = 'Yes'
 | 
					    YES = 'Yes'
 | 
				
			||||||
    NO = 'No'
 | 
					    NO = 'No'
 | 
				
			||||||
 | 
					    FIELD_REQUIRED = 'Please fill this field.'
 | 
				
			||||||
 | 
					    FILE_REQUIRED = 'Please select a file.'
 | 
				
			||||||
 | 
					    IMAGE_REQUIRED = 'The uploaded file must be an image.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, id, msg, default, fuzzy=False, comments=[]):
 | 
					    def __init__(self, id, msg, default, fuzzy=False, comments=[],
 | 
				
			||||||
 | 
					                 niceDefault=False):
 | 
				
			||||||
        self.id = id
 | 
					        self.id = id
 | 
				
			||||||
        self.msg = msg
 | 
					        self.msg = msg
 | 
				
			||||||
        self.default = default
 | 
					        self.default = default
 | 
				
			||||||
 | 
					        if niceDefault: self.produceNiceDefault()
 | 
				
			||||||
        self.fuzzy = fuzzy # True if the default value has changed in the pot
 | 
					        self.fuzzy = fuzzy # True if the default value has changed in the pot
 | 
				
			||||||
        # file: the msg in the po file needs to be translated again.
 | 
					        # file: the msg in the po file needs to be translated again.
 | 
				
			||||||
        self.comments = comments
 | 
					        self.comments = comments
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										267
									
								
								gen/utils.py
									
										
									
									
									
								
							
							
						
						| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import re
 | 
					import re, os, os.path, time
 | 
				
			||||||
 | 
					from appy.shared.utils import getOsTempFolder, normalizeString
 | 
				
			||||||
sequenceTypes = (list, tuple)
 | 
					sequenceTypes = (list, tuple)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Classes used by edit/view templates for accessing information ----------------
 | 
					# Classes used by edit/view templates for accessing information ----------------
 | 
				
			||||||
| 
						 | 
					@ -8,111 +8,100 @@ class Descr:
 | 
				
			||||||
    '''Abstract class for description classes.'''
 | 
					    '''Abstract class for description classes.'''
 | 
				
			||||||
    def get(self): return self.__dict__
 | 
					    def get(self): return self.__dict__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FieldDescr(Descr):
 | 
					 | 
				
			||||||
    def __init__(self, atField, appyType, fieldRel):
 | 
					 | 
				
			||||||
        # The corresponding Archetypes field (may be None in the case of
 | 
					 | 
				
			||||||
        # backward references)
 | 
					 | 
				
			||||||
        self.atField = atField
 | 
					 | 
				
			||||||
        # The corresponding Appy type
 | 
					 | 
				
			||||||
        self.appyType = appyType
 | 
					 | 
				
			||||||
        # The field relationship, needed when the field description is a
 | 
					 | 
				
			||||||
        # backward reference.
 | 
					 | 
				
			||||||
        self.fieldRel = fieldRel
 | 
					 | 
				
			||||||
        # Can we sort this field ?
 | 
					 | 
				
			||||||
        at = self.appyType
 | 
					 | 
				
			||||||
        self.sortable = False
 | 
					 | 
				
			||||||
        if not fieldRel and ((self.atField.getName() == 'title') or \
 | 
					 | 
				
			||||||
                             (at['indexed'])):
 | 
					 | 
				
			||||||
            self.sortable = True
 | 
					 | 
				
			||||||
        # Can we filter this field?
 | 
					 | 
				
			||||||
        self.filterable = False
 | 
					 | 
				
			||||||
        if not fieldRel and at['indexed'] and (at['type'] == 'String') and \
 | 
					 | 
				
			||||||
           (at['format'] == 0) and not at['isSelect']:
 | 
					 | 
				
			||||||
            self.filterable = True
 | 
					 | 
				
			||||||
        if fieldRel:
 | 
					 | 
				
			||||||
            self.widgetType = 'backField'
 | 
					 | 
				
			||||||
            self.group = appyType['backd']['group']
 | 
					 | 
				
			||||||
            self.show = appyType['backd']['show']
 | 
					 | 
				
			||||||
            self.page = appyType['backd']['page']
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            self.widgetType = 'field'
 | 
					 | 
				
			||||||
            self.group = appyType['group']
 | 
					 | 
				
			||||||
            self.show = appyType['show']
 | 
					 | 
				
			||||||
            self.page = appyType['page']
 | 
					 | 
				
			||||||
            fieldName = self.atField.getName()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GroupDescr(Descr):
 | 
					class GroupDescr(Descr):
 | 
				
			||||||
    def __init__(self, name, cols, page):
 | 
					    def __init__(self, group, page, metaType):
 | 
				
			||||||
        self.name = name
 | 
					        '''Creates the data structure manipulated in ZPTs from p_group, the
 | 
				
			||||||
        self.cols = cols # The nb of columns for placing fields into the group
 | 
					           Group instance used in the field definition.'''
 | 
				
			||||||
        self.rows = None # The number of rows
 | 
					        self.type = 'group'
 | 
				
			||||||
 | 
					        # All p_group attributes become self attributes.
 | 
				
			||||||
 | 
					        for name, value in group.__dict__.iteritems():
 | 
				
			||||||
 | 
					            if not name.startswith('_'):
 | 
				
			||||||
 | 
					                setattr(self, name, value)
 | 
				
			||||||
 | 
					        self.columnsWidths = [col.width for col in group.columns]
 | 
				
			||||||
 | 
					        self.columnsAligns = [col.align for col in group.columns]
 | 
				
			||||||
 | 
					        # Names of i18n labels
 | 
				
			||||||
 | 
					        self.labelId = '%s_group_%s' % (metaType, self.name)
 | 
				
			||||||
 | 
					        self.descrId = self.labelId + '_descr'
 | 
				
			||||||
 | 
					        self.helpId  = self.labelId + '_help'
 | 
				
			||||||
 | 
					        # The name of the page where the group lies
 | 
				
			||||||
        self.page = page
 | 
					        self.page = page
 | 
				
			||||||
        self.fields = []
 | 
					        # The widgets belonging to the group that the current user may see.
 | 
				
			||||||
        self.widgetType = 'group'
 | 
					        # They will be stored by m_addWidget below as a list of lists because
 | 
				
			||||||
 | 
					        # they will be rendered as a table.
 | 
				
			||||||
 | 
					        self.widgets = [[]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def computeRows(groupDict):
 | 
					    @staticmethod
 | 
				
			||||||
        '''Computes self.rows. But because at this time the object has already
 | 
					    def addWidget(groupDict, newWidget):
 | 
				
			||||||
           been converted to a dict (for being maniputated within ZPTs, this
 | 
					        '''Adds p_newWidget into p_groupDict['widgets']. We try first to add
 | 
				
			||||||
           method is a static method that takes the dict as arg.'''
 | 
					           p_newWidget into the last widget row. If it is not possible, we
 | 
				
			||||||
        groupDict['rows'] = len(groupDict['fields']) / groupDict['cols']
 | 
					           create a new row.
 | 
				
			||||||
        if len(groupDict['fields']) % groupDict['cols']:
 | 
					 | 
				
			||||||
            groupDict['rows'] += 1
 | 
					 | 
				
			||||||
    computeRows = staticmethod(computeRows)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getGroupInfo(groupName):
 | 
					           This method is a static method taking p_groupDict as first param
 | 
				
			||||||
        '''In the group name, the user may optionally specify at the end the
 | 
					           instead of being an instance method because at this time the object
 | 
				
			||||||
           number of columns for placing fields into the group. This method
 | 
					           has already been converted to a dict (for being maniputated within
 | 
				
			||||||
           returns the real group name and the number of columns.'''
 | 
					           ZPTs).'''
 | 
				
			||||||
        res = groupName.rsplit('_', 1)
 | 
					        # Get the last row
 | 
				
			||||||
        if len(res) == 1:
 | 
					        widgetRow = groupDict['widgets'][-1]
 | 
				
			||||||
            res.append(1) # Append the default numer of columns
 | 
					        numberOfColumns = len(groupDict['columnsWidths'])
 | 
				
			||||||
 | 
					        # Computes the number of columns already filled by widgetRow
 | 
				
			||||||
 | 
					        rowColumns = 0
 | 
				
			||||||
 | 
					        for widget in widgetRow: rowColumns += widget['colspan']
 | 
				
			||||||
 | 
					        freeColumns = numberOfColumns - rowColumns
 | 
				
			||||||
 | 
					        if freeColumns >= newWidget['colspan']:
 | 
				
			||||||
 | 
					            # We can add the widget in the last row.
 | 
				
			||||||
 | 
					            widgetRow.append(newWidget)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            try:
 | 
					            if freeColumns:
 | 
				
			||||||
                res[1] = int(res[1])
 | 
					                # Terminate the current row by appending empty cells
 | 
				
			||||||
            except ValueError:
 | 
					                for i in range(freeColumns): widgetRow.append('')
 | 
				
			||||||
                res[1] = 1
 | 
					            # Create a new row
 | 
				
			||||||
        return res
 | 
					            newRow = [newWidget]
 | 
				
			||||||
    getGroupInfo = staticmethod(getGroupInfo)
 | 
					            groupDict['widgets'].append(newRow)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PageDescr(Descr):
 | 
					class PageDescr(Descr):
 | 
				
			||||||
    def getPageInfo(pageOrName, pageKlass):
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def getPageInfo(pageOrName):
 | 
				
			||||||
        '''pageOrName can be:
 | 
					        '''pageOrName can be:
 | 
				
			||||||
           - a string containing the name of the page
 | 
					           - a string containing the name of the page
 | 
				
			||||||
           - a string containing <pageName>_<phaseName>
 | 
					           - a string containing <pageName>_<phaseName>
 | 
				
			||||||
           - a appy.gen.Page instance for a more detailed page description.
 | 
					           - a appy.gen.Page instance for a more detailed page description.
 | 
				
			||||||
           This method returns a normalized tuple containing page-related
 | 
					           This method returns a normalized tuple containing page-related
 | 
				
			||||||
           information.'''
 | 
					           information.'''
 | 
				
			||||||
        if isinstance(pageOrName, pageKlass):
 | 
					        if isinstance(pageOrName, basestring):
 | 
				
			||||||
            res = [pageOrName.name, pageOrName.phase, pageOrName.show]
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            res = pageOrName.rsplit('_', 1)
 | 
					            res = pageOrName.rsplit('_', 1)
 | 
				
			||||||
            if len(res) == 1:
 | 
					            if len(res) == 1:
 | 
				
			||||||
                res.append('main')
 | 
					                res.append('main')
 | 
				
			||||||
            res.append(True)
 | 
					            res.append(True)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            res = [pageOrName.name, pageOrName.phase, pageOrName.show]
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
    getPageInfo = staticmethod(getPageInfo)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PhaseDescr(Descr):
 | 
					class PhaseDescr(Descr):
 | 
				
			||||||
    def __init__(self, name, states, forPlone, ploneObj):
 | 
					    def __init__(self, name, states, obj):
 | 
				
			||||||
        self.name = name
 | 
					        self.name = name
 | 
				
			||||||
        self.states = states
 | 
					        self.states = states
 | 
				
			||||||
        self.forPlone = forPlone
 | 
					        self.obj = obj
 | 
				
			||||||
        self.ploneObj = ploneObj
 | 
					 | 
				
			||||||
        self.phaseStatus = None
 | 
					        self.phaseStatus = None
 | 
				
			||||||
        self.pages = [] # The list of pages in this phase
 | 
					        self.pages = [] # The list of pages in this phase
 | 
				
			||||||
        self.totalNbOfPhases = None
 | 
					        self.totalNbOfPhases = None
 | 
				
			||||||
 | 
					        # The following attributes allows to browse, from a given page, to the
 | 
				
			||||||
 | 
					        # last page of the previous phase and to the first page of the following
 | 
				
			||||||
 | 
					        # phase if allowed by phase state.
 | 
				
			||||||
 | 
					        self.previousPhase = None
 | 
				
			||||||
 | 
					        self.nextPhase = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def addPage(self, appyType, obj):
 | 
					    def addPage(self, appyType, obj):
 | 
				
			||||||
        toAdd = appyType['page']
 | 
					        toAdd = appyType.page
 | 
				
			||||||
        if (toAdd == 'main') and self.forPlone:
 | 
					 | 
				
			||||||
            toAdd = 'default'
 | 
					 | 
				
			||||||
        if (toAdd not in self.pages) and \
 | 
					        if (toAdd not in self.pages) and \
 | 
				
			||||||
           obj._appy_showPage(appyType['page'], appyType['pageShow']):
 | 
					           obj._appy_showPage(appyType.page, appyType.pageShow):
 | 
				
			||||||
            self.pages.append(toAdd)
 | 
					            self.pages.append(toAdd)
 | 
				
			||||||
    def computeStatus(self):
 | 
					
 | 
				
			||||||
 | 
					    def computeStatus(self, allPhases):
 | 
				
			||||||
        '''Compute status of whole phase based on individual status of states
 | 
					        '''Compute status of whole phase based on individual status of states
 | 
				
			||||||
           in this phase. If this phase includes no state, the concept of phase
 | 
					           in this phase. If this phase includes no state, the concept of phase
 | 
				
			||||||
           is simply used as a tab, and its status depends on the page currently
 | 
					           is simply used as a tab, and its status depends on the page currently
 | 
				
			||||||
           shown.'''
 | 
					           shown. This method also fills fields "previousPhase" and "nextPhase"
 | 
				
			||||||
 | 
					           if relevant, based on list of p_allPhases.'''
 | 
				
			||||||
        res = 'Current'
 | 
					        res = 'Current'
 | 
				
			||||||
        if self.states:
 | 
					        if self.states:
 | 
				
			||||||
            # Compute status base on states
 | 
					            # Compute status base on states
 | 
				
			||||||
| 
						 | 
					@ -124,17 +113,19 @@ class PhaseDescr(Descr):
 | 
				
			||||||
                        break
 | 
					                        break
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # Compute status based on current page
 | 
					            # Compute status based on current page
 | 
				
			||||||
            rq = self.ploneObj.REQUEST
 | 
					            page = self.obj.REQUEST.get('page', 'main')
 | 
				
			||||||
            if rq.has_key('fieldset'):
 | 
					            if page in self.pages:
 | 
				
			||||||
                pageName = rq['fieldset']
 | 
					 | 
				
			||||||
                if not self.forPlone and (pageName == 'default'):
 | 
					 | 
				
			||||||
                    pageName = 'main'
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                pageName = rq.get('pageName', 'main')
 | 
					 | 
				
			||||||
            if pageName in self.pages:
 | 
					 | 
				
			||||||
                res = 'Current'
 | 
					                res = 'Current'
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                res = 'Deselected'
 | 
					                res = 'Deselected'
 | 
				
			||||||
 | 
					            # Identify previous and next phases
 | 
				
			||||||
 | 
					            for phaseInfo in allPhases:
 | 
				
			||||||
 | 
					                if phaseInfo['name'] == self.name:
 | 
				
			||||||
 | 
					                    i = allPhases.index(phaseInfo)
 | 
				
			||||||
 | 
					                    if i > 0:
 | 
				
			||||||
 | 
					                        self.previousPhase = allPhases[i-1]
 | 
				
			||||||
 | 
					                    if i < (len(allPhases)-1):
 | 
				
			||||||
 | 
					                        self.nextPhase = allPhases[i+1]
 | 
				
			||||||
        self.phaseStatus = res
 | 
					        self.phaseStatus = res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StateDescr(Descr):
 | 
					class StateDescr(Descr):
 | 
				
			||||||
| 
						 | 
					@ -159,32 +150,7 @@ def produceNiceMessage(msg):
 | 
				
			||||||
    return res
 | 
					    return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ValidationErrors: pass
 | 
					class AppyObject: pass
 | 
				
			||||||
class AppyRequest:
 | 
					 | 
				
			||||||
    def __init__(self, zopeRequest, appyObj=None):
 | 
					 | 
				
			||||||
        self.zopeRequest = zopeRequest
 | 
					 | 
				
			||||||
        self.appyObj = appyObj
 | 
					 | 
				
			||||||
    def __str__(self): return '<AppyRequest object>'
 | 
					 | 
				
			||||||
    def __repr__(self): return '<AppyRequest object>'
 | 
					 | 
				
			||||||
    def __getattr__(self, attr):
 | 
					 | 
				
			||||||
        res = None
 | 
					 | 
				
			||||||
        if self.appyObj:
 | 
					 | 
				
			||||||
            # I can retrieve type information from the ploneObj.
 | 
					 | 
				
			||||||
            appyType = self.appyObj.o.getAppyType(attr)
 | 
					 | 
				
			||||||
            if appyType['type'] == 'Ref':
 | 
					 | 
				
			||||||
                res = self.zopeRequest.get('appy_ref_%s' % attr, None)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                res = self.zopeRequest.get(attr, None)
 | 
					 | 
				
			||||||
                if appyType['pythonType']:
 | 
					 | 
				
			||||||
                    try:
 | 
					 | 
				
			||||||
                        exec 'res = %s' % res # bool('False') gives True, so we
 | 
					 | 
				
			||||||
                        # can't write: res = appyType['pythonType'](res)
 | 
					 | 
				
			||||||
                    except SyntaxError, se:
 | 
					 | 
				
			||||||
                        # Can happen when for example, an Integer value is empty
 | 
					 | 
				
			||||||
                        res = None
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            res = self.zopeRequest.get(attr, None)
 | 
					 | 
				
			||||||
        return res
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class SomeObjects:
 | 
					class SomeObjects:
 | 
				
			||||||
| 
						 | 
					@ -261,4 +227,85 @@ class FakeBrain:
 | 
				
			||||||
    def pretty_title_or_id(self): return self.Title
 | 
					    def pretty_title_or_id(self): return self.Title
 | 
				
			||||||
    def getObject(self, REQUEST=None): return self
 | 
					    def getObject(self, REQUEST=None): return self
 | 
				
			||||||
    def getRID(self): return self.url
 | 
					    def getRID(self): return self.url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					CONVERSION_ERROR = 'An error occurred while executing command "%s". %s'
 | 
				
			||||||
 | 
					class FileWrapper:
 | 
				
			||||||
 | 
					    '''When you get, from an appy object, the value of a File attribute, you
 | 
				
			||||||
 | 
					       get an instance of this class.'''
 | 
				
			||||||
 | 
					    def __init__(self, atFile):
 | 
				
			||||||
 | 
					        '''This constructor is only used by Appy to create a nice File instance
 | 
				
			||||||
 | 
					           from a Plone/Zope corresponding instance (p_atFile). If you need to
 | 
				
			||||||
 | 
					           create a new file and assign it to a File attribute, use the
 | 
				
			||||||
 | 
					           attribute setter, do not create yourself an instance of this
 | 
				
			||||||
 | 
					           class.'''
 | 
				
			||||||
 | 
					        d = self.__dict__
 | 
				
			||||||
 | 
					        d['_atFile'] = atFile # Not for you!
 | 
				
			||||||
 | 
					        d['name'] = atFile.filename
 | 
				
			||||||
 | 
					        d['content'] = atFile.data
 | 
				
			||||||
 | 
					        d['mimeType'] = atFile.content_type
 | 
				
			||||||
 | 
					        d['size'] = atFile.size # In bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __setattr__(self, name, v):
 | 
				
			||||||
 | 
					        d = self.__dict__
 | 
				
			||||||
 | 
					        if name == 'name':
 | 
				
			||||||
 | 
					            self._atFile.filename = v
 | 
				
			||||||
 | 
					            d['name'] = v
 | 
				
			||||||
 | 
					        elif name == 'content':
 | 
				
			||||||
 | 
					            self._atFile.update_data(v, self.mimeType, len(v))
 | 
				
			||||||
 | 
					            d['content'] = v
 | 
				
			||||||
 | 
					            d['size'] = len(v)
 | 
				
			||||||
 | 
					        elif name == 'mimeType':
 | 
				
			||||||
 | 
					            self._atFile.content_type = self.mimeType = v
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            raise 'Impossible to set attribute %s. "Settable" attributes ' \
 | 
				
			||||||
 | 
					                  'are "name", "content" and "mimeType".' % name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dump(self, filePath=None, format=None, tool=None):
 | 
				
			||||||
 | 
					        '''Writes the file on disk. If p_filePath is specified, it is the
 | 
				
			||||||
 | 
					           path name where the file will be dumped; folders mentioned in it
 | 
				
			||||||
 | 
					           must exist. If not, the file will be dumped in the OS temp folder.
 | 
				
			||||||
 | 
					           The absolute path name of the dumped file is returned.
 | 
				
			||||||
 | 
					           If an error occurs, the method returns None. If p_format is
 | 
				
			||||||
 | 
					           specified, OpenOffice will be called for converting the dumped file
 | 
				
			||||||
 | 
					           to the desired format. In this case, p_tool, a Appy tool, must be
 | 
				
			||||||
 | 
					           provided. Indeed, any Appy tool contains parameters for contacting
 | 
				
			||||||
 | 
					           OpenOffice in server mode.'''
 | 
				
			||||||
 | 
					        if not filePath:
 | 
				
			||||||
 | 
					            filePath = '%s/file%f.%s' % (getOsTempFolder(), time.time(),
 | 
				
			||||||
 | 
					                normalizeString(self.name))
 | 
				
			||||||
 | 
					        f = file(filePath, 'w')
 | 
				
			||||||
 | 
					        if self.content.__class__.__name__ == 'Pdata':
 | 
				
			||||||
 | 
					            # The file content is splitted in several chunks.
 | 
				
			||||||
 | 
					            f.write(self.content.data)
 | 
				
			||||||
 | 
					            nextPart = self.content.next
 | 
				
			||||||
 | 
					            while nextPart:
 | 
				
			||||||
 | 
					                f.write(nextPart.data)
 | 
				
			||||||
 | 
					                nextPart = nextPart.next
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # Only one chunk
 | 
				
			||||||
 | 
					            f.write(self.content)
 | 
				
			||||||
 | 
					        f.close()
 | 
				
			||||||
 | 
					        if format:
 | 
				
			||||||
 | 
					            if not tool: return
 | 
				
			||||||
 | 
					            # Convert the dumped file using OpenOffice
 | 
				
			||||||
 | 
					            convScript = '%s/converter.py' % os.path.dirname(appy.pod.__file__)
 | 
				
			||||||
 | 
					            cmd = '%s %s "%s" %s -p%d' % (tool.unoEnabledPython, convScript,
 | 
				
			||||||
 | 
					                filePath, format, tool.openOfficePort)
 | 
				
			||||||
 | 
					            errorMessage = executeCommand(cmd)
 | 
				
			||||||
 | 
					            # Even if we have an "error" message, it could be a simple warning.
 | 
				
			||||||
 | 
					            # So we will continue here and, as a subsequent check for knowing if
 | 
				
			||||||
 | 
					            # an error occurred or not, we will test the existence of the
 | 
				
			||||||
 | 
					            # converted file (see below).
 | 
				
			||||||
 | 
					            os.remove(filePath)
 | 
				
			||||||
 | 
					            # Return the name of the converted file.
 | 
				
			||||||
 | 
					            baseName, ext = os.path.splitext(filePath)
 | 
				
			||||||
 | 
					            if (ext == '.%s' % format):
 | 
				
			||||||
 | 
					                filePath = '%s.res.%s' % (baseName, format)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                filePath = '%s.%s' % (baseName, format)
 | 
				
			||||||
 | 
					            if not os.path.exists(filePath):
 | 
				
			||||||
 | 
					                tool.log(CONVERSION_ERROR % (cmd, errorMessage), type='error')
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        return filePath
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ from appy.pod import PodError, XML_SPECIAL_CHARS
 | 
				
			||||||
from appy.pod.elements import *
 | 
					from appy.pod.elements import *
 | 
				
			||||||
from appy.pod.actions import IfAction, ElseAction, ForAction, VariableAction, \
 | 
					from appy.pod.actions import IfAction, ElseAction, ForAction, VariableAction, \
 | 
				
			||||||
                             NullAction
 | 
					                             NullAction
 | 
				
			||||||
 | 
					from appy.shared import xmlPrologue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ParsingError(Exception): pass
 | 
					class ParsingError(Exception): pass
 | 
				
			||||||
| 
						 | 
					@ -158,7 +159,7 @@ class FileBuffer(Buffer):
 | 
				
			||||||
        Buffer.__init__(self, env, None)
 | 
					        Buffer.__init__(self, env, None)
 | 
				
			||||||
        self.result = result
 | 
					        self.result = result
 | 
				
			||||||
        self.content = file(result, 'w')
 | 
					        self.content = file(result, 'w')
 | 
				
			||||||
        self.content.write('<?xml version="1.0" encoding="UTF-8"?>')
 | 
					        self.content.write(xmlPrologue)
 | 
				
			||||||
    def getLength(self): return 0
 | 
					    def getLength(self): return 0
 | 
				
			||||||
    # getLength is used to manage insertions into sub-buffers. But in the case
 | 
					    # getLength is used to manage insertions into sub-buffers. But in the case
 | 
				
			||||||
    # of a FileBuffer, we will only have 1 sub-buffer at a time, and we don't
 | 
					    # of a FileBuffer, we will only have 1 sub-buffer at a time, and we don't
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,10 @@ class DocImporter:
 | 
				
			||||||
        self.svgNs = ns[OdfEnvironment.NS_SVG]
 | 
					        self.svgNs = ns[OdfEnvironment.NS_SVG]
 | 
				
			||||||
        self.tempFolder = tempFolder
 | 
					        self.tempFolder = tempFolder
 | 
				
			||||||
        self.importFolder = self.getImportFolder()
 | 
					        self.importFolder = self.getImportFolder()
 | 
				
			||||||
 | 
					        # If the importer generates one or several images, we will retain their
 | 
				
			||||||
 | 
					        # names here, because we will need to declare them in
 | 
				
			||||||
 | 
					        # META-INF/manifest.xml
 | 
				
			||||||
 | 
					        self.fileNames = []
 | 
				
			||||||
        if self.at:
 | 
					        if self.at:
 | 
				
			||||||
            # Check that the file exists
 | 
					            # Check that the file exists
 | 
				
			||||||
            if not os.path.isfile(self.at):
 | 
					            if not os.path.isfile(self.at):
 | 
				
			||||||
| 
						 | 
					@ -142,6 +146,7 @@ class PdfImporter(DocImporter):
 | 
				
			||||||
                    self.tempFolder, self.ns)
 | 
					                    self.tempFolder, self.ns)
 | 
				
			||||||
                imgImporter.setAnchor('paragraph')
 | 
					                imgImporter.setAnchor('paragraph')
 | 
				
			||||||
                self.res += imgImporter.run()
 | 
					                self.res += imgImporter.run()
 | 
				
			||||||
 | 
					                self.fileNames += imgImporter.fileNames
 | 
				
			||||||
                os.remove(nextImage)
 | 
					                os.remove(nextImage)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                noMoreImages = True
 | 
					                noMoreImages = True
 | 
				
			||||||
| 
						 | 
					@ -214,6 +219,7 @@ class ImageImporter(DocImporter):
 | 
				
			||||||
        # Compute path to image
 | 
					        # Compute path to image
 | 
				
			||||||
        i = self.importPath.rfind('/Pictures/')
 | 
					        i = self.importPath.rfind('/Pictures/')
 | 
				
			||||||
        imagePath = self.importPath[i+1:]
 | 
					        imagePath = self.importPath[i+1:]
 | 
				
			||||||
 | 
					        self.fileNames.append(imagePath)
 | 
				
			||||||
        # Compute image size
 | 
					        # Compute image size
 | 
				
			||||||
        width, height = getSize(self.importPath, self.format)
 | 
					        width, height = getSize(self.importPath, self.format)
 | 
				
			||||||
        if width != None:
 | 
					        if width != None:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@
 | 
				
			||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,USA.
 | 
					# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,USA.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import zipfile, shutil, xml.sax, os, os.path, re
 | 
					import zipfile, shutil, xml.sax, os, os.path, re, mimetypes, time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from UserDict import UserDict
 | 
					from UserDict import UserDict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,33 +134,45 @@ class Renderer:
 | 
				
			||||||
        self.stylesManager = None # Manages the styles defined into the ODT
 | 
					        self.stylesManager = None # Manages the styles defined into the ODT
 | 
				
			||||||
        # template
 | 
					        # template
 | 
				
			||||||
        self.tempFolder = None
 | 
					        self.tempFolder = None
 | 
				
			||||||
        self.curdir = os.getcwd()
 | 
					 | 
				
			||||||
        self.env = None
 | 
					        self.env = None
 | 
				
			||||||
        self.pyPath = pythonWithUnoPath
 | 
					        self.pyPath = pythonWithUnoPath
 | 
				
			||||||
        self.ooPort = ooPort
 | 
					        self.ooPort = ooPort
 | 
				
			||||||
        self.forceOoCall = forceOoCall
 | 
					        self.forceOoCall = forceOoCall
 | 
				
			||||||
        self.finalizeFunction = finalizeFunction
 | 
					        self.finalizeFunction = finalizeFunction
 | 
				
			||||||
 | 
					        # Retain potential files or images that will be included through
 | 
				
			||||||
 | 
					        # "do ... from document" statements: we will need to declare them in
 | 
				
			||||||
 | 
					        # META-INF/manifest.xml.
 | 
				
			||||||
 | 
					        self.fileNames = []
 | 
				
			||||||
        self.prepareFolders()
 | 
					        self.prepareFolders()
 | 
				
			||||||
        # Unzip template
 | 
					        # Unzip template
 | 
				
			||||||
        self.unzipFolder = os.path.join(self.tempFolder, 'unzip')
 | 
					        self.unzipFolder = os.path.join(self.tempFolder, 'unzip')
 | 
				
			||||||
        os.mkdir(self.unzipFolder)
 | 
					        os.mkdir(self.unzipFolder)
 | 
				
			||||||
        for zippedFile in self.templateZip.namelist():
 | 
					        for zippedFile in self.templateZip.namelist():
 | 
				
			||||||
 | 
					            # Before writing the zippedFile into self.unzipFolder, create the
 | 
				
			||||||
 | 
					            # intermediary subfolder(s) if needed.
 | 
				
			||||||
 | 
					            fileName = None
 | 
				
			||||||
 | 
					            if zippedFile.endswith('/') or zippedFile.endswith(os.sep):
 | 
				
			||||||
 | 
					                # This is an empty folder. Create it nevertheless.
 | 
				
			||||||
 | 
					                os.makedirs(os.path.join(self.unzipFolder, zippedFile))
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
                fileName = os.path.basename(zippedFile)
 | 
					                fileName = os.path.basename(zippedFile)
 | 
				
			||||||
                folderName = os.path.dirname(zippedFile)
 | 
					                folderName = os.path.dirname(zippedFile)
 | 
				
			||||||
            # Create folder if needed
 | 
					 | 
				
			||||||
                fullFolderName = self.unzipFolder
 | 
					                fullFolderName = self.unzipFolder
 | 
				
			||||||
                if folderName:
 | 
					                if folderName:
 | 
				
			||||||
                    fullFolderName = os.path.join(fullFolderName, folderName)
 | 
					                    fullFolderName = os.path.join(fullFolderName, folderName)
 | 
				
			||||||
                    if not os.path.exists(fullFolderName):
 | 
					                    if not os.path.exists(fullFolderName):
 | 
				
			||||||
                        os.makedirs(fullFolderName)
 | 
					                        os.makedirs(fullFolderName)
 | 
				
			||||||
            # Unzip file
 | 
					            # Unzip the file in self.unzipFolder
 | 
				
			||||||
            if fileName:
 | 
					            if fileName:
 | 
				
			||||||
                fullFileName = os.path.join(fullFolderName, fileName)
 | 
					                fullFileName = os.path.join(fullFolderName, fileName)
 | 
				
			||||||
                f = open(fullFileName, 'wb')
 | 
					                f = open(fullFileName, 'wb')
 | 
				
			||||||
                fileContent = self.templateZip.read(zippedFile)
 | 
					                fileContent = self.templateZip.read(zippedFile)
 | 
				
			||||||
                if fileName == 'content.xml':
 | 
					                if (fileName == 'content.xml') and not folderName:
 | 
				
			||||||
 | 
					                    # content.xml files may reside in subfolders.
 | 
				
			||||||
 | 
					                    # We modify only the one in the root folder.
 | 
				
			||||||
                    self.contentXml = fileContent
 | 
					                    self.contentXml = fileContent
 | 
				
			||||||
                elif fileName == 'styles.xml':
 | 
					                elif (fileName == 'styles.xml') and not folderName:
 | 
				
			||||||
 | 
					                    # Same remark as above.
 | 
				
			||||||
                    self.stylesManager = StylesManager(fileContent)
 | 
					                    self.stylesManager = StylesManager(fileContent)
 | 
				
			||||||
                    self.stylesXml = fileContent
 | 
					                    self.stylesXml = fileContent
 | 
				
			||||||
                f.write(fileContent)
 | 
					                f.write(fileContent)
 | 
				
			||||||
| 
						 | 
					@ -268,7 +280,10 @@ class Renderer:
 | 
				
			||||||
        imp = importer(content, at, format, self.tempFolder, ns)
 | 
					        imp = importer(content, at, format, self.tempFolder, ns)
 | 
				
			||||||
        if isImage:
 | 
					        if isImage:
 | 
				
			||||||
            imp.setAnchor(anchor)
 | 
					            imp.setAnchor(anchor)
 | 
				
			||||||
        return imp.run()
 | 
					        res = imp.run()
 | 
				
			||||||
 | 
					        if imp.fileNames:
 | 
				
			||||||
 | 
					            self.fileNames += imp.fileNames
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def prepareFolders(self):
 | 
					    def prepareFolders(self):
 | 
				
			||||||
        # Check if I can write the result
 | 
					        # Check if I can write the result
 | 
				
			||||||
| 
						 | 
					@ -293,6 +308,27 @@ class Renderer:
 | 
				
			||||||
        except OSError, oe:
 | 
					        except OSError, oe:
 | 
				
			||||||
            raise PodError(CANT_WRITE_TEMP_FOLDER % (self.result, oe))
 | 
					            raise PodError(CANT_WRITE_TEMP_FOLDER % (self.result, oe))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def patchManifest(self):
 | 
				
			||||||
 | 
					        '''Declares, in META-INF/manifest.xml, images or files included via the
 | 
				
			||||||
 | 
					           "do... from document" statements if any.'''
 | 
				
			||||||
 | 
					        if self.fileNames:
 | 
				
			||||||
 | 
					            j = os.path.join
 | 
				
			||||||
 | 
					            toInsert = ''
 | 
				
			||||||
 | 
					            for fileName in self.fileNames:
 | 
				
			||||||
 | 
					                mimeType = mimetypes.guess_type(fileName)[0]
 | 
				
			||||||
 | 
					                toInsert += ' <manifest:file-entry manifest:media-type="%s" ' \
 | 
				
			||||||
 | 
					                            'manifest:full-path="%s"/>\n' % (mimeType, fileName)
 | 
				
			||||||
 | 
					            manifestName = j(self.unzipFolder, j('META-INF', 'manifest.xml'))
 | 
				
			||||||
 | 
					            f = file(manifestName)
 | 
				
			||||||
 | 
					            manifestContent = f.read()
 | 
				
			||||||
 | 
					            hook = '</manifest:manifest>'
 | 
				
			||||||
 | 
					            manifestContent = manifestContent.replace(hook, toInsert+hook)
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					            # Write the new manifest content
 | 
				
			||||||
 | 
					            f = file(manifestName, 'w')
 | 
				
			||||||
 | 
					            f.write(manifestContent)
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Public interface
 | 
					    # Public interface
 | 
				
			||||||
    def run(self):
 | 
					    def run(self):
 | 
				
			||||||
        '''Renders the result.'''
 | 
					        '''Renders the result.'''
 | 
				
			||||||
| 
						 | 
					@ -303,6 +339,8 @@ class Renderer:
 | 
				
			||||||
        self.currentParser = self.stylesParser
 | 
					        self.currentParser = self.stylesParser
 | 
				
			||||||
        # Create the resulting styles.xml
 | 
					        # Create the resulting styles.xml
 | 
				
			||||||
        self.currentParser.parse(self.stylesXml)
 | 
					        self.currentParser.parse(self.stylesXml)
 | 
				
			||||||
 | 
					        # Patch META-INF/manifest.xml
 | 
				
			||||||
 | 
					        self.patchManifest()
 | 
				
			||||||
        # Re-zip the result
 | 
					        # Re-zip the result
 | 
				
			||||||
        self.finalize()
 | 
					        self.finalize()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -397,11 +435,18 @@ class Renderer:
 | 
				
			||||||
            resultOdt = zipfile.ZipFile(resultOdtName,'w', zipfile.ZIP_DEFLATED)
 | 
					            resultOdt = zipfile.ZipFile(resultOdtName,'w', zipfile.ZIP_DEFLATED)
 | 
				
			||||||
        except RuntimeError:
 | 
					        except RuntimeError:
 | 
				
			||||||
            resultOdt = zipfile.ZipFile(resultOdtName,'w')
 | 
					            resultOdt = zipfile.ZipFile(resultOdtName,'w')
 | 
				
			||||||
        os.chdir(self.unzipFolder)
 | 
					        for dir, dirnames, filenames in os.walk(self.unzipFolder):
 | 
				
			||||||
        for dir, dirnames, filenames in os.walk('.'):
 | 
					 | 
				
			||||||
            for f in filenames:
 | 
					            for f in filenames:
 | 
				
			||||||
                resultOdt.write(os.path.join(dir, f)[2:])
 | 
					                folderName = dir[len(self.unzipFolder)+1:]
 | 
				
			||||||
                # [2:] is there to avoid havin './' in the path in the zip file.
 | 
					                resultOdt.write(os.path.join(dir, f),
 | 
				
			||||||
 | 
					                                os.path.join(folderName, f))
 | 
				
			||||||
 | 
					            if not dirnames and not filenames:
 | 
				
			||||||
 | 
					                # This is an empty leaf folder. We must create an entry in the
 | 
				
			||||||
 | 
					                # zip for him
 | 
				
			||||||
 | 
					                folderName = dir[len(self.unzipFolder):]
 | 
				
			||||||
 | 
					                zInfo = zipfile.ZipInfo("%s/" % folderName,time.localtime()[:6])
 | 
				
			||||||
 | 
					                zInfo.external_attr = 48
 | 
				
			||||||
 | 
					                resultOdt.writestr(zInfo, '')
 | 
				
			||||||
        resultOdt.close()
 | 
					        resultOdt.close()
 | 
				
			||||||
        resultType = os.path.splitext(self.result)[1]
 | 
					        resultType = os.path.splitext(self.result)[1]
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
| 
						 | 
					@ -431,6 +476,5 @@ class Renderer:
 | 
				
			||||||
                    raise PodError(CONVERT_ERROR % output)
 | 
					                    raise PodError(CONVERT_ERROR % output)
 | 
				
			||||||
                os.rename(resultName, self.result)
 | 
					                os.rename(resultName, self.result)
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            os.chdir(self.curdir)
 | 
					 | 
				
			||||||
            FolderDeleter.delete(self.tempFolder)
 | 
					            FolderDeleter.delete(self.tempFolder)
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1127
									
								
								pod/test/Tests.rtf
									
										
									
									
									
								
							
							
						
						
							
								
								
									
										5
									
								
								pod/test/contexts/Chart1.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					johnScore = 25
 | 
				
			||||||
 | 
					markScore = 53
 | 
				
			||||||
 | 
					wilsonScore = 12
 | 
				
			||||||
 | 
					meghuScore = 59
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								pod/test/results/chart1.odt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								pod/test/templates/Chart1.odt
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -18,7 +18,7 @@ mimeTypesExts = {
 | 
				
			||||||
             'image/jpeg'                             : 'jpg',
 | 
					             'image/jpeg'                             : 'jpg',
 | 
				
			||||||
             'image/gif'                              : 'gif'
 | 
					             'image/gif'                              : 'gif'
 | 
				
			||||||
             }
 | 
					             }
 | 
				
			||||||
xmlPrologue = '<?xml version="1.0" encoding="utf-8"?>'
 | 
					xmlPrologue = '<?xml version="1.0" encoding="utf-8"?>\n'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class UnmarshalledObject:
 | 
					class UnmarshalledObject:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										58
									
								
								shared/odf.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,58 @@
 | 
				
			||||||
 | 
					'''This module contains some useful classes for constructing ODF documents
 | 
				
			||||||
 | 
					   programmatically.'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class OdtTable:
 | 
				
			||||||
 | 
					    '''This class allows to construct an ODT table programmatically.'''
 | 
				
			||||||
 | 
					    # Some namespace definitions
 | 
				
			||||||
 | 
					    tns = 'table:'
 | 
				
			||||||
 | 
					    txns = 'text:'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, tableName, paraStyle, cellStyle,
 | 
				
			||||||
 | 
					                 paraHeaderStyle, cellHeaderStyle, nbOfCols):
 | 
				
			||||||
 | 
					        self.tableName = tableName
 | 
				
			||||||
 | 
					        self.paraStyle = paraStyle
 | 
				
			||||||
 | 
					        self.cellStyle = cellStyle
 | 
				
			||||||
 | 
					        self.paraHeaderStyle = paraHeaderStyle
 | 
				
			||||||
 | 
					        self.cellHeaderStyle = cellHeaderStyle
 | 
				
			||||||
 | 
					        self.nbOfCols = nbOfCols
 | 
				
			||||||
 | 
					        self.res = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dumpCell(self, content, span=1, header=False):
 | 
				
			||||||
 | 
					        if header:
 | 
				
			||||||
 | 
					            paraStyleName = self.paraHeaderStyle
 | 
				
			||||||
 | 
					            cellStyleName = self.cellHeaderStyle
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            paraStyleName = self.paraStyle
 | 
				
			||||||
 | 
					            cellStyleName = self.cellStyle
 | 
				
			||||||
 | 
					        self.res += '<%stable-cell %sstyle-name="%s" ' \
 | 
				
			||||||
 | 
					                    '%snumber-columns-spanned="%d">' % \
 | 
				
			||||||
 | 
					                    (self.tns, self.tns, cellStyleName, self.tns, span)
 | 
				
			||||||
 | 
					        self.res += '<%sp %sstyle-name="%s">%s</%sp>' % \
 | 
				
			||||||
 | 
					                    (self.txns, self.txns, paraStyleName, content, self.txns)
 | 
				
			||||||
 | 
					        self.res += '</%stable-cell>' % self.tns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def startRow(self):
 | 
				
			||||||
 | 
					        self.res += '<%stable-row>' % self.tns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def endRow(self):
 | 
				
			||||||
 | 
					        self.res += '</%stable-row>' % self.tns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def startTable(self):
 | 
				
			||||||
 | 
					        self.res += '<%stable %sname="AnalysisTable">' % (self.tns, self.tns)
 | 
				
			||||||
 | 
					        self.res += '<%stable-column %snumber-columns-repeated="%d"/>' % \
 | 
				
			||||||
 | 
					                    (self.tns, self.tns, self.nbOfCols)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def endTable(self):
 | 
				
			||||||
 | 
					        self.res += '</%stable>' % self.tns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dumpFloat(self, number):
 | 
				
			||||||
 | 
					        return str(round(number, 2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self):
 | 
				
			||||||
 | 
					        '''Returns the whole table.'''
 | 
				
			||||||
 | 
					        self.startTable()
 | 
				
			||||||
 | 
					        self.getRows()
 | 
				
			||||||
 | 
					        self.endTable()
 | 
				
			||||||
 | 
					        return self.res.decode('utf-8')
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -526,8 +526,7 @@ class XmlMarshaller:
 | 
				
			||||||
                            mustDump = True
 | 
					                            mustDump = True
 | 
				
			||||||
                    if mustDump:
 | 
					                    if mustDump:
 | 
				
			||||||
                        self.dumpField(res, fieldName, fieldValue)
 | 
					                        self.dumpField(res, fieldName, fieldValue)
 | 
				
			||||||
            elif objectType in ('archetype', 'appy'):
 | 
					            elif objectType == 'archetype':
 | 
				
			||||||
                fields = instance.schema.fields()
 | 
					 | 
				
			||||||
                for field in instance.schema.fields():
 | 
					                for field in instance.schema.fields():
 | 
				
			||||||
                    # Dump only needed fields
 | 
					                    # Dump only needed fields
 | 
				
			||||||
                    mustDump = False
 | 
					                    mustDump = False
 | 
				
			||||||
| 
						 | 
					@ -550,7 +549,21 @@ class XmlMarshaller:
 | 
				
			||||||
                            fieldType = 'ref'
 | 
					                            fieldType = 'ref'
 | 
				
			||||||
                        self.dumpField(res, field.getName(),field.get(instance),
 | 
					                        self.dumpField(res, field.getName(),field.get(instance),
 | 
				
			||||||
                                       fieldType=fieldType)
 | 
					                                       fieldType=fieldType)
 | 
				
			||||||
                if objectType == 'appy':
 | 
					            elif objectType == 'appy':
 | 
				
			||||||
 | 
					                for field in instance.getAllAppyTypes():
 | 
				
			||||||
 | 
					                    # Dump only needed fields
 | 
				
			||||||
 | 
					                    if field.name in self.fieldsToExclude: continue
 | 
				
			||||||
 | 
					                    if (field.type == 'Ref') and field.isBack: continue
 | 
				
			||||||
 | 
					                    if (type(self.fieldsToMarshall) in self.sequenceTypes) \
 | 
				
			||||||
 | 
					                        and (field.name not in self.fieldsToMarshall): continue
 | 
				
			||||||
 | 
					                    # Determine field type
 | 
				
			||||||
 | 
					                    fieldType = 'basic'
 | 
				
			||||||
 | 
					                    if field.type == 'File':
 | 
				
			||||||
 | 
					                        fieldType = 'file'
 | 
				
			||||||
 | 
					                    elif field.type == 'Ref':
 | 
				
			||||||
 | 
					                        fieldType = 'ref'
 | 
				
			||||||
 | 
					                    self.dumpField(res, field.name,field.getValue(instance),
 | 
				
			||||||
 | 
					                                   fieldType=fieldType)
 | 
				
			||||||
                # Dump the object history.
 | 
					                # Dump the object history.
 | 
				
			||||||
                res.write('<history type="list">')
 | 
					                res.write('<history type="list">')
 | 
				
			||||||
                wfInfo = instance.portal_workflow.getWorkflowsFor(instance)
 | 
					                wfInfo = instance.portal_workflow.getWorkflowsFor(instance)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||