Allowed to express layouts in a more concise manner and various graphical improvements.
This commit is contained in:
parent
eb52c1bb7d
commit
0b4f6e1f79
104
gen/__init__.py
104
gen/__init__.py
|
@ -31,7 +31,8 @@ class Group:
|
|||
'''Used for describing a group of widgets within a page.'''
|
||||
def __init__(self, name, columns=['100%'], wide=True, style='fieldset',
|
||||
hasLabel=True, hasDescr=False, hasHelp=False,
|
||||
hasHeaders=False, group=None, colspan=1, valign='top'):
|
||||
hasHeaders=False, group=None, colspan=1, align='center',
|
||||
valign='top'):
|
||||
self.name = name
|
||||
# In its simpler form, field "columns" below can hold a list or tuple
|
||||
# of column widths expressed as strings, that will be given as is in
|
||||
|
@ -66,6 +67,7 @@ class Group:
|
|||
# If the group is rendered into another group, we can specify the number
|
||||
# of columns that this group will span.
|
||||
self.colspan = colspan
|
||||
self.align = align
|
||||
self.valign = valign
|
||||
if style == 'tabs':
|
||||
# Group content will be rendered as tabs. In this case, some
|
||||
|
@ -351,26 +353,7 @@ class Type:
|
|||
self.type = self.__class__.__name__
|
||||
self.pythonType = None # The True corresponding Python type
|
||||
# Get the layouts. Consult layout.py for more info about layouts.
|
||||
areDefaultLayouts = False
|
||||
if not layouts:
|
||||
# Get the default layouts as defined by the subclass
|
||||
areDefaultLayouts = True
|
||||
layouts = self.getDefaultLayouts()
|
||||
if not layouts:
|
||||
# Get the global default layouts
|
||||
layouts = copy.deepcopy(defaultFieldLayouts)
|
||||
else:
|
||||
layouts = copy.deepcopy(layouts)
|
||||
# We make copies of layouts, because every layout can be different,
|
||||
# even if the user decides to reuse one from one field to another.
|
||||
# This is because we modify every layout for adding
|
||||
# master/slave-related info, focus-related info, etc, which can be
|
||||
# different from one field to the other.
|
||||
# Express the layouts in a standardized way.
|
||||
self.layouts = self.formatLayouts(layouts, areDefaultLayouts)
|
||||
self.hasLabel = self.hasLayoutElement('l')
|
||||
self.hasDescr = self.hasLayoutElement('d')
|
||||
self.hasHelp = self.hasLayoutElement('h')
|
||||
self.layouts = self.formatLayouts(layouts)
|
||||
# Can we filter this field?
|
||||
self.filterable = False
|
||||
# Can this field have values that can be edited and validated?
|
||||
|
@ -451,21 +434,57 @@ class Type:
|
|||
else:
|
||||
res = self.show
|
||||
# Take into account possible values 'view' and 'edit' for 'show' param.
|
||||
if (res == 'view' and isEdit) or (res == 'edit' and not isEdit):
|
||||
res = False
|
||||
if res == 'view':
|
||||
if isEdit: res = False
|
||||
else: res = True
|
||||
elif res == 'edit':
|
||||
if isEdit: res = True
|
||||
else: res = False
|
||||
return res
|
||||
|
||||
def formatLayouts(self, layouts, areDefault):
|
||||
'''Standardizes the given dict of p_layouts. p_areDefault is True if
|
||||
p_layouts are the global default layouts or a subclass-specific set
|
||||
of default layouts.'''
|
||||
# Create a Table instance for every simple layout string.
|
||||
def showPage(self, obj):
|
||||
'''Must the page where this field lies be shown ? "Show value" can be
|
||||
True, False or 'view' (page is available only in "view" mode).'''
|
||||
if callable(self.pageShow):
|
||||
return self.pageShow(obj.appy())
|
||||
else:
|
||||
return self.pageShow
|
||||
|
||||
def formatLayouts(self, layouts):
|
||||
'''Standardizes the given p_layouts. .'''
|
||||
# First, get the layouts as a dictionary, if p_layouts is None or
|
||||
# expressed as a simple string.
|
||||
areDefault = False
|
||||
if not layouts:
|
||||
# Get the default layouts as defined by the subclass
|
||||
areDefault = True
|
||||
layouts = self.getDefaultLayouts()
|
||||
if not layouts:
|
||||
# Get the global default layouts
|
||||
layouts = copy.deepcopy(defaultFieldLayouts)
|
||||
else:
|
||||
if isinstance(layouts, basestring) or isinstance(layouts, Table):
|
||||
# The user specified a single layoutString (the "edit" one)
|
||||
layouts = {'edit': layouts}
|
||||
else:
|
||||
layouts = copy.deepcopy(layouts)
|
||||
# Here, we make a copy of the layouts, because every layout can
|
||||
# be different, even if the user decides to reuse one from one
|
||||
# field to another. This is because we modify every layout for
|
||||
# adding master/slave-related info, focus-related info, etc,
|
||||
# which can be different from one field to the other.
|
||||
# We have now a dict of layouts in p_layouts. Ensure now that a Table
|
||||
# instance is created for every layout (=value from the dict). Indeed,
|
||||
# a layout could have been expressed as a simple layout string.
|
||||
for layoutType in layouts.iterkeys():
|
||||
if isinstance(layouts[layoutType], basestring):
|
||||
layouts[layoutType] = Table(layouts[layoutType])
|
||||
# Create the "cell" layout if not specified.
|
||||
# Create the "view" layout from the "edit" layout if not specified
|
||||
if 'view' not in layouts:
|
||||
layouts['view'] = Table(other=layouts['edit'], derivedType='view')
|
||||
# Create the "cell" layout from the 'view' layout if not specified.
|
||||
if 'cell' not in layouts:
|
||||
layouts['cell'] = Table('f')
|
||||
layouts['cell'] = Table(other=layouts['view'], derivedType='cell')
|
||||
# Put the required CSS classes in the layouts
|
||||
layouts['cell'].addCssClasses('no-style-table')
|
||||
if self.master:
|
||||
|
@ -473,7 +492,12 @@ class Type:
|
|||
# allowing to show/hide, in Javascript, its widget according to
|
||||
# master value.
|
||||
classes = 'slave_%s' % self.master.id
|
||||
classes += ' slaveValue_%s_%s' % (self.master.id, self.masterValue)
|
||||
if type(self.masterValue) not in sequenceTypes:
|
||||
masterValues = [self.masterValue]
|
||||
else:
|
||||
masterValues = self.masterValue
|
||||
for masterValue in masterValues:
|
||||
classes += ' slaveValue_%s_%s' % (self.master.id, masterValue)
|
||||
layouts['view'].addCssClasses(classes)
|
||||
layouts['edit'].addCssClasses(classes)
|
||||
if self.focus:
|
||||
|
@ -489,17 +513,21 @@ class Type:
|
|||
if not self.required:
|
||||
for layoutType in layouts.iterkeys():
|
||||
layouts[layoutType].removeElement('r')
|
||||
# Derive some boolean values from the layouts.
|
||||
self.hasLabel = self.hasLayoutElement('l', layouts)
|
||||
self.hasDescr = self.hasLayoutElement('d', layouts)
|
||||
self.hasHelp = self.hasLayoutElement('h', layouts)
|
||||
# Store Table instance's dicts instead of instances: this way, they can
|
||||
# be manipulated in ZPTs.
|
||||
for layoutType in layouts.iterkeys():
|
||||
layouts[layoutType] = layouts[layoutType].get()
|
||||
return layouts
|
||||
|
||||
def hasLayoutElement(self, element):
|
||||
def hasLayoutElement(self, element, layouts):
|
||||
'''This method returns True if the given layout p_element can be found
|
||||
at least once among the various p_layouts defined for this field.'''
|
||||
for layout in self.layouts.itervalues():
|
||||
if element in layout['layoutString']: return True
|
||||
for layout in layouts.itervalues():
|
||||
if element in layout.layoutString: return True
|
||||
return False
|
||||
|
||||
def getDefaultLayouts(self):
|
||||
|
@ -1161,14 +1189,16 @@ class Ref(Type):
|
|||
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
||||
|
||||
def isShowable(self, obj, layoutType):
|
||||
res = Type.isShowable(self, obj, layout)
|
||||
res = Type.isShowable(self, obj, layoutType)
|
||||
if not res: return res
|
||||
# We add here specific Ref rules for preventing to show the field under
|
||||
# some inappropriate circumstances.
|
||||
if (layoutType == 'edit') and self.add: return False
|
||||
if self.isBack:
|
||||
if layoutType == 'edit': return False
|
||||
else:
|
||||
return obj.getBRefs(self.relationship)
|
||||
return True
|
||||
return res
|
||||
|
||||
def getValue(self, obj):
|
||||
if self.isBack:
|
||||
|
@ -1622,6 +1652,6 @@ class Config:
|
|||
# ------------------------------------------------------------------------------
|
||||
# Special field "type" is mandatory for every class. If one class does not
|
||||
# define it, we will add a copy of the instance defined below.
|
||||
title = String(multiplicity=(1,1), indexed=True, show='edit')
|
||||
title = String(multiplicity=(1,1), show='edit')
|
||||
title.init('title', None, 'appy')
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -118,21 +118,47 @@ class Row(LayoutElement):
|
|||
# ------------------------------------------------------------------------------
|
||||
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
|
||||
simpleParams = ('style', 'css_class', 'cellpadding', 'cellspacing', 'width',
|
||||
'align')
|
||||
derivedRepls = {'view': 'hrv', 'cell': 'l'}
|
||||
def __init__(self, layoutString=None, style=None, css_class='',
|
||||
cellpadding=0, cellspacing=0, width='100%', align='left',
|
||||
other=None, derivedType=None):
|
||||
if other:
|
||||
# We need to create a Table instance from another Table instance,
|
||||
# given in p_other. In this case, we ignore previous params.
|
||||
if derivedType != None:
|
||||
# We will not simply clone p_other. If p_derivedType is:
|
||||
# - "view", p_derivedFrom is an "edit" layout, and we must
|
||||
# create the corresponding "view" layout;
|
||||
# - "cell", p_derivedFrom is a "view" layout, and we must
|
||||
# create the corresponding "cell" layout;
|
||||
self.layoutString = Table.deriveLayout(other.layoutString,
|
||||
derivedType)
|
||||
else:
|
||||
self.layoutString = layoutString
|
||||
source = 'other.'
|
||||
else:
|
||||
source = ''
|
||||
self.layoutString = layoutString
|
||||
# Initialise simple params, either from the true params, either from
|
||||
# the p_other Table instance.
|
||||
for param in Table.simpleParams:
|
||||
exec 'self.%s = %s%s' % (param, source, param)
|
||||
# The following attribute will store a special Row instance used for
|
||||
# defining column properties.
|
||||
self.headerRow = None
|
||||
# The content rows are stored hereafter.
|
||||
# The content rows will be stored hereafter.
|
||||
self.rows = []
|
||||
self.layoutString = layoutString
|
||||
self.decodeRows(layoutString)
|
||||
self.decodeRows(self.layoutString)
|
||||
|
||||
@staticmethod
|
||||
def deriveLayout(layout, derivedType):
|
||||
'''Returns a layout derived from p_layout.'''
|
||||
res = layout
|
||||
for letter in Table.derivedRepls[derivedType]:
|
||||
res = res.replace(letter, '')
|
||||
return res
|
||||
|
||||
def addCssClasses(self, css_class):
|
||||
'''Adds a single or a group of p_css_class.'''
|
||||
|
@ -186,5 +212,5 @@ class Table(LayoutElement):
|
|||
# ------------------------------------------------------------------------------
|
||||
defaultPageLayouts = {
|
||||
'view': Table('m;-s|-n!-w|-b|'), 'edit': Table('m;-w|-b|')}
|
||||
defaultFieldLayouts = {'view': 'l;f!', 'edit': 'lrv;f!'}
|
||||
defaultFieldLayouts = {'edit': 'lrv;f!'}
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -652,6 +652,7 @@ class Generator(AbstractGenerator):
|
|||
Flavour._appy_addImportRelatedFields(classDescr)
|
||||
Flavour._appy_addWorkflowFields(self.flavour)
|
||||
Flavour._appy_addWorkflowFields(self.podTemplate)
|
||||
Flavour._appy_addWorkflowFields(self.user)
|
||||
# Complete self.flavour.orderedAttributes from the attributes that we
|
||||
# just added to the Flavour model class.
|
||||
for fieldName in Flavour._appy_attributes:
|
||||
|
|
|
@ -139,7 +139,15 @@ class PloneInstaller:
|
|||
site.invokeFactory(self.appyFolderType, self.productName,
|
||||
title=self.productName)
|
||||
getattr(site.portal_types, self.appyFolderType).global_allow = 0
|
||||
appFolder = getattr(site, self.productName)
|
||||
# Manager has been granted Add permissions for all root classes.
|
||||
# This may not be desired, so remove this.
|
||||
appFolder = getattr(site, self.productName)
|
||||
for className in self.config.rootClasses:
|
||||
permission = self.getAddPermission(className)
|
||||
print 'Permission is', permission
|
||||
appFolder.manage_permission(permission, (), acquire=0)
|
||||
else:
|
||||
appFolder = getattr(site, self.productName)
|
||||
# All roles defined as creators should be able to create the
|
||||
# corresponding root content types in this folder.
|
||||
i = -1
|
||||
|
|
|
@ -46,6 +46,7 @@ class AbstractMixin:
|
|||
appyType.store(obj, value)
|
||||
if created:
|
||||
# Now we have a title for the object, so we derive a nice id
|
||||
obj.unmarkCreationFlag()
|
||||
obj._renameAfterCreation(check_auto_id=True)
|
||||
if previousData:
|
||||
# Keep in history potential changes on historized fields
|
||||
|
@ -181,31 +182,45 @@ class AbstractMixin:
|
|||
obj.plone_utils.addPortalMessage(msg)
|
||||
return self.goto('%s/skyn/view' % obj.absolute_url(), True)
|
||||
if rq.get('buttonPrevious.x', None):
|
||||
# Go to the previous page (edit mode) for this object.
|
||||
# Go to the previous page for this object.
|
||||
# We recompute the list of phases and pages because things
|
||||
# may have changed since the object has been updated (ie,
|
||||
# additional pages may be shown or hidden now, so the next and
|
||||
# previous pages may have changed).
|
||||
# previous pages may have changed). Moreover, previous and next
|
||||
# pages may not be available in "edit" mode, so we return the edit
|
||||
# or view pages depending on page.show.
|
||||
currentPage = rq.get('page')
|
||||
phaseInfo = self.getAppyPhases(page=currentPage)
|
||||
previousPage = self.getPreviousPage(phaseInfo, currentPage)
|
||||
previousPage, show = self.getPreviousPage(phaseInfo, currentPage)
|
||||
if previousPage:
|
||||
rq.set('page', previousPage)
|
||||
return obj.skyn.edit(obj)
|
||||
# Return the edit or view page?
|
||||
if show != 'view':
|
||||
rq.set('page', previousPage)
|
||||
return obj.skyn.edit(obj)
|
||||
else:
|
||||
urlBack = '%s/skyn/view?page=%s' % (obj.absolute_url(),
|
||||
previousPage)
|
||||
return self.goto(urlBack)
|
||||
else:
|
||||
obj.plone_utils.addPortalMessage(msg)
|
||||
return self.goto('%s/skyn/view' % obj.absolute_url(), True)
|
||||
return self.goto('%s/skyn/view' % obj.absolute_url())
|
||||
if rq.get('buttonNext.x', None):
|
||||
# Go to the next page (edit mode) for this object
|
||||
# Go to the next page for this object
|
||||
currentPage = rq.get('page')
|
||||
phaseInfo = self.getAppyPhases(page=currentPage)
|
||||
nextPage = self.getNextPage(phaseInfo, currentPage)
|
||||
nextPage, show = self.getNextPage(phaseInfo, currentPage)
|
||||
if nextPage:
|
||||
rq.set('page', nextPage)
|
||||
return obj.skyn.edit(obj)
|
||||
# Return the edit or view page?
|
||||
if show != 'view':
|
||||
rq.set('page', nextPage)
|
||||
return obj.skyn.edit(obj)
|
||||
else:
|
||||
urlBack = '%s/skyn/view?page=%s' % (obj.absolute_url(),
|
||||
nextPage)
|
||||
return self.goto(urlBack)
|
||||
else:
|
||||
obj.plone_utils.addPortalMessage(msg)
|
||||
return self.goto('%s/skyn/view' % obj.absolute_url(), True)
|
||||
return self.goto('%s/skyn/view' % obj.absolute_url())
|
||||
return obj.skyn.edit(obj)
|
||||
|
||||
def onDelete(self):
|
||||
|
@ -575,28 +590,36 @@ class AbstractMixin:
|
|||
pageIndex = phase['pages'].index(page)
|
||||
if pageIndex > 0:
|
||||
# We stay on the same phase, previous page
|
||||
return phase['pages'][pageIndex-1]
|
||||
res = phase['pages'][pageIndex-1]
|
||||
show = phase['pageShows'][res]
|
||||
return res, show
|
||||
else:
|
||||
if phase['previousPhase']:
|
||||
# We go to the last page of previous phase
|
||||
previousPhase = phase['previousPhase']
|
||||
return previousPhase['pages'][-1]
|
||||
res = previousPhase['pages'][-1]
|
||||
show = previousPhase['pageShows'][res]
|
||||
return res, show
|
||||
else:
|
||||
return None
|
||||
return None, None
|
||||
|
||||
def getNextPage(self, phase, page):
|
||||
'''Returns the page that follows p_page which is in p_phase.'''
|
||||
pageIndex = phase['pages'].index(page)
|
||||
if pageIndex < len(phase['pages'])-1:
|
||||
# We stay on the same phase, next page
|
||||
return phase['pages'][pageIndex+1]
|
||||
res = phase['pages'][pageIndex+1]
|
||||
show = phase['pageShows'][res]
|
||||
return res, show
|
||||
else:
|
||||
if phase['nextPhase']:
|
||||
# We go to the first page of next phase
|
||||
nextPhase = phase['nextPhase']
|
||||
return nextPhase['pages'][0]
|
||||
res = nextPhase['pages'][0]
|
||||
show = nextPhase['pageShows'][res]
|
||||
return res, show
|
||||
else:
|
||||
return None
|
||||
return None, None
|
||||
|
||||
def changeRefOrder(self, fieldName, objectUid, newIndex, isDelta):
|
||||
'''This method changes the position of object with uid p_objectUid in
|
||||
|
@ -873,12 +896,6 @@ class AbstractMixin:
|
|||
res = [o.appy() for o in objs]
|
||||
return res
|
||||
|
||||
def _appy_showPage(self, page, pageShow):
|
||||
'''Must I show p_page?'''
|
||||
if callable(pageShow):
|
||||
return pageShow(self.appy())
|
||||
else: return pageShow
|
||||
|
||||
def _appy_showState(self, workflow, stateShow):
|
||||
'''Must I show a state whose "show value" is p_stateShow?'''
|
||||
if callable(stateShow):
|
||||
|
|
|
@ -78,7 +78,7 @@ class User(ModelClass):
|
|||
firstName = String(**gm)
|
||||
def showLogin(self): pass
|
||||
def validateLogin(self): pass
|
||||
login = String(show=showLogin, validator=validateLogin, **gm)
|
||||
login = String(show=showLogin, validator=validateLogin, indexed=True, **gm)
|
||||
def showPassword(self): pass
|
||||
def validatePassword(self): pass
|
||||
password1 = String(format=String.PASSWORD, show=showPassword,
|
||||
|
@ -142,7 +142,7 @@ class Flavour(ModelClass):
|
|||
res.group = copy.copy(appyType.group)
|
||||
res.phase = 'main'
|
||||
# Set default layouts for all Flavour fields
|
||||
res.layouts = None
|
||||
res.layouts = res.formatLayouts(None)
|
||||
res.specificReadPermission = False
|
||||
res.specificWritePermission = False
|
||||
res.multiplicity = (0, appyType.multiplicity[1])
|
||||
|
|
|
@ -651,8 +651,8 @@
|
|||
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);
|
||||
tal:define="previousPage python: contextObj.getPreviousPage(phaseInfo, page)[0];
|
||||
nextPage python: contextObj.getNextPage(phaseInfo, page)[0];
|
||||
isEdit python: layoutType == 'edit';">
|
||||
<br/>
|
||||
<tal:previousButton condition="previousPage">
|
||||
|
@ -682,7 +682,7 @@
|
|||
tal:attributes="src string:$portal_url/skyn/cancel.png"/>
|
||||
</tal:cancelButton>
|
||||
|
||||
<tal:editLink condition="not:isEdit">
|
||||
<tal:editLink condition="python: not isEdit and (phaseInfo['pageShows'][page] != 'view')">
|
||||
<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"
|
||||
|
|
|
@ -153,19 +153,20 @@
|
|||
<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%">
|
||||
cellspacing="1" cellpadding="2" 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: (len(phases) > 1) and ('appyPhase step%s' % phase['phaseStatus']) or 'appyPhase'">
|
||||
<span class="portletGroup" tal:condition="python: len(phases) > 1">
|
||||
<div 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>
|
||||
</div>
|
||||
<div class="portletMenu">
|
||||
<table width="100%" cellpadding="0" cellspacing="0"
|
||||
tal:condition="python: len(phase['pages']) > 1">
|
||||
<tr tal:repeat="aPage phase/pages" valign="top">
|
||||
|
@ -184,6 +185,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tal:comment replace="nothing">The down arrow pointing to the next phase (if any)</tal:comment>
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
<tal:comment replace="nothing">First row: the tabs.</tal:comment>
|
||||
<tr valign="middle"><td style="border-bottom: 1px solid #ff8040">
|
||||
<table cellpadding="0" cellspacing="0" style="position:relative; bottom:-1px;">
|
||||
<tr valign="bottom">
|
||||
<tr valign="middle">
|
||||
<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;
|
||||
|
@ -134,12 +134,13 @@
|
|||
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%', '')">
|
||||
<table metal:define-macro="groupContent"
|
||||
tal:attributes="width python: test(widget['wide'], '100%', '');
|
||||
align widget/align">
|
||||
<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">
|
||||
class widget/style" align="left">
|
||||
<span tal:replace="structure python: contextObj.translate(widget['labelId'])"/>
|
||||
<tal:help condition="widget/hasHelp">
|
||||
<metal:call use-macro="portal/skyn/widgets/show/macros/help"/>
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
border-left: 1px solid #8cacbb;
|
||||
border-right: 1px solid #8cacbb;
|
||||
}
|
||||
.portletGroup {
|
||||
font-size: 85%;
|
||||
padding-left: 0.7em;
|
||||
}
|
||||
|
||||
/* Stylesheet with Internet Explorer-specific workarounds. */
|
||||
* html #portal-columns {
|
||||
|
|
|
@ -6,7 +6,7 @@ textarea { width: 99%; }
|
|||
|
||||
#portal-breadcrumbs { display: none; }
|
||||
#importedElem { color: grey; font-style: italic; }
|
||||
label { font-weight: bold; font-style: italic; }
|
||||
label { font-weight: bold; font-style: italic; line-height: 1.4em;}
|
||||
.discreet { font-size: 94%; }
|
||||
.appyList { line-height: 1.1em; margin: 0 0 0.5em 1.2em; padding: 0; }
|
||||
.appyBullet { margin: 0; }
|
||||
|
@ -26,7 +26,7 @@ label { font-weight: bold; font-style: italic; }
|
|||
.appyPhase {
|
||||
border-style: dashed;
|
||||
border-width: thin;
|
||||
padding: 0 0.1em 0 1em;
|
||||
padding: 0 0.6em 0 1em;
|
||||
}
|
||||
|
||||
.appyState {
|
||||
|
@ -68,14 +68,14 @@ label { font-weight: bold; font-style: italic; }
|
|||
background-color: #cde2a7;
|
||||
background-image: url(&dtml-portal_url;/skyn/done.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: -1px 4px;
|
||||
background-position: -1px 7px;
|
||||
}
|
||||
|
||||
.stepCurrent {
|
||||
background-color: #eef3f5;
|
||||
background-image: url(&dtml-portal_url;/skyn/current.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: -1px 4px;
|
||||
background-position: -1px 7px;
|
||||
}
|
||||
|
||||
.stepFuture {
|
||||
|
@ -224,11 +224,13 @@ th {
|
|||
font-variant: small-caps;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
margin: 0.3em 0 0.3em 0;
|
||||
}
|
||||
.portletSep { border-top: 1px dashed #8cacbb; }
|
||||
.portletGroupItem { padding-left: 0.8em; font-style: italic; }
|
||||
.portletPageItem { font-style: italic; }
|
||||
.portletCurrent { font-weight: bold; }
|
||||
.portletMenu { margin-bottom: 0.4em; }
|
||||
|
||||
div.appyGrey {
|
||||
display: none;
|
||||
|
|
|
@ -63,6 +63,9 @@ class UserWrapper(AbstractWrapper):
|
|||
# Perform updates on the corresponding Plone user
|
||||
ploneUser = self.o.portal_membership.getMemberById(self.login)
|
||||
ploneUser.setMemberProperties({'fullname': self.title})
|
||||
# This object must be owned by its Plone user
|
||||
if 'Owner' not in self.o.get_local_roles_for_userid(self.login):
|
||||
self.o.manage_addLocalRoles(self.login, ('Owner',))
|
||||
# Change group membership according to self.roles. Indeed, instead of
|
||||
# granting roles directly to the user, we will add the user to a
|
||||
# Appy-created group having this role.
|
||||
|
|
11
gen/utils.py
11
gen/utils.py
|
@ -83,6 +83,9 @@ class PhaseDescr(Descr):
|
|||
self.obj = obj
|
||||
self.phaseStatus = None
|
||||
self.pages = [] # The list of pages in this phase
|
||||
# Below, a dict of "show" values (True, False or 'view') for every page
|
||||
# in self.pages.
|
||||
self.pageShows = {}
|
||||
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
|
||||
|
@ -92,9 +95,11 @@ class PhaseDescr(Descr):
|
|||
|
||||
def addPage(self, appyType, obj):
|
||||
toAdd = appyType.page
|
||||
if (toAdd not in self.pages) and \
|
||||
obj._appy_showPage(appyType.page, appyType.pageShow):
|
||||
self.pages.append(toAdd)
|
||||
if toAdd not in self.pages:
|
||||
showValue = appyType.showPage(obj)
|
||||
if showValue:
|
||||
self.pages.append(toAdd)
|
||||
self.pageShows[toAdd] = showValue
|
||||
|
||||
def computeStatus(self, allPhases):
|
||||
'''Compute status of whole phase based on individual status of states
|
||||
|
|
Loading…
Reference in a new issue