[gen] Class.popup: finalized the development of 'popup' classes.

This commit is contained in:
Gaetan Delannay 2014-06-16 00:58:45 +02:00
parent ef68bb420b
commit e11e754305
11 changed files with 286 additions and 121 deletions

View file

@ -307,7 +307,7 @@ class File(Field):
size=":field.width"/> size=":field.width"/>
<script var="isDisabled=not value and 'false' or 'true'" <script var="isDisabled=not value and 'false' or 'true'"
type="text/javascript">:'document.getElementById(%s).disabled=%s'%\ type="text/javascript">:'document.getElementById(%s).disabled=%s'%\
(q(fName), q(isDisabled))</script></x>''') (fName, isDisabled)</script></x>''')
pxSearch = '' pxSearch = ''

View file

@ -33,12 +33,13 @@ class Phase:
class=":(aPage == page) and 'currentPage' or ''"> class=":(aPage == page) and 'currentPage' or ''">
<!-- First line: page name and icons --> <!-- First line: page name and icons -->
<span if="not (singlePhase and singlePage)"> <span if="not (singlePhase and singlePage)">
<a href=":zobj.getUrl(page=aPage)">::aPageInfo.page.getLabel(zobj)</a> <a href=":zobj.getUrl(page=aPage, \
inPopup=inPopup)">::aPageInfo.page.getLabel(zobj)</a>
<x var="locked=zobj.isLocked(user, aPage); <x var="locked=zobj.isLocked(user, aPage);
editable=mayEdit and aPageInfo.showOnEdit and \ editable=mayEdit and aPageInfo.showOnEdit and \
aPageInfo.showEdit"> aPageInfo.showEdit">
<a if="editable and not locked" <a if="editable and not locked"
href=":zobj.getUrl(mode='edit', page=aPage)"> href=":zobj.getUrl(mode='edit', page=aPage, inPopup=inPopup)">
<img src=":url('edit')" title=":_('object_edit')"/></a> <img src=":url('edit')" title=":_('object_edit')"/></a>
<a if="editable and locked"> <a if="editable and locked">
<img style="cursor: help" <img style="cursor: help"

View file

@ -35,8 +35,7 @@ class Ref(Field):
# reach the consult view for this object. If we are on a back reference, the # reach the consult view for this object. If we are on a back reference, the
# link allows to reach the correct page where the forward reference is # link allows to reach the correct page where the forward reference is
# defined. If we are on a forward reference, the "nav" parameter is added to # defined. If we are on a forward reference, the "nav" parameter is added to
# the URL for allowing to navigate from one object to the next/previous on # the URL for allowing to navigate from one object to the next/previous one.
# ui/view.
pxObjectTitle = Px(''' pxObjectTitle = Px('''
<x var="includeShownInfo=includeShownInfo|False; <x var="includeShownInfo=includeShownInfo|False;
navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \ navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
@ -45,12 +44,14 @@ class Ref(Field):
cssClass=tied.o.getCssFor('title')"> cssClass=tied.o.getCssFor('title')">
<x>::tied.o.getSupTitle(navInfo)</x> <x>::tied.o.getSupTitle(navInfo)</x>
<a var="pageName=field.isBack and field.back.pageName or 'main'; <a var="pageName=field.isBack and field.back.pageName or 'main';
fullUrl=tied.o.getUrl(page=pageName, nav=navInfo)" linkInPopup=inPopup or (target.target != '_self');
href=":fullUrl" class=":cssClass">:(not includeShownInfo) and \ fullUrl=tied.o.getUrl(page=pageName, nav=navInfo, \
inPopup=linkInPopup)"
href=":fullUrl" class=":cssClass" target=":target.target"
onclick=":target.openPopup">:(not includeShownInfo) and \
tied.title or field.getReferenceLabel(tied) tied.title or field.getReferenceLabel(tied)
</a><span name="subTitle" style=":showSubTitles and 'display:inline' or \ </a><span name="subTitle" style=":showSubTitles and 'display:inline' or \
'display:none'">::tied.o.getSubTitle()</span> 'display:none'">::tied.o.getSubTitle()</span></x>''')
</x>''')
# This PX displays buttons for triggering global actions on several linked # This PX displays buttons for triggering global actions on several linked
# objects (delete many, unlink many,...) # objects (delete many, unlink many,...)
@ -84,7 +85,8 @@ class Ref(Field):
<table class="noStyle"> <table class="noStyle">
<tr> <tr>
<!-- Arrows for moving objects up or down --> <!-- Arrows for moving objects up or down -->
<td if="(totalNumber &gt;1) and changeOrder and not inPickList" <td if="(totalNumber &gt;1) and changeOrder and not inPickList \
and not inMenu"
var2="ajaxBaseCall=navBaseCall.replace('**v**','%s,%s,{%s:%s,%s:%s}'%\ var2="ajaxBaseCall=navBaseCall.replace('**v**','%s,%s,{%s:%s,%s:%s}'%\
(q(startNumber), q('doChangeOrder'), q('refObjectUid'), (q(startNumber), q('doChangeOrder'), q('refObjectUid'),
q(tiedUid), q('move'), q('**v**')))"> q(tiedUid), q('move'), q('**v**')))">
@ -108,8 +110,11 @@ class Ref(Field):
<!-- Edit --> <!-- Edit -->
<td if="not field.noForm and tied.o.mayEdit()"> <td if="not field.noForm and tied.o.mayEdit()">
<a var="navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \ <a var="navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
field.pageName, loop.tied.nb + 1 + startNumber, totalNumber)" field.pageName, loop.tied.nb + 1 + startNumber, totalNumber);
href=":tied.o.getUrl(mode='edit', page='main', nav=navInfo)"> linkInPopup=inPopup or (target.target != '_self')"
href=":tied.o.getUrl(mode='edit', page='main', nav=navInfo, \
inPopup=linkInPopup)"
target=":target.target" onclick=":target.openPopup">
<img src=":url('edit')" title=":_('object_edit')"/></a> <img src=":url('edit')" title=":_('object_edit')"/></a>
</td> </td>
<!-- Delete --> <!-- Delete -->
@ -140,24 +145,27 @@ class Ref(Field):
# Displays the button allowing to add a new object through a Ref field, if # Displays the button allowing to add a new object through a Ref field, if
# it has been declared as addable and if multiplicities allow it. # it has been declared as addable and if multiplicities allow it.
pxAdd = Px(''' pxAdd = Px('''
<input if="mayAdd and not inPickList" type="button" <form if="mayAdd and not inPickList"
class="buttonSmall button" class=":inMenu and 'addFormMenu' or 'addForm'"
var2="navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \ var2="formName='%s_%s_add' % (zobj.id, field.name)"
field.pageName, 0, totalNumber); name=":formName" id=":formName" target=":target.target"
formCall='goto(%s)' % \ action=":'%s/do' % folder.absolute_url()">
q('%s/do?action=Create&amp;className=%s&amp;nav=%s' % \ <input type="hidden" name="action" value="Create"/>
(folder.absolute_url(), tiedClassName, navInfo)); <input type="hidden" name="className" value=":tiedClassName"/>
formCall=not field.addConfirm and formCall or \ <input type="hidden" name="nav"
'askConfirm(%s,%s,%s)' % (q('script'), q(formCall), \ value=":'ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
q(addConfirmMsg)); field.pageName, 0, totalNumber)"/>
noFormCall=navBaseCall.replace('**v**', \ <input type="hidden" name="popup"
'%d,%s' % (startNumber, q('doCreateWithoutForm'))); value=":(inPopup or (target.target != '_self')) and '1' or '0'"/>
noFormCall=not field.addConfirm and noFormCall or \ <input
'askConfirm(%s, %s, %s)' % (q('script'), q(noFormCall), \ type=":(field.addConfirm or field.noForm) and 'button' or 'submit'"
q(addConfirmMsg)); class="buttonSmall button"
label=_('add_ref')" var="label=_('add_ref')" value=":label"
style=":'%s; %s' % (url('add', bg=True), ztool.getButtonWidth(label))" style=":'%s; %s' % (url('add', bg=True), \
value=":label" onclick=":field.noForm and noFormCall or formCall"/>''') ztool.getButtonWidth(label))"
onclick=":field.getOnAdd(q, formName, addConfirmMsg, target, \
navBaseCall, startNumber)"/>
</form>''')
# This PX displays, in a cell header from a ref table, icons for sorting the # This PX displays, in a cell header from a ref table, icons for sorting the
# ref field according to the field that corresponds to this column. # ref field according to the field that corresponds to this column.
@ -309,39 +317,60 @@ class Ref(Field):
req.get('showSubTitles', 'true') == 'true'; req.get('showSubTitles', 'true') == 'true';
subLabel='selectable_objects'">:field.pxViewList</x>''') subLabel='selectable_objects'">:field.pxViewList</x>''')
# PX that displays referred objects as menus. # PX that displays referred objects as dropdown menus.
pxMenu = Px('''
<img if="menu.icon" src=":menu.icon" title=":menu.text"/><x
if="not menu.icon">:menu.text</x>
<!-- Nb of objects in the menu -->
<x>:len(menu.objects)</x>''')
pxViewMenus = Px(''' pxViewMenus = Px('''
<div if="objects" <x var2="dtc='display: table-cell'; inMenu=True">
for="menu in field.getLinkedObjectsByMenu(obj, objects)" <!-- No object is present -->
var2="dtc='display: table-cell'" <div if="not objects" style=":'padding-left: 3px; %s' % dtc"
class="discreet">-</div>
<!-- One menu for every object type -->
<div for="menu in field.getLinkedObjectsByMenu(obj, objects)"
style=":not loop.menu.last and ('%s;padding-right:4px') % dtc or dtc"> style=":not loop.menu.last and ('%s;padding-right:4px') % dtc or dtc">
<div class="dropdownMenu"
<!-- A single object in the menu: show a clickable icon to get it --> var2="dropdownId='%s_%s_%d' % (zobj.id, name, loop.menu.nb);
<a if="len(menu.objects) == 1" var2="tied=menu.objects[0]" singleObject=len(menu.objects) == 1"
class="dropdownMenu" href=":field.getMenuUrl(zobj, tied)"
title=":tied.title">
<img if="menu.icon" src=":menu.icon"/><x
if="not menu.icon">:menu.text</x> 1</a>
<!-- Several objects: put them in a dropdown menu -->
<div if="len(menu.objects) &gt; 1" class="dropdownMenu"
var2="dropdownId='%s_%s_%d' % (zobj.id, name, loop.menu.nb)"
onmouseover=":'toggleDropdown(%s)' % q(dropdownId)" onmouseover=":'toggleDropdown(%s)' % q(dropdownId)"
onmouseout=":'toggleDropdown(%s,%s)' % (q(dropdownId), q('none'))"> onmouseout=":'toggleDropdown(%s,%s)' % (q(dropdownId), q('none'))">
<img if="menu.icon" src=":menu.icon" title=":menu.text"/><x
if="not menu.icon">:menu.text</x> <!-- The menu name and/or icon, that is clickable if there is a single
<!-- Display the number of objects in the menu (if more than one) --> object in the menu. -->
<x if="len(menu.objects) &gt; 1">:len(menu.objects)</x> <x if="singleObject" var2="tied=menu.objects[0]">
<!-- The dropdown menu containing annexes --> <a if="field.menuUrlMethod" class="dropdownMenu"
href=":field.getMenuUrl(zobj, tied)"
title=":tied.title">:field.pxMenu</a>
<a if="not field.menuUrlMethod" class="dropdownMenu"
var2="linkInPopup=inPopup or (target.target != '_self')"
target=":target.target" onclick=":target.openPopup"
href=":tied.o.getUrl(nav='',inPopup=linkInPopup)"
title=":tied.title">:field.pxMenu</a>
</x>
<x if="not singleObject">:field.pxMenu</x>
<!-- The dropdown menu containing tied objects -->
<div id=":dropdownId" class="dropdown" style="width:150px"> <div id=":dropdownId" class="dropdown" style="width:150px">
<div for="tied in menu.objects" <div for="tied in menu.objects"
class=":not loop.tied.first and 'refMenuItem' or ''" var2="startNumber=0;
var2="tiedUrl=field.getMenuUrl(zobj, tied)"> totalNumber=len(menu.objects);
<a href=":tiedUrl">:tied.title</a> tiedUid=tied.uid"
class=":not loop.tied.first and 'refMenuItem' or ''">
<!-- A specific link may have to be computed from
field.menuUrlMethod -->
<a if="field.menuUrlMethod"
href=":field.getMenuUrl(zobj, tied)">:tied.title</a>
<!-- Show standard pxObjectTitle else -->
<x if="not field.menuUrlMethod">:field.pxObjectTitle</x>
<div if="tied.o.mayAct()">:field.pxObjectActions</div>
</div> </div>
</div> </div>
</div> </div>
</div>''') </div><x>:field.pxAdd</x></x> ''')
# Simplified widget showing minimal info about tied objects. # Simplified widget showing minimal info about tied objects.
pxViewMinimal = Px(''' pxViewMinimal = Px('''
@ -359,6 +388,7 @@ class Ref(Field):
linkList=field.link == 'list'; linkList=field.link == 'list';
renderAll=req.get('scope') != 'objs'; renderAll=req.get('scope') != 'objs';
inPickList=False; inPickList=False;
inMenu=False;
startNumber=field.getStartNumber(render, req, ajaxHookId); startNumber=field.getStartNumber(render, req, ajaxHookId);
info=field.getValue(zobj,startNumber=startNumber,someObjects=True); info=field.getValue(zobj,startNumber=startNumber,someObjects=True);
objects=info.objects; objects=info.objects;
@ -368,6 +398,7 @@ class Ref(Field):
batchNumber=len(objects); batchNumber=len(objects);
folder=zobj.getCreateFolder(); folder=zobj.getCreateFolder();
tiedClassName=ztool.getPortalType(field.klass); tiedClassName=ztool.getPortalType(field.klass);
target=ztool.getLinksTargetInfo(field.klass);
mayEdit=not field.isBack and zobj.mayEdit(field.writePermission); mayEdit=not field.isBack and zobj.mayEdit(field.writePermission);
mayUnlink=mayEdit and field.getAttribute(zobj, 'unlink'); mayUnlink=mayEdit and field.getAttribute(zobj, 'unlink');
mayAdd=mayEdit and field.mayAdd(zobj, checkMayEdit=False); mayAdd=mayEdit and field.mayAdd(zobj, checkMayEdit=False);
@ -729,6 +760,7 @@ class Ref(Field):
def getLinkedObjectsByMenu(self, obj, objects): def getLinkedObjectsByMenu(self, obj, objects):
'''This method groups p_objects into sub-lists of objects, grouped by '''This method groups p_objects into sub-lists of objects, grouped by
menu (happens when self.render == 'menus').''' menu (happens when self.render == 'menus').'''
if not objects: return ()
res = [] res = []
# We store in "menuIds" the already encountered menus: # We store in "menuIds" the already encountered menus:
# ~{s_menuId : i_indexInRes}~ # ~{s_menuId : i_indexInRes}~
@ -948,6 +980,29 @@ class Ref(Field):
obj.raiseUnauthorized("User can't write Ref field '%s' (%s)." % \ obj.raiseUnauthorized("User can't write Ref field '%s' (%s)." % \
(self.name, may.msg)) (self.name, may.msg))
def getOnAdd(self, q, formName, addConfirmMsg, target, navBaseCall,
startNumber):
'''Computes the JS code to execute when button "add" is clicked.'''
if self.noForm:
# Ajax-refresh the Ref with a special param to link a newly created
# object.
res = navBaseCall.replace('**v**',
"%d,'doCreateWithoutForm'" % startNumber)
if self.addConfirm:
res = "askConfirm('script', %s, %s)" % \
(q(res, False), q(addConfirmMsg))
else:
# In the basic case, no JS code is executed: target.openPopup is
# empty and the button-related form is submitted in the main page.
res = target.openPopup
if self.addConfirm and not target.openPopup:
res = "askConfirm('form','%s',%s)" % (formName,q(addConfirmMsg))
elif self.addConfirm and target.openPopup:
res = "askConfirm('form+script',%s,%s)" % \
(q(formName + '+' + target.openPopup, False), \
q(addConfirmMsg))
return res
def getCbJsInit(self, obj): def getCbJsInit(self, obj):
'''When checkboxes are enabled, this method defines a JS associative '''When checkboxes are enabled, this method defines a JS associative
array (named "_appy_objs_cbs") that will store checkboxes' statuses. array (named "_appy_objs_cbs") that will store checkboxes' statuses.

View file

@ -416,10 +416,11 @@ class ToolMixin(BaseMixin):
sub-lists of p_sub elements.''' sub-lists of p_sub elements.'''
return sutils.splitList(l, sub) return sutils.splitList(l, sub)
def quote(self, s): def quote(self, s, escapeWithEntity=True):
'''Returns the quoted version of p_s.''' '''Returns the quoted version of p_s.'''
if not isinstance(s, basestring): s = str(s) if not isinstance(s, basestring): s = str(s)
s = s.replace('\r\n', '').replace('\n', '').replace("'", "&apos;") repl = escapeWithEntity and '&apos;' or "\\'"
s = s.replace('\r\n', '').replace('\n', '').replace("'", repl)
return "'%s'" % s return "'%s'" % s
def getLayoutType(self): def getLayoutType(self):
@ -789,7 +790,7 @@ class ToolMixin(BaseMixin):
startNumber += batchSize startNumber += batchSize
return startNumber return startNumber
def getNavigationInfo(self): def getNavigationInfo(self, inPopup=False):
'''Extracts navigation information from request/nav and returns an '''Extracts navigation information from request/nav and returns an
object with the info that a page can use for displaying object object with the info that a page can use for displaying object
navigation.''' navigation.'''
@ -841,7 +842,7 @@ class ToolMixin(BaseMixin):
uids = getattr(masterObj, fieldName) uids = getattr(masterObj, fieldName)
# Display the reference widget at the page where the current object # Display the reference widget at the page where the current object
# lies. # lies.
startNumberKey = '%s%s_startNumber' % (masterObj.UID(), fieldName) startNumberKey = '%s%s_startNumber' % (masterObj.id, fieldName)
startNumber = self.computeStartNumberFrom(res.currentNumber-1, startNumber = self.computeStartNumberFrom(res.currentNumber-1,
res.totalNumber, batchSize) res.totalNumber, batchSize)
res.sourceUrl = masterObj.getUrl(**{startNumberKey:startNumber, res.sourceUrl = masterObj.getUrl(**{startNumberKey:startNumber,
@ -895,7 +896,7 @@ class ToolMixin(BaseMixin):
sibling = brain.getObject() sibling = brain.getObject()
setattr(res, urlKey, sibling.getUrl(\ setattr(res, urlKey, sibling.getUrl(\
nav=newNav % (index + 1), nav=newNav % (index + 1),
page=rq.get('page', 'main'))) page=rq.get('page', 'main'), inPopup=inPopup))
return res return res
def getGroupedSearchFields(self, searchInfo): def getGroupedSearchFields(self, searchInfo):
@ -1368,4 +1369,30 @@ class ToolMixin(BaseMixin):
# Set a minimum width for small labels. # Set a minimum width for small labels.
if len(label) < 15: return 'width:130px' if len(label) < 15: return 'width:130px'
return 'padding-left: 26px; padding-right: 8px' return 'padding-left: 26px; padding-right: 8px'
def getLinksTargetInfo(self, klass):
'''Appy allows to open links to view or edit instances of p_klass
either via the same browser window, or via a popup. This method
returns info about that, as an object having 2 attributes:
- target is "_self" if the link leads to the same browser window,
"appyIFrame" if the link must be opened in a popup;
- openPopup is unused if target is "_self" and contains the
Javascript code to open the popup.'''
res = Object(target='_self', openPopup='')
if hasattr(klass, 'popup'):
res.target = 'appyIFrame'
d = klass.popup
if isinstance(d, basestring):
# Width only
params = int(d[:-2])
else:
# Width and height
params = "%s, %s" % (d[0][:-2], d[1][:-2])
res.openPopup = "openPopup('iframePopup',null,%s)" % params
return res
def backFromPopup(self):
'''Returns the PX allowing to close the iframe popup and refresh the
base page.'''
return self.appy().pxBack({'ztool': self})
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View file

@ -196,7 +196,8 @@ class BaseMixin:
className = rq.get('className') className = rq.get('className')
# Create the params to add to the URL we will redirect the user to # Create the params to add to the URL we will redirect the user to
# create the object. # create the object.
urlParams = {'mode':'edit', 'page':'main', 'nav':''} urlParams = {'mode':'edit', 'page':'main', 'nav':'',
'inPopup':rq.get('popup') == '1'}
initiator, initiatorPage, initiatorField = self.getInitiatorInfo() initiator, initiatorPage, initiatorField = self.getInitiatorInfo()
if initiator: if initiator:
# The object to create will be linked to an initiator object through # The object to create will be linked to an initiator object through
@ -379,12 +380,15 @@ class BaseMixin:
tool = self.getTool() tool = self.getTool()
errorMessage = self.translate('validation_error') errorMessage = self.translate('validation_error')
isNew = self.isTemporary() isNew = self.isTemporary()
inPopup = rq.get('popup') == '1'
# If this object is created from an initiator, get info about him. # If this object is created from an initiator, get info about him.
initiator, initiatorPage, initiatorField = self.getInitiatorInfo() initiator, initiatorPage, initiatorField = self.getInitiatorInfo()
# If the user clicked on 'Cancel', go back to the previous page. # If the user clicked on 'Cancel', go back to the previous page.
buttonClicked = rq.get('button') buttonClicked = rq.get('button')
if buttonClicked == 'cancel': if buttonClicked == 'cancel':
if initiator: if inPopup:
back = tool.backFromPopup()
elif initiator:
# Go back to the initiator page. # Go back to the initiator page.
urlBack = initiator.getUrl(page=initiatorPage, nav='') urlBack = initiator.getUrl(page=initiatorPage, nav='')
else: else:
@ -395,6 +399,7 @@ class BaseMixin:
urlBack = self.getUrl() urlBack = self.getUrl()
self.say(self.translate('object_canceled')) self.say(self.translate('object_canceled'))
self.removeLock(rq['page']) self.removeLock(rq['page'])
if inPopup: return back
return self.goto(urlBack) return self.goto(urlBack)
# Object for storing validation errors # Object for storing validation errors
@ -433,18 +438,18 @@ class BaseMixin:
if not msg: msg = self.translate('object_saved') if not msg: msg = self.translate('object_saved')
# If the object has already been deleted (ie, it is a kind of transient # If the object has already been deleted (ie, it is a kind of transient
# object like a one-shot form and has already been deleted in method # object like a one-shot form and has already been deleted in method
# onEdit), redirect to the main site page. # onEdit) or if the user can't access the object anymore, redirect him
if not getattr(obj.getParentNode().aq_base, obj.id, None): # to the user's home page.
return self.goto(tool.getSiteUrl(), msg) if not getattr(obj.getParentNode().aq_base, obj.id, None) or \
# If the user can't access the object anymore, redirect him to its home not obj.mayView():
# page. if inPopup: return tool.backFromPopup()
if not obj.mayView(): return self.goto(tool.getHomePage(), msg) return self.goto(tool.getHomePage(), msg)
if (buttonClicked == 'save') or saveConfirmed: if (buttonClicked == 'save') or saveConfirmed:
obj.say(msg) obj.say(msg)
if inPopup: return tool.backFromPopup()
if isNew and initiator: if isNew and initiator:
return self.goto(initiator.getUrl(page=initiatorPage, nav='')) return self.goto(initiator.getUrl(page=initiatorPage, nav=''))
else: return self.goto(obj.getUrl())
return self.goto(obj.getUrl())
if buttonClicked == 'previous': if buttonClicked == 'previous':
# Go to the previous page for this object. # Go to the previous page for this object.
# We recompute the list of phases and pages because things # We recompute the list of phases and pages because things
@ -462,29 +467,30 @@ class BaseMixin:
# I do not use gotoEdit here because I really need to # I do not use gotoEdit here because I really need to
# redirect the user to the edit page. Indeed, the object # redirect the user to the edit page. Indeed, the object
# edit URL may have moved from temp_folder to another place. # edit URL may have moved from temp_folder to another place.
return self.goto(obj.getUrl(mode='edit', page=pageName)) return self.goto(obj.getUrl(mode='edit', page=pageName,
inPopup=inPopup))
else: else:
return self.goto(obj.getUrl(page=pageName)) return self.goto(obj.getUrl(page=pageName, inPopup=inPopup))
else: else:
obj.say(msg) obj.say(msg)
return self.goto(obj.getUrl()) return self.goto(obj.getUrl(inPopup=inPopup))
if buttonClicked == 'next': if buttonClicked == 'next':
# Go to the next page for this object. # Go to the next page for this object.
# We remember page name, because the next method may set a new # We remember page name, because the next method may set a new
# current page if the current one is not visible anymore. # current page if the current one is not visible anymore.
pageName = rq['page']
phaseObj = self.getAppyPhases(currentOnly=True, layoutType='edit') phaseObj = self.getAppyPhases(currentOnly=True, layoutType='edit')
pageName, pageInfo = phaseObj.getNextPage(pageName) pageName, pageInfo = phaseObj.getNextPage(rq['page'])
if pageName: if pageName:
# Return to the edit or view page? # Return to the edit or view page?
if pageInfo.showOnEdit: if pageInfo.showOnEdit:
# Same remark as above (click on "previous"). # Same remark as above (click on "previous").
return self.goto(obj.getUrl(mode='edit', page=pageName)) return self.goto(obj.getUrl(mode='edit', page=pageName,
inPopup=inPopup))
else: else:
return self.goto(obj.getUrl(page=pageName)) return self.goto(obj.getUrl(page=pageName, inPopup=inPopup))
else: else:
obj.say(msg) obj.say(msg)
return self.goto(obj.getUrl()) return self.goto(obj.getUrl(inPopup=inPopup))
return obj.gotoEdit() return obj.gotoEdit()
def reindex(self, indexes=None, unindex=False): def reindex(self, indexes=None, unindex=False):
@ -1326,11 +1332,15 @@ class BaseMixin:
return layoutType in showValue return layoutType in showValue
getUrlDefaults = {'page':True, 'nav':True} getUrlDefaults = {'page':True, 'nav':True}
def getUrl(self, base=None, mode='view', **kwargs): def getUrl(self, base=None, mode='view', inPopup=False, **kwargs):
'''Returns an URL for this object. '''Returns an URL for this object.
* If p_base is None, it will be the base URL for this object * If p_base is None, it will be the base URL for this object
(ie, Zope self.absolute_url()). (ie, Zope self.absolute_url()).
* p_mode can be "edit", "view" or "raw" (a non-param, base URL) * p_mode can be "edit", "view" or "raw" (a non-param, base URL)
* If p_inPopup is True, the link will be opened in the Appy iframe.
An additional param "popup=1" will be added to URL params, in order
to tell Appy that the link target will be shown in a popup, in a
minimalistic way (no portlet...).
* p_kwargs can store additional parameters to add to the URL. * p_kwargs can store additional parameters to add to the URL.
In this dict, every value that is a string will be added to the In this dict, every value that is a string will be added to the
URL as-is. Every value that is True will be replaced by the value URL as-is. Every value that is True will be replaced by the value
@ -1355,6 +1365,7 @@ class BaseMixin:
if not kwargs: kwargs = self.getUrlDefaults if not kwargs: kwargs = self.getUrlDefaults
if 'page' not in kwargs: kwargs['page'] = True if 'page' not in kwargs: kwargs['page'] = True
if 'nav' not in kwargs: kwargs['nav'] = True if 'nav' not in kwargs: kwargs['nav'] = True
kwargs['popup'] = inPopup and '1' or '0'
# Create URL parameters from kwargs # Create URL parameters from kwargs
params = [] params = []
for name, value in kwargs.iteritems(): for name, value in kwargs.iteritems():
@ -1392,18 +1403,19 @@ class BaseMixin:
return False return False
if parent.meta_type not in ('Folder', 'Temporary Folder'): return parent if parent.meta_type not in ('Folder', 'Temporary Folder'): return parent
def getBreadCrumb(self): def getBreadCrumb(self, inPopup=False):
'''Gets breadcrumb info about this object and its parents (if it must '''Gets breadcrumb info about this object and its parents (if it must
be shown).''' be shown).'''
# Return an empty breadcrumb if it must not be shown. # Return an empty breadcrumb if it must not be shown.
klass = self.getClass() klass = self.getClass()
if hasattr(klass, 'breadcrumb') and not klass.breadcrumb: return () if hasattr(klass, 'breadcrumb') and not klass.breadcrumb: return ()
# Compute the breadcrumb # Compute the breadcrumb
res = [Object(url=self.absolute_url(), res = [Object(url=self.getUrl(inPopup=inPopup),
title=self.getFieldValue('title', layoutType='view'))] title=self.getFieldValue('title', layoutType='view'))]
# In a popup: limit the breadcrumb to the current object.
if inPopup: return res
parent = self.getParent() parent = self.getParent()
if parent: if parent: res = parent.getBreadCrumb() + res
res = parent.getBreadCrumb() + res
return res return res
def index_html(self): def index_html(self):

View file

@ -714,3 +714,7 @@ msgstr ""
#. Default: "You are not allowed to consult this." #. Default: "You are not allowed to consult this."
msgid "unauthorized" msgid "unauthorized"
msgstr "" msgstr ""
#. Default: "Close"
msgid "window_close"
msgstr ""

View file

@ -62,7 +62,7 @@ input.button { color: #666666; height: 20px; margin-bottom: 5px;
background-color: white; background-repeat: no-repeat; background-color: white; background-repeat: no-repeat;
background-position: 8px 25%; box-shadow: 2px 2px 2px #888888} background-position: 8px 25%; box-shadow: 2px 2px 2px #888888}
input.buttonSmall { width: 100px !important; font-size: 85%; height: 18px; input.buttonSmall { width: 100px !important; font-size: 85%; height: 18px;
margin-bottom: 3px} margin-bottom: 3px }
.fake { background-color: #e6e6e6 !important ; cursor:help !important } .fake { background-color: #e6e6e6 !important ; cursor:help !important }
.xhtml { background-color: white; padding: 6px; font-size: 95% } .xhtml { background-color: white; padding: 6px; font-size: 95% }
.xhtml img { margin-right: 5px } .xhtml img { margin-right: 5px }
@ -74,6 +74,7 @@ input.buttonSmall { width: 100px !important; font-size: 85%; height: 18px;
width: 600px; border: 1px #F0C36D solid; padding: 6px; width: 600px; border: 1px #F0C36D solid; padding: 6px;
background-color: #F9EDBE; text-align: center; margin-left: -300px; background-color: #F9EDBE; text-align: center; margin-left: -300px;
border-radius: 2px 2px 2px 2px; box-shadow: 0 2px 4px #A9A9A9 } border-radius: 2px 2px 2px 2px; box-shadow: 0 2px 4px #A9A9A9 }
.messagePopup { width: 80%; top: 0; left: 0; margin-left: 10px }
.focus { font-size: 90%; margin: 7px 0 7px 0; padding: 7px; .focus { font-size: 90%; margin: 7px 0 7px 0; padding: 7px;
background-color: #d7dee4; border-radius: 2px 2px 2px 2px; background-color: #d7dee4; border-radius: 2px 2px 2px 2px;
box-shadow: 0 2px 4px #A9A9A9 } box-shadow: 0 2px 4px #A9A9A9 }
@ -101,6 +102,8 @@ td.search { padding-top: 8px }
font-weight: normal; text-align: left; z-index: 2 } font-weight: normal; text-align: left; z-index: 2 }
.dropdownMenu { cursor: pointer; font-size: 93%; position: relative } .dropdownMenu { cursor: pointer; font-size: 93%; position: relative }
.dropdown a:hover { text-decoration: underline } .dropdown a:hover { text-decoration: underline }
.addForm { display: inline }
.addFormMenu { display: table-cell; padding-left: 7px }
.list { margin-bottom: 3px } .list { margin-bottom: 3px }
.list td, .list th { border: 3px solid #ededed; color: grey; .list td, .list th { border: 3px solid #ededed; color: grey;
padding: 3px 5px 3px 5px } padding: 3px 5px 3px 5px }
@ -127,8 +130,8 @@ td.search { padding-top: 8px }
.odd { background-color: #f6f6f6 } .odd { background-color: #f6f6f6 }
.odd2 { background-color: #f2f2f2 } .odd2 { background-color: #f2f2f2 }
.refMenuItem { border-top: grey 1px dashed; margin: 3px 0; padding-top: 3px } .refMenuItem { border-top: grey 1px dashed; margin: 3px 0; padding-top: 3px }
.summary { margin-bottom: 5px; background-color: #f9f9f9; .summary { margin-bottom: 5px; background-color: whitesmoke;
border: 2px solid #f9f9f9 } border: 3px solid white }
.by { padding: 5px; color: grey; font-size: 97% } .by { padding: 5px; color: grey; font-size: 97% }
.underline { border-bottom: 1px dotted grey } .underline { border-bottom: 1px dotted grey }
.state { font-weight: bold; border-bottom: 1px dashed grey } .state { font-weight: bold; border-bottom: 1px dashed grey }

View file

@ -703,7 +703,7 @@ function protectAppyForm() {
} }
// Functions for opening and closing a popup // Functions for opening and closing a popup
function openPopup(popupId, msg) { function openPopup(popupId, msg, width, height) {
// Put the message into the popup // Put the message into the popup
if (msg) { if (msg) {
var msgHook = (popupId == 'alertPopup')? 'appyAlertText': 'appyConfirmText'; var msgHook = (popupId == 'alertPopup')? 'appyAlertText': 'appyConfirmText';
@ -715,13 +715,35 @@ function openPopup(popupId, msg) {
// Put it at the right place on the screen // Put it at the right place on the screen
var scrollTop = document.documentElement.scrollTop || window.pageYOffset || 0; var scrollTop = document.documentElement.scrollTop || window.pageYOffset || 0;
popup.style.top = (scrollTop + 150) + 'px'; popup.style.top = (scrollTop + 150) + 'px';
if (width) popup.style.width = width + 'px';
if (popupId == 'iframePopup') {
// Initialize iframe's width.
var iframe = document.getElementById('appyIFrame');
iframe.style.width = (width-20) + 'px';
if (height) iframe.style.height = height + 'px';
}
popup.style.display = 'block'; popup.style.display = 'block';
} }
function closePopup(popupId) { function closePopup(popupId) {
// Close the popup // Close the popup
var popup = document.getElementById(popupId); var container = window.parent.document;
var popup = container.getElementById(popupId);
popup.style.display = 'none'; popup.style.display = 'none';
popup.style.width = null;
if (popupId == 'iframePopup') {
// Reinitialise the enclosing iframe.
var iframe = container.getElementById('appyIFrame');
iframe.style.width = null;
iframe.innerHTML = '';
// Leave the form silently if we are on an edit page
iframe.contentWindow.onbeforeunload = null;
}
}
function backFromPopup() {
closePopup('iframePopup');
window.parent.location = window.parent.location;
} }
// Function triggered when an action needs to be confirmed by the user // Function triggered when an action needs to be confirmed by the user
@ -734,8 +756,8 @@ function askConfirm(actionType, action, msg, showComment) {
confirmForm.actionType.value = actionType; confirmForm.actionType.value = actionType;
confirmForm.action.value = action; confirmForm.action.value = action;
var commentArea = document.getElementById('commentArea'); var commentArea = document.getElementById('commentArea');
if (showComment) commentArea.style.display = "block"; if (showComment) commentArea.style.display = 'block';
else commentArea.style.display = "none"; else commentArea.style.display = 'none';
openPopup("confirmActionPopup", msg); openPopup("confirmActionPopup", msg);
} }
@ -762,6 +784,12 @@ function doConfirm() {
// We must execute Javascript code in "action" // We must execute Javascript code in "action"
eval(action); eval(action);
} }
else if (actionType == 'form+script') {
var elems = action.split('+');
// Submit the form in elems[0] and execute the JS code in elems[1]
document.getElementById(elems[0]).submit();
eval(elems[1]);
}
} }
// Function triggered when the user asks password reinitialisation // Function triggered when the user asks password reinitialisation
@ -952,4 +980,4 @@ function onSelectDate(cal) {
if (update && p.singleClick && cal.dateClicked) { if (update && p.singleClick && cal.dateClicked) {
cal.callCloseHandler(); cal.callCloseHandler();
} }
}; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

After

Width:  |  Height:  |  Size: 219 B

View file

@ -176,22 +176,24 @@ class ToolWrapper(AbstractWrapper):
'current' or ''">::_(className + '_plural')</a> 'current' or ''">::_(className + '_plural')</a>
</div> </div>
<!-- Actions --> <!-- Create instances of this class -->
<x var="mayCreate=ztool.userMayCreate(rootClass); <form if="ztool.userMayCreate(rootClass) and \
createMeans=ztool.getCreateMeans(rootClass)"> ('form' in ztool.getCreateMeans(rootClass))" class="addForm"
<!-- Create a new object from a web form. --> var2="target=ztool.getLinksTargetInfo(rootClass)"
<input type="button" class="buttonSmall button" action=":'%s/do' % toolUrl" target=":target.target">
if="mayCreate and ('form' in createMeans)" <input type="hidden" name="action" value="Create"/>
var2="label=_('query_create')" value=":label" <input type="hidden" name="className" value=":className"/>
<input type="hidden" name="popup"
value=":(inPopup or (target.target != '_self')) and '1' or '0'"/>
<input type="submit" class="buttonSmall button"
var="label=_('query_create')" value=":label"
onclick=":target.openPopup"
style=":'%s; %s' % (url('add', bg=True), \ style=":'%s; %s' % (url('add', bg=True), \
ztool.getButtonWidth(label))" ztool.getButtonWidth(label))"/>
onclick=":'goto(%s)' % \ </form>
q('%s/do?action=Create&amp;className=%s' % \
(toolUrl, className))"/>
</x>
<!-- Searches --> <!-- Searches -->
<x if="ztool.advancedSearchEnabledFor(rootClass)"> <x if="ztool.advancedSearchEnabledFor(rootClass)">
<!-- Live search --> <!-- Live search -->
<form action=":'%s/do' % toolUrl"> <form action=":'%s/do' % toolUrl">
<input type="hidden" name="action" value="SearchObjects"/> <input type="hidden" name="action" value="SearchObjects"/>
@ -232,7 +234,8 @@ class ToolWrapper(AbstractWrapper):
# The message that is shown when a user triggers an action. # The message that is shown when a user triggers an action.
pxMessage = Px(''' pxMessage = Px('''
<div var="messages=ztool.consumeMessages()" if="messages" class="message"> <div var="messages=ztool.consumeMessages()" if="messages"
class=":inPopup and 'messagePopup message' or 'message'">
<!-- The icon for closing the message --> <!-- The icon for closing the message -->
<img src=":url('close')" align=":dright" class="clickable" <img src=":url('close')" align=":dright" class="clickable"
onclick="this.parentNode.style.display='none'"/> onclick="this.parentNode.style.display='none'"/>
@ -308,8 +311,11 @@ class ToolWrapper(AbstractWrapper):
(className, searchName, startNumber+currentNumber, totalNumber); (className, searchName, startNumber+currentNumber, totalNumber);
cssClass=zobj.getCssFor('title')"> cssClass=zobj.getCssFor('title')">
<x>::zobj.getSupTitle(navInfo)</x> <x>::zobj.getSupTitle(navInfo)</x>
<a href=":zobj.getUrl(nav=navInfo, page=zobj.getDefaultViewPage())" <a if="enableLinks" class=":cssClass"
if="enableLinks" class=":cssClass">:zobj.Title()</a><span var2="linkInPopup=inPopup or (target.target != '_self')"
target=":target.target" onclick=":target.openPopup"
href=":zobj.getUrl(nav=navInfo, page=zobj.getDefaultViewPage(), \
inPopup=linkInPopup)">:zobj.Title()</a><span
if="not enableLinks" class=":cssClass">:zobj.Title()</span><span if="not enableLinks" class=":cssClass">:zobj.Title()</span><span
style=":showSubTitles and 'display:inline' or 'display:none'" style=":showSubTitles and 'display:inline' or 'display:none'"
name="subTitle">::zobj.getSubTitle()</span> name="subTitle">::zobj.getSubTitle()</span>
@ -320,9 +326,11 @@ class ToolWrapper(AbstractWrapper):
<!-- Edit --> <!-- Edit -->
<td if="zobj.mayEdit()"> <td if="zobj.mayEdit()">
<a var="navInfo='search.%s.%s.%d.%d' % \ <a var="navInfo='search.%s.%s.%d.%d' % \
(className, searchName, loop.zobj.nb+1+startNumber, totalNumber)" (className, searchName, loop.zobj.nb+1+startNumber, totalNumber);
linkInPopup=inPopup or (target.target != '_self')"
target=":target.target" onclick=":target.openPopup"
href=":zobj.getUrl(mode='edit', page=zobj.getDefaultEditPage(), \ href=":zobj.getUrl(mode='edit', page=zobj.getDefaultEditPage(), \
nav=navInfo)"> nav=navInfo, inPopup=linkInPopup)">
<img src=":url('edit')" title=":_('object_edit')"/></a> <img src=":url('edit')" title=":_('object_edit')"/></a>
</td> </td>
<td> <td>
@ -429,7 +437,8 @@ class ToolWrapper(AbstractWrapper):
newSearchUrl='%s/search?className=%s%s' % \ newSearchUrl='%s/search?className=%s%s' % \
(ztool.absolute_url(), className, refUrlPart); (ztool.absolute_url(), className, refUrlPart);
showSubTitles=req.get('showSubTitles', 'true') == 'true'; showSubTitles=req.get('showSubTitles', 'true') == 'true';
resultMode=ztool.getResultMode(className)"> resultMode=ztool.getResultMode(className);
target=ztool.getLinksTargetInfo(ztool.getAppyClass(className))">
<x if="zobjects"> <x if="zobjects">
<!-- Display here POD templates if required. --> <!-- Display here POD templates if required. -->
@ -532,6 +541,17 @@ class ToolWrapper(AbstractWrapper):
</form> </form>
</x>''', template=AbstractWrapper.pxTemplate, hook='content') </x>''', template=AbstractWrapper.pxTemplate, hook='content')
pxBack = Px('''
<html>
<head>
<script src=":ztool.getIncludeUrl('appy.js')" type="text/javascript">
</script>
</head>
<body>
<script type="text/javascript">backFromPopup()</script>
</body>
</html>''')
def isManager(self): def isManager(self):
'''Some pages on the tool can only be accessed by managers.''' '''Some pages on the tool can only be accessed by managers.'''
if self.user.has_role('Manager'): return 'view' if self.user.has_role('Manager'): return 'view'

View file

@ -21,9 +21,9 @@ class AbstractWrapper(object):
# Buttons for going to next/previous objects if this one is among bunch of # Buttons for going to next/previous objects if this one is among bunch of
# referenced or searched objects. currentNumber starts with 1. # referenced or searched objects. currentNumber starts with 1.
pxNavigateSiblings = Px(''' pxNavigateSiblings = Px('''
<div if="req.get('nav', None)" var2="ni=ztool.getNavigationInfo()"> <div if="req.get('nav', None)" var2="ni=ztool.getNavigationInfo(inPopup)">
<!-- Go to the source URL (search or referred object) --> <!-- Go to the source URL (search or referred object) -->
<a if="ni.sourceUrl" href=":ni.sourceUrl"><img <a if="not inPopup and ni.sourceUrl" href=":ni.sourceUrl"><img
var="gotoSource=_('goto_source'); var="gotoSource=_('goto_source');
goBack=ni.backText and ('%s - %s' % (ni.backText, gotoSource)) \ goBack=ni.backText and ('%s - %s' % (ni.backText, gotoSource)) \
or gotoSource" or gotoSource"
@ -52,7 +52,7 @@ class AbstractWrapper(object):
<tr> <tr>
<!-- Breadcrumb --> <!-- Breadcrumb -->
<td var="sup=zobj.getSupBreadCrumb(); <td var="sup=zobj.getSupBreadCrumb();
breadcrumb=zobj.getBreadCrumb(); breadcrumb=zobj.getBreadCrumb(inPopup=inPopup);
sub=zobj.getSubBreadCrumb()" class="breadcrumb"> sub=zobj.getSubBreadCrumb()" class="breadcrumb">
<x if="sup">::sup</x> <x if="sup">::sup</x>
<x for="bc in breadcrumb" var2="nb=loop.bc.nb"> <x for="bc in breadcrumb" var2="nb=loop.bc.nb">
@ -84,7 +84,8 @@ class AbstractWrapper(object):
dummy=setattr(req, 'pxContext', _ctx_); dummy=setattr(req, 'pxContext', _ctx_);
lang=ztool.getUserLanguage(); q=ztool.quote; lang=ztool.getUserLanguage(); q=ztool.quote;
layoutType=ztool.getLayoutType(); layoutType=ztool.getLayoutType();
showPortlet=ztool.showPortlet(obj, layoutType); inPopup=req.get('popup') == '1';
showPortlet=not inPopup and ztool.showPortlet(obj, layoutType);
dir=ztool.getLanguageDirection(lang); dir=ztool.getLanguageDirection(lang);
cfg=ztool.getProductConfig(True); cfg=ztool.getProductConfig(True);
dleft=(dir == 'ltr') and 'left' or 'right'; dleft=(dir == 'ltr') and 'left' or 'right';
@ -170,9 +171,17 @@ class AbstractWrapper(object):
</div> </div>
</div> </div>
<!-- Popup containing the Appy iframe -->
<div id="iframePopup" class="popup" if="not inPopup"
style="background-color: #fbfbfb">
<img align=":dright" src=":url('close')" class="clickable"
onclick="closePopup('iframePopup')"/>
<iframe id="appyIFrame" name="appyIFrame" frameborder="0"></iframe>
</div>
<table class=":(cfg.skin == 'wide') and 'mainWide main' or 'main'" <table class=":(cfg.skin == 'wide') and 'mainWide main' or 'main'"
align="center" cellpadding="0"> align="center" cellpadding="0">
<tr class="top"> <tr class="top" if="not inPopup">
<!-- Top banner --> <!-- Top banner -->
<td var="bannerName=(dir == 'ltr') and 'banner' or 'bannerrtl'" <td var="bannerName=(dir == 'ltr') and 'banner' or 'bannerrtl'"
style=":url(bannerName, bg=True) + '; background-repeat:no-repeat;\ style=":url(bannerName, bg=True) + '; background-repeat:no-repeat;\
@ -213,7 +222,7 @@ class AbstractWrapper(object):
</tr> </tr>
<!-- The user strip --> <!-- The user strip -->
<tr height=":cfg.discreetLogin and '5px' or '28px'"> <tr height=":cfg.discreetLogin and '5px' or '28px'" if="not inPopup">
<td> <td>
<table class="userStrip"> <table class="userStrip">
<tr> <tr>
@ -297,7 +306,7 @@ class AbstractWrapper(object):
</td> </td>
</tr> </tr>
<!-- Footer --> <!-- Footer -->
<tr height="26px"><td>:tool.pxFooter</td></tr> <tr height="26px" if="not inPopup"><td>:tool.pxFooter</td></tr>
</table> </table>
</body> </body>
</html>''', prologue=Px.xhtmlPrologue) </html>''', prologue=Px.xhtmlPrologue)
@ -401,7 +410,7 @@ class AbstractWrapper(object):
historyMaxPerPage=req.get('maxPerPage', 5); historyMaxPerPage=req.get('maxPerPage', 5);
historyExpanded=req.get('appyHistory','collapsed')=='expanded'; historyExpanded=req.get('appyHistory','collapsed')=='expanded';
creator=zobj.Creator()"> creator=zobj.Creator()">
<table width="100%" class="summary"> <table width="100%" class="summary" cellpadding="0" cellspacing="0">
<tr> <tr>
<td colspan="2" class="by"> <td colspan="2" class="by">
<!-- Plus/minus icon for accessing history --> <!-- Plus/minus icon for accessing history -->
@ -461,7 +470,8 @@ class AbstractWrapper(object):
<tr valign="top"> <tr valign="top">
<!-- Refresh --> <!-- Refresh -->
<td if="zobj.isDebug()"> <td if="zobj.isDebug()">
<a href=":zobj.getUrl(mode=layoutType, page=page, refresh='yes')"> <a href=":zobj.getUrl(mode=layoutType, page=page, refresh='yes', \
inPopup=inPopup)">
<img title="Refresh" style="vertical-align:top" src=":url('refresh')"/> <img title="Refresh" style="vertical-align:top" src=":url('refresh')"/>
</a> </a>
</td> </td>
@ -479,7 +489,8 @@ class AbstractWrapper(object):
<!-- Button on the view page --> <!-- Button on the view page -->
<input if="not isEdit" type="button" class="button" value=":label" <input if="not isEdit" type="button" class="button" value=":label"
style=":'%s; %s' % (url('previous', bg=True), buttonWidth)" style=":'%s; %s' % (url('previous', bg=True), buttonWidth)"
onclick=":'goto(%s)' % q(zobj.getUrl(page=previousPage))"/> onclick=":'goto(%s)' % q(zobj.getUrl(page=previousPage, \
inPopup=inPopup))"/>
</td> </td>
<!-- Save --> <!-- Save -->
@ -506,7 +517,8 @@ class AbstractWrapper(object):
var="label=_('object_edit')" value=":label" var="label=_('object_edit')" value=":label"
style=":'%s; %s' % (url('edit', bg=True), \ style=":'%s; %s' % (url('edit', bg=True), \
ztool.getButtonWidth(label))" ztool.getButtonWidth(label))"
onclick=":'goto(%s)' % q(zobj.getUrl(mode='edit', page=page))"/> onclick=":'goto(%s)' % q(zobj.getUrl(mode='edit', page=page, \
inPopup=inPopup))"/>
<!-- Locked --> <!-- Locked -->
<a if="editable and locked"> <a if="editable and locked">
@ -536,7 +548,8 @@ class AbstractWrapper(object):
<!-- Button on the view page --> <!-- Button on the view page -->
<input if="not isEdit" type="button" class="button" value=":label" <input if="not isEdit" type="button" class="button" value=":label"
style=":'%s; %s' % (url('next', bg=True), buttonWidth)" style=":'%s; %s' % (url('next', bg=True), buttonWidth)"
onclick=":'goto(%s)' % q(zobj.getUrl(page=nextPage))"/> onclick=":'goto(%s)' % q(zobj.getUrl(page=nextPage, \
inPopup=inPopup))"/>
</td> </td>
<!-- Workflow transitions --> <!-- Workflow transitions -->
@ -590,6 +603,7 @@ class AbstractWrapper(object):
enctype="multipart/form-data" action=":zobj.absolute_url()+'/do'"> enctype="multipart/form-data" action=":zobj.absolute_url()+'/do'">
<input type="hidden" name="action" value="Update"/> <input type="hidden" name="action" value="Update"/>
<input type="hidden" name="button" value=""/> <input type="hidden" name="button" value=""/>
<input type="hidden" name="popup" value=":inPopup and '1' or '0'"/>
<input type="hidden" name="page" value=":page"/> <input type="hidden" name="page" value=":page"/>
<input type="hidden" name="nav" value=":req.get('nav', None)"/> <input type="hidden" name="nav" value=":req.get('nav', None)"/>
<input type="hidden" name="confirmed" value="False"/> <input type="hidden" name="confirmed" value="False"/>
@ -615,6 +629,7 @@ class AbstractWrapper(object):
lang=ztool.getUserLanguage(); q=ztool.quote; lang=ztool.getUserLanguage(); q=ztool.quote;
action=req.get('action', None); action=req.get('action', None);
px=req['px'].split(':'); px=req['px'].split(':');
inPopup=req.get('popup') == '1';
className=(len(px) == 3) and px[0] or None; className=(len(px) == 3) and px[0] or None;
field=className and zobj.getAppyType(px[1], className) or None; field=className and zobj.getAppyType(px[1], className) or None;
field=(len(px) == 2) and zobj.getAppyType(px[0]) or field; field=(len(px) == 2) and zobj.getAppyType(px[0]) or field;