[gen] [gen] Action field: param confirm can be 'text': in this case, the confirm popup contains a textarea whose content is passed as param to the method speficied in param 'action'. Action fields can now be defined in a new layout 'buttons' (show='buttons') in order to appear, on the view layout, besides the extsting series of buttons (edit, next/previous pages...).
This commit is contained in:
parent
960a4c6a46
commit
ccf7e44eef
|
@ -350,7 +350,7 @@ class Field:
|
|||
for r in res:
|
||||
if r == layoutType: return True
|
||||
return
|
||||
elif res in ('view', 'edit', 'result'):
|
||||
elif res in ('view', 'edit', 'result', 'buttons'):
|
||||
return res == layoutType
|
||||
return bool(res)
|
||||
|
||||
|
|
|
@ -29,18 +29,22 @@ class Action(Field):
|
|||
pxView = pxCell = Px('''
|
||||
<form var="formId='%s_%s_form' % (zobj.id, name);
|
||||
label=_(field.labelId);
|
||||
descr=field.descrId and _(field.descrId) or None;
|
||||
buttonWidth=ztool.getButtonWidth(label)"
|
||||
id=":formId" action=":ztool.absolute_url() + '/do'">
|
||||
<input type="hidden" name="action" value="ExecuteAction"/>
|
||||
<input type="hidden" name="objectUid" value=":zobj.id"/>
|
||||
<input type="hidden" name="fieldName" value=":name"/>
|
||||
<input if="field.confirm" type="button" class="button"
|
||||
var="labelConfirm=_(field.labelId + '_confirm')" value=":label"
|
||||
<input type="hidden" name="comment" value=""/>
|
||||
<input if="field.confirm" type="button" class="button" title=":descr"
|
||||
var="labelConfirm=_(field.labelId + '_confirm');
|
||||
commentParam=(field.confirm == 'text') and 'true' or 'false'"
|
||||
value=":label"
|
||||
style=":'%s; %s' % (url('action', bg=True), buttonWidth)"
|
||||
onclick=":'askConfirm(%s,%s,%s)' % (q('form'), q(formId), \
|
||||
q(labelConfirm))"/>
|
||||
onclick=":'askConfirm(%s,%s,%s,%s)' % (q('form'), q(formId), \
|
||||
q(labelConfirm), commentParam)"/>
|
||||
<input if="not field.confirm" type="submit" class="button" name="do"
|
||||
value=":label"
|
||||
value=":label" title=":descr"
|
||||
style=":'%s; %s' % (url('action', bg=True), buttonWidth)"/>
|
||||
</form>''')
|
||||
|
||||
|
@ -78,13 +82,24 @@ class Action(Field):
|
|||
|
||||
def getDefaultLayouts(self): return {'view': 'l-f', 'edit': 'lrv-f'}
|
||||
|
||||
def callAction(self, obj, method, hasParam, param):
|
||||
'''Calls p_method on p_obj. m_method can be the single action as defined
|
||||
in self.action or one of them is self.action contains several
|
||||
methods. Calling m_method can be done with a p_param (when p_hasParam
|
||||
is True), ie, when self.confirm is "text".'''
|
||||
if hasParam: return method(obj, param)
|
||||
else: return method(obj)
|
||||
|
||||
def __call__(self, obj):
|
||||
'''Calls the action on p_obj.'''
|
||||
# Must we call the method(s) with a param ?
|
||||
hasParam = self.confirm == 'text'
|
||||
param = hasParam and obj.request.get('comment', None)
|
||||
if type(self.action) in sutils.sequenceTypes:
|
||||
# There are multiple Python methods
|
||||
res = [True, '']
|
||||
for act in self.action:
|
||||
actRes = act(obj)
|
||||
actRes = self.callAction(obj, act, hasParam, param)
|
||||
if type(actRes) in sutils.sequenceTypes:
|
||||
res[0] = res[0] and actRes[0]
|
||||
if self.result.startswith('file'):
|
||||
|
@ -95,7 +110,7 @@ class Action(Field):
|
|||
res[0] = res[0] and actRes
|
||||
else:
|
||||
# There is only one Python method
|
||||
actRes = self.action(obj)
|
||||
actRes = self.callAction(obj, self.action, hasParam, param)
|
||||
if type(actRes) in sutils.sequenceTypes:
|
||||
res = list(actRes)
|
||||
else:
|
||||
|
|
|
@ -57,8 +57,8 @@ def sendMail(config, to, subject, body, attachments=None, log=None):
|
|||
else:
|
||||
msg = ''
|
||||
if log:
|
||||
log('mail disabled%s: should send mail from %s to %s.' % \
|
||||
(msg, fromAddress, str(to)))
|
||||
log('mail disabled%s: should send mail from %s to %d ' \
|
||||
'recipient(s): %s.' % (msg, fromAddress, len(to), str(to)))
|
||||
log('subject: %s' % subject)
|
||||
log('body: %s' % body)
|
||||
if attachments and log: log('%d attachment(s).' % len(attachments))
|
||||
|
|
|
@ -816,13 +816,15 @@ class BaseMixin:
|
|||
cssJs['js'] = js or ()
|
||||
return res
|
||||
|
||||
def getAppyTypes(self, layoutType, pageName):
|
||||
def getAppyTypes(self, layoutType, pageName, type=None):
|
||||
'''Returns the list of fields that belong to a given page (p_pageName)
|
||||
for a given p_layoutType. If p_pageName is None, fields of all pages
|
||||
are returned.'''
|
||||
are returned. If p_type is defined, only fields of this p_type are
|
||||
returned. '''
|
||||
res = []
|
||||
for field in self.getAllAppyTypes():
|
||||
if pageName and (field.page.name != pageName): continue
|
||||
if type and (field.type != type): continue
|
||||
if not field.isShowable(self, layoutType): continue
|
||||
res.append(field)
|
||||
return res
|
||||
|
|
|
@ -72,6 +72,7 @@ input.buttonSmall { width: 100px !important; font-size: 85%; height: 18px;
|
|||
.help { cursor: help }
|
||||
.refLink { font-style: italic; padding-left: 5px; font-size: 90%; color: grey }
|
||||
.buttons { margin-left: 4px }
|
||||
.objectButtons { margin-top: 5px }
|
||||
.message { position: absolute; top: -40px; left: 50%; font-size: 90%;
|
||||
width: 600px; border: 1px #F0C36D solid; padding: 6px;
|
||||
background-color: #F9EDBE; text-align: center; margin-left: -300px;
|
||||
|
|
|
@ -381,22 +381,19 @@ class AbstractWrapper(object):
|
|||
pxTransitions = Px('''
|
||||
<form var="transitions=targetObj.getTransitions()" if="transitions"
|
||||
var2="formId='trigger_%s' % targetObj.id" method="post"
|
||||
id=":formId" action=":targetObj.absolute_url() + '/do'">
|
||||
id=":formId" action=":targetObj.absolute_url() + '/do'"
|
||||
style="display: inline">
|
||||
<input type="hidden" name="action" value="Trigger"/>
|
||||
<input type="hidden" name="transition"/>
|
||||
<!-- Input field for storing the comment coming from the popup -->
|
||||
<textarea id="comment" name="comment" cols="30" rows="3"
|
||||
style="display:none"></textarea>
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<tr valign="middle">
|
||||
<td align=":dright" for="transition in transitions">
|
||||
<!-- Render a transition or a group of transitions. -->
|
||||
<x if="transition.type == 'transition'">:transition.pxView</x>
|
||||
<x if="transition.type == 'group'"
|
||||
var2="uiGroup=transition">:uiGroup.px</x>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<x for="transition in transitions">
|
||||
<!-- Render a transition or a group of transitions. -->
|
||||
<x if="transition.type == 'transition'">:transition.pxView</x>
|
||||
<x if="transition.type == 'group'"
|
||||
var2="uiGroup=transition">:uiGroup.px</x>
|
||||
</x>
|
||||
</form>''')
|
||||
|
||||
# Displays header information about an object: title, workflow-related info,
|
||||
|
@ -458,103 +455,107 @@ class AbstractWrapper(object):
|
|||
# Shows the range of buttons (next, previous, save,...) and the workflow
|
||||
# transitions for a given object.
|
||||
pxButtons = Px('''
|
||||
<table cellpadding="2" cellspacing="0" style="margin-top: 7px"
|
||||
var="previousPage=phaseObj.getPreviousPage(page)[0];
|
||||
nextPage=phaseObj.getNextPage(page)[0];
|
||||
isEdit=layoutType == 'edit';
|
||||
mayAct=not isEdit and zobj.mayAct();
|
||||
pageInfo=phaseObj.pagesInfo[page]">
|
||||
<tr valign="top">
|
||||
<!-- Refresh -->
|
||||
<td if="zobj.isDebug()">
|
||||
<a href=":zobj.getUrl(mode=layoutType, page=page, refresh='yes', \
|
||||
inPopup=inPopup)">
|
||||
<img title="Refresh" style="vertical-align:top" src=":url('refresh')"/>
|
||||
</a>
|
||||
</td>
|
||||
<!-- Previous -->
|
||||
<td if="previousPage and pageInfo.showPrevious"
|
||||
var2="label=_('page_previous');
|
||||
buttonWidth=ztool.getButtonWidth(label)">
|
||||
<!-- Button on the edit page -->
|
||||
<x if="isEdit">
|
||||
<input type="button" class="button" value=":label"
|
||||
onClick="submitAppyForm('previous')"
|
||||
style=":'%s; %s' % (url('previous', bg=True), buttonWidth)"/>
|
||||
<input type="hidden" name="previousPage" value=":previousPage"/>
|
||||
</x>
|
||||
<!-- Button on the view page -->
|
||||
<input if="not isEdit" type="button" class="button" value=":label"
|
||||
style=":'%s; %s' % (url('previous', bg=True), buttonWidth)"
|
||||
onclick=":'goto(%s)' % q(zobj.getUrl(page=previousPage, \
|
||||
inPopup=inPopup))"/>
|
||||
</td>
|
||||
<div class="objectButtons" style=":'float: %s' % dleft"
|
||||
var="previousPage=phaseObj.getPreviousPage(page)[0];
|
||||
nextPage=phaseObj.getNextPage(page)[0];
|
||||
isEdit=layoutType == 'edit';
|
||||
mayAct=not isEdit and zobj.mayAct();
|
||||
pageInfo=phaseObj.pagesInfo[page]">
|
||||
<!-- Refresh -->
|
||||
<a if="zobj.isDebug()"
|
||||
href=":zobj.getUrl(mode=layoutType, page=page, refresh='yes', \
|
||||
inPopup=inPopup)">
|
||||
<img title="Refresh" style="vertical-align:top" src=":url('refresh')"/>
|
||||
</a>
|
||||
<!-- Previous -->
|
||||
<x if="previousPage and pageInfo.showPrevious"
|
||||
var2="label=_('page_previous');
|
||||
buttonWidth=ztool.getButtonWidth(label)">
|
||||
<!-- Button on the edit page -->
|
||||
<x if="isEdit">
|
||||
<input type="button" class="button" value=":label"
|
||||
onClick="submitAppyForm('previous')"
|
||||
style=":'%s; %s' % (url('previous', bg=True), buttonWidth)"/>
|
||||
<input type="hidden" name="previousPage" value=":previousPage"/>
|
||||
</x>
|
||||
<!-- Button on the view page -->
|
||||
<input if="not isEdit" type="button" class="button" value=":label"
|
||||
style=":'%s; %s' % (url('previous', bg=True), buttonWidth)"
|
||||
onclick=":'goto(%s)' % q(zobj.getUrl(page=previousPage, \
|
||||
inPopup=inPopup))"/>
|
||||
</x>
|
||||
|
||||
<!-- Save -->
|
||||
<td if="isEdit and pageInfo.showSave">
|
||||
<input type="button" class="button" onClick="submitAppyForm('save')"
|
||||
var="label=_('object_save')" value=":label"
|
||||
style=":'%s; %s' % (url('save', bg=True), \
|
||||
ztool.getButtonWidth(label))" />
|
||||
</td>
|
||||
<!-- Cancel -->
|
||||
<td if="isEdit and pageInfo.showCancel">
|
||||
<input type="button" class="button" onClick="submitAppyForm('cancel')"
|
||||
var="label=_('object_cancel')" value=":label"
|
||||
style=":'%s; %s' % (url('cancel', bg=True), \
|
||||
ztool.getButtonWidth(label))"/>
|
||||
</td>
|
||||
<td if="not isEdit"
|
||||
var2="locked=zobj.isLocked(user, page);
|
||||
editable=pageInfo.showOnEdit and pageInfo.showEdit and \
|
||||
mayAct and zobj.mayEdit()">
|
||||
<!-- Save -->
|
||||
<input if="isEdit and pageInfo.showSave"
|
||||
type="button" class="button" onClick="submitAppyForm('save')"
|
||||
var2="label=_('object_save')" value=":label"
|
||||
style=":'%s; %s' % (url('save', bg=True), \
|
||||
ztool.getButtonWidth(label))" />
|
||||
|
||||
<!-- Edit -->
|
||||
<input type="button" class="button" if="editable and not locked"
|
||||
var="label=_('object_edit')" value=":label"
|
||||
style=":'%s; %s' % (url('edit', bg=True), \
|
||||
ztool.getButtonWidth(label))"
|
||||
onclick=":'goto(%s)' % q(zobj.getUrl(mode='edit', page=page, \
|
||||
inPopup=inPopup))"/>
|
||||
<!-- Cancel -->
|
||||
<input if="isEdit and pageInfo.showCancel"
|
||||
type="button" class="button" onClick="submitAppyForm('cancel')"
|
||||
var2="label=_('object_cancel')" value=":label"
|
||||
style=":'%s; %s' % (url('cancel', bg=True), \
|
||||
ztool.getButtonWidth(label))"/>
|
||||
|
||||
<!-- Locked -->
|
||||
<a if="editable and locked">
|
||||
<img style="cursor: help"
|
||||
var="lockDate=ztool.formatDate(locked[1]);
|
||||
lockMap={'user':ztool.getUserName(locked[0]), \
|
||||
'date':lockDate};
|
||||
lockMsg=_('page_locked', mapping=lockMap)"
|
||||
src=":url('lockedBig')" title=":lockMsg"/></a>
|
||||
<a if="editable and locked and user.has_role('Manager')">
|
||||
<img class="clickable" title=":_('page_unlock')"
|
||||
src=":url('unlockBig')"
|
||||
onclick=":'onUnlockPage(%s,%s)' % (q(zobj.id), q(page))"/></a>
|
||||
</td>
|
||||
<x if="not isEdit"
|
||||
var2="locked=zobj.isLocked(user, page);
|
||||
editable=pageInfo.showOnEdit and pageInfo.showEdit and \
|
||||
mayAct and zobj.mayEdit()">
|
||||
|
||||
<!-- Next -->
|
||||
<td if="nextPage and pageInfo.showNext"
|
||||
var2="label=_('page_next');
|
||||
buttonWidth=ztool.getButtonWidth(label)">
|
||||
<!-- Button on the edit page -->
|
||||
<x if="isEdit">
|
||||
<input type="button" class="button" onClick="submitAppyForm('next')"
|
||||
style=":'%s; %s' % (url('next', bg=True), buttonWidth)"
|
||||
value=":label"/>
|
||||
<input type="hidden" name="nextPage" value=":nextPage"/>
|
||||
</x>
|
||||
<!-- Button on the view page -->
|
||||
<input if="not isEdit" type="button" class="button" value=":label"
|
||||
<!-- Edit -->
|
||||
<input type="button" class="button" if="editable and not locked"
|
||||
var="label=_('object_edit')" value=":label"
|
||||
style=":'%s; %s' % (url('edit', bg=True), \
|
||||
ztool.getButtonWidth(label))"
|
||||
onclick=":'goto(%s)' % q(zobj.getUrl(mode='edit', page=page, \
|
||||
inPopup=inPopup))"/>
|
||||
|
||||
<!-- Locked -->
|
||||
<a if="editable and locked">
|
||||
<img style="cursor: help"
|
||||
var="lockDate=ztool.formatDate(locked[1]);
|
||||
lockMap={'user':ztool.getUserName(locked[0]), \
|
||||
'date':lockDate};
|
||||
lockMsg=_('page_locked', mapping=lockMap)"
|
||||
src=":url('lockedBig')" title=":lockMsg"/></a>
|
||||
<a if="editable and locked and user.has_role('Manager')">
|
||||
<img class="clickable" title=":_('page_unlock')"
|
||||
src=":url('unlockBig')"
|
||||
onclick=":'onUnlockPage(%s,%s)' % (q(zobj.id), q(page))"/></a>
|
||||
</x>
|
||||
|
||||
<!-- Next -->
|
||||
<x if="nextPage and pageInfo.showNext"
|
||||
var2="label=_('page_next');
|
||||
buttonWidth=ztool.getButtonWidth(label)">
|
||||
<!-- Button on the edit page -->
|
||||
<x if="isEdit">
|
||||
<input type="button" class="button" onClick="submitAppyForm('next')"
|
||||
style=":'%s; %s' % (url('next', bg=True), buttonWidth)"
|
||||
onclick=":'goto(%s)' % q(zobj.getUrl(page=nextPage, \
|
||||
inPopup=inPopup))"/>
|
||||
</td>
|
||||
value=":label"/>
|
||||
<input type="hidden" name="nextPage" value=":nextPage"/>
|
||||
</x>
|
||||
<!-- Button on the view page -->
|
||||
<input if="not isEdit" type="button" class="button" value=":label"
|
||||
style=":'%s; %s' % (url('next', bg=True), buttonWidth)"
|
||||
onclick=":'goto(%s)' % q(zobj.getUrl(page=nextPage, \
|
||||
inPopup=inPopup))"/>
|
||||
</x>
|
||||
|
||||
<!-- Workflow transitions -->
|
||||
<td var="targetObj=zobj; buttonsMode='normal'"
|
||||
if="mayAct and \
|
||||
targetObj.showTransitions(layoutType)">:obj.pxTransitions</td>
|
||||
</tr>
|
||||
</table>''')
|
||||
<!-- Workflow transitions -->
|
||||
<x var="targetObj=zobj; buttonsMode='normal'"
|
||||
if="mayAct and \
|
||||
targetObj.showTransitions(layoutType)">:obj.pxTransitions</x>
|
||||
</div>
|
||||
<!-- Fields (actions) defined with layout "buttons" -->
|
||||
<x if="layoutType != 'edit'">
|
||||
<div class="objectButtons" style=":'float: %s' % dleft"
|
||||
var="fields=zobj.getAppyTypes('buttons', page, type='Action');
|
||||
layoutType='view'" if="fields">
|
||||
<x for="field in fields">:field.pxRender</x></div>
|
||||
</x>''')
|
||||
|
||||
# Displays the fields of a given page for a given object.
|
||||
pxFields = Px('''
|
||||
|
@ -1199,4 +1200,28 @@ class AbstractWrapper(object):
|
|||
return localRoles
|
||||
|
||||
def raiseUnauthorized(self, msg=None): return self.o.raiseUnauthorized(msg)
|
||||
|
||||
def sendMailIf(self, privilege, subject, body, attachments=None,
|
||||
isRole=False):
|
||||
'''Sends a mail related to this object to any active user having
|
||||
p_privilege on it. If p_isRole is False, p_privilege is a permission.
|
||||
Else, it is a role.'''
|
||||
# Determine the list of recipients based on active users having
|
||||
# p_privilege on p_self.
|
||||
recipients = []
|
||||
for user in self.tool.users:
|
||||
if (user.state == 'inactive'): continue
|
||||
# Check if the user has p_privilege on this object
|
||||
hasPrivilege = isRole and user.has_role or user.has_permission
|
||||
if not hasPrivilege(privilege, self): continue
|
||||
# Get the mail recipient for this user
|
||||
recipient = user.getMailRecipient()
|
||||
if not recipient: continue
|
||||
recipients.append(recipient)
|
||||
if recipients:
|
||||
self.tool.sendMail(recipients, subject, body, attachments)
|
||||
else:
|
||||
name = isRole and 'role' or 'permission'
|
||||
self.log('no recipient for sending mail about %s with %s %s.' % \
|
||||
(self.id, name, privilege))
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue