[gen] Added the possibility to navigate to tied object number X within a list of tied objects from a Ref that is numbered.

This commit is contained in:
Gaetan Delannay 2014-10-21 09:25:37 +02:00
parent 4577855d60
commit 7484fbca93
18 changed files with 371 additions and 228 deletions

View file

@ -38,9 +38,8 @@ class Ref(Field):
# 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 one.
pxObjectTitle = Px('''
<x var="navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
field.pageName, loop.tied.nb + 1 + startNumber, totalNumber);
navInfo=(not field.isBack and not inPickList) and navInfo or '';
<x var="navInfo=field.getNavInfo(zobj, loop.tied.nb + 1 + startNumber, \
totalNumber, inPickList);
pageName=field.isBack and field.back.pageName or 'main'">
<x>::tied.o.getSupTitle(navInfo)</x>
<x>::tied.o.getListTitle(nav=navInfo, target=target, page=pageName, \
@ -105,8 +104,8 @@ class Ref(Field):
</td>
<!-- Edit -->
<td if="not field.noForm and tied.o.mayEdit()">
<a var="navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
field.pageName, loop.tied.nb + 1 + startNumber, totalNumber);
<a var="navInfo=field.getNavInfo(zobj, loop.tied.nb + 1 + startNumber, \
totalNumber);
linkInPopup=inPopup or (target.target != '_self')"
href=":tied.o.getUrl(mode='edit', page='main', nav=navInfo, \
inPopup=linkInPopup)"
@ -149,8 +148,7 @@ class Ref(Field):
<input type="hidden" name="action" value="Create"/>
<input type="hidden" name="className" value=":tiedClassName"/>
<input type="hidden" name="nav"
value=":'ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
field.pageName, 0, totalNumber)"/>
value=":field.getNavInfo(zobj, 0, totalNumber)"/>
<input type="hidden" name="popup"
value=":(inPopup or (target.target != '_self')) and '1' or '0'"/>
<input
@ -436,6 +434,7 @@ class Ref(Field):
changeOrder=mayEdit and field.getAttribute(zobj, 'changeOrder');
sortConfirm=changeOrder and _('sort_confirm');
numbered=field.isNumbered(zobj);
gotoNumber=numbered;
changeNumber=not inPickList and numbered and changeOrder and \
(totalNumber &gt; 3);
checkboxesEnabled=field.getAttribute(zobj, 'checkboxes') and \
@ -1419,6 +1418,25 @@ class Ref(Field):
appyObj.say(msg)
tool.goto(urlBack)
def getNavInfo(self, obj, nb, total, inPickList=False):
'''Gets the navigation info allowing to navigate from tied object number
p_nb to its siblings.'''
if self.isBack or inPickList: return ''
# If p_nb is None, we want to produce a generic nav info into which we
# will insert a specific number afterwards.
if nb == None: return 'ref.%s.%s.%%d.%d' % (obj.id, self.name, total)
return 'ref.%s.%s.%d.%d' % (obj.id, self.name, nb, total)
def onGotoTied(self, obj):
'''Called when the user wants to go to a tied object whose number is in
the request.'''
number = int(obj.REQUEST['number']) - 1
uids = getattr(obj.aq_base, self.name)
tiedUid = uids[number]
tied = obj.getTool().getObject(tiedUid)
tiedUrl = tied.getUrl(nav=self.getNavInfo(obj, number+1, len(uids)))
return obj.goto(tiedUrl)
def autoref(klass, field):
'''klass.field is a Ref to p_klass. This kind of auto-reference can't be
declared in the "normal" way, like this:

View file

@ -155,6 +155,15 @@ class Search:
node['_appy_objs_cbs'] = {};
node['_appy_objs_sem'] = '%s';''' % (hookId, default)
def getSessionKey(self, className, full=True):
'''Returns the name of the key, in the session, where results for this
search are stored when relevant. If p_full is False, only the suffix
of the session key is returned (ie, without the leading
"search_").'''
res = (self.name == 'allSearch') and className or self.name
if not full: return res
return 'search_%s' % res
class UiSearch:
'''Instances of this class are generated on-the-fly for manipulating a
Search from the User Interface.'''

View file

@ -45,7 +45,7 @@ cellDelms = ''.join(cellDelimiters.keys())
pxDict = {
# Page-related elements
's': 'pxHeader', 'w': 'pxFields', 'n': 'pxNavigateSiblings', 'b': 'pxButtons',
's': 'pxHeader', 'w': 'pxFields', 'n': 'pxNavigationStrip', 'b': 'pxButtons',
# Field-related elements
'l': 'pxLabel', 'd': 'pxDescription', 'h': 'pxHelp', 'v': 'pxValidation',
'r': 'pxRequired', 'c': 'pxChanges'}

View file

@ -8,6 +8,7 @@ from appy.gen import utils as gutils
from appy.gen.mixins import BaseMixin
from appy.gen.wrappers import AbstractWrapper
from appy.gen.descriptors import ClassDescriptor
from appy.gen.navigate import Siblings
from appy.shared import mimeTypes
from appy.shared import utils as sutils
from appy.shared.data import languages
@ -375,15 +376,15 @@ class ToolMixin(BaseMixin):
# time a page for an element is consulted.
if remember:
if not searchName:
if not search or (search.name == 'allSearch'):
if not search:
searchName = className
else:
searchName = search.name
searchName = search.getSessionKey(className, full=False)
uids = {}
i = -1
for obj in res.objects:
i += 1
uids[startNumber+i] = obj.UID()
uids[startNumber+i] = obj.id
self.REQUEST.SESSION['search_%s' % searchName] = uids
return res
@ -776,144 +777,9 @@ class ToolMixin(BaseMixin):
if not res: return ''
return res
def getQueryUrl(self, contentType, searchName, startNumber=None):
'''This method creates the URL that allows to perform a (non-Ajax)
request for getting queried objects from a search named p_searchName
on p_contentType.'''
baseUrl = self.absolute_url()
baseParams = 'className=%s' % contentType
rq = self.REQUEST
if rq.get('ref'): baseParams += '&ref=%s' % rq.get('ref')
# Manage start number
if startNumber != None:
baseParams += '&startNumber=%s' % startNumber
elif rq.has_key('startNumber'):
baseParams += '&startNumber=%s' % rq['startNumber']
# Manage search name
if searchName: baseParams += '&search=%s' % searchName
return '%s/query?%s' % (baseUrl, baseParams)
def computeStartNumberFrom(self, currentNumber, totalNumber, batchSize):
'''Returns the number (start at 0) of the first element in a list
containing p_currentNumber (starts at 0) whose total number is
p_totalNumber and whose batch size is p_batchSize.'''
startNumber = 0
res = startNumber
while (startNumber < totalNumber):
if (currentNumber < startNumber + batchSize):
return startNumber
else:
startNumber += batchSize
return startNumber
def getNavigationInfo(self, inPopup=False):
'''Extracts navigation information from request/nav and returns an
object with the info that a page can use for displaying object
navigation.'''
res = Object()
rq = self.REQUEST
t, d1, d2, currentNumber, totalNumber = rq.get('nav').split('.')
res.currentNumber = int(currentNumber)
res.totalNumber = int(totalNumber)
# Compute the label of the search, or ref field
if t == 'search':
searchName = d2
if not searchName:
# We search all objects of a given type.
label = '%s_plural' % d1.split(':')[0]
elif searchName == 'customSearch':
# This is an advanced, custom search.
label = 'search_results'
else:
# This is a named, predefined search.
label = '%s_search_%s' % (d1.split(':')[0], searchName)
res.backText = self.translate(label)
# If it is a dynamic search this label does not exist.
if ('_' in res.backText): res.backText = ''
else:
fieldName, pageName = d2.split(':')
sourceObj = self.getObject(d1)
label = '%s_%s' % (sourceObj.meta_type, fieldName)
res.backText = '%s - %s' % (sourceObj.Title(),self.translate(label))
newNav = '%s.%s.%s.%%d.%s' % (t, d1, d2, totalNumber)
# Among, first, previous, next and last, which one do I need?
previousNeeded = False # Previous ?
previousIndex = res.currentNumber - 2
if (previousIndex > -1) and (res.totalNumber > previousIndex):
previousNeeded = True
nextNeeded = False # Next ?
nextIndex = res.currentNumber
if nextIndex < res.totalNumber: nextNeeded = True
firstNeeded = False # First ?
firstIndex = 0
if previousIndex > 0: firstNeeded = True
lastNeeded = False # Last ?
lastIndex = res.totalNumber - 1
if (nextIndex < lastIndex): lastNeeded = True
# Get the list of available UIDs surrounding the current object
if t == 'ref': # Manage navigation from a reference
# In the case of a reference, we retrieve ALL surrounding objects.
masterObj = self.getObject(d1)
batchSize = masterObj.getAppyType(fieldName).maxPerPage
uids = getattr(masterObj, fieldName)
# Display the reference widget at the page where the current object
# lies.
startNumberKey = '%s%s_startNumber' % (masterObj.id, fieldName)
startNumber = self.computeStartNumberFrom(res.currentNumber-1,
res.totalNumber, batchSize)
res.sourceUrl = masterObj.getUrl(**{startNumberKey:startNumber,
'page':pageName, 'nav':''})
else: # Manage navigation from a search
contentType = d1
searchName = keySuffix = d2
batchSize = self.appy().numberOfResultsPerPage
if not searchName: keySuffix = contentType
s = rq.SESSION
searchKey = 'search_%s' % keySuffix
if s.has_key(searchKey): uids = s[searchKey]
else: uids = {}
# In the case of a search, we retrieve only a part of all
# surrounding objects, those that are stored in the session.
if (previousNeeded and not uids.has_key(previousIndex)) or \
(nextNeeded and not uids.has_key(nextIndex)):
# I do not have this UID in session. I will need to
# retrigger the query by querying all objects surrounding
# this one.
newStartNumber = (res.currentNumber-1) - (batchSize / 2)
if newStartNumber < 0: newStartNumber = 0
self.executeQuery(contentType, searchName=searchName,
startNumber=newStartNumber, remember=True)
uids = s[searchKey]
# For the moment, for first and last, we get them only if we have
# them in session.
if not uids.has_key(0): firstNeeded = False
if not uids.has_key(lastIndex): lastNeeded = False
# Compute URL of source object
startNumber = self.computeStartNumberFrom(res.currentNumber-1,
res.totalNumber, batchSize)
res.sourceUrl = self.getQueryUrl(contentType, searchName,
startNumber=startNumber)
# Compute URLs
for urlType in ('previous', 'next', 'first', 'last'):
exec 'needIt = %sNeeded' % urlType
urlKey = '%sUrl' % urlType
setattr(res, urlKey, None)
if needIt:
exec 'index = %sIndex' % urlType
uid = None
try:
uid = uids[index]
# uids can be a list (ref) or a dict (search)
except KeyError: pass
except IndexError: pass
if uid:
brain = self.getObject(uid, brain=True)
if brain:
sibling = brain.getObject()
setattr(res, urlKey, sibling.getUrl(\
nav=newNav % (index + 1),
page=rq.get('page', 'main'), inPopup=inPopup))
return res
def getNavigationInfo(self, nav, inPopup):
'''Produces a Siblings instance from navigation info p_nav.'''
return Siblings.get(nav, self, inPopup)
def getGroupedSearchFields(self, searchInfo):
'''This method transforms p_searchInfo.fields, which is a "flat"

View file

@ -35,20 +35,17 @@ class BaseMixin:
def getInitiatorInfo(self, appy=False):
'''Gets information about a potential initiator object from the request.
Returns a 3-tuple (initiator, pageName, field):
Returns a 2-tuple (initiator, field):
* initiator is the initiator (Zope or Appy) object;
* pageName is the page on the initiator where the origin of the Ref
field lies;
* field is the Ref instance.
'''
rq = self.REQUEST
if not rq.get('nav', '').startswith('ref.'): return None, None, None
if not rq.get('nav', '').startswith('ref.'): return None, None
splitted = rq['nav'].split('.')
initiator = self.getTool().getObject(splitted[1])
fieldName, page = splitted[2].split(':')
field = initiator.getAppyType(fieldName)
field = initiator.getAppyType(splitted[2])
if appy: initiator = initiator.appy()
return initiator, page, field
return initiator, field
def createOrUpdate(self, created, values,
initiator=None, initiatorField=None):
@ -203,7 +200,7 @@ class BaseMixin:
# create the object.
urlParams = {'mode':'edit', 'page':'main', 'nav':'',
'inPopup':rq.get('popup') == '1'}
initiator, initiatorPage, initiatorField = self.getInitiatorInfo()
initiator, initiatorField = self.getInitiatorInfo()
if initiator:
# The object to create will be linked to an initiator object through
# a Ref field. We create here a new navigation string with one more
@ -387,7 +384,8 @@ class BaseMixin:
isNew = self.isTemporary()
inPopup = rq.get('popup') == '1'
# If this object is created from an initiator, get info about him.
initiator, initiatorPage, initiatorField = self.getInitiatorInfo()
initiator, initiatorField = self.getInitiatorInfo()
initiatorPage = initiatorField and initiatorField.pageName or None
# If the user clicked on 'Cancel', go back to the previous page.
buttonClicked = rq.get('button')
if buttonClicked == 'cancel':
@ -696,6 +694,10 @@ class BaseMixin:
self.REQUEST.set(field.name, '')
return self.edit()
def gotoTied(self):
'''Redirects the user to an object tied to this one.'''
return self.getAppyType(self.REQUEST['field']).onGotoTied(self)
def getCreateFolder(self):
'''When an object must be created from this one through a Ref field, we
must know where to put the newly create object: within this one if it

220
gen/navigate.py Normal file
View file

@ -0,0 +1,220 @@
# ------------------------------------------------------------------------------
from appy.px import Px
# ------------------------------------------------------------------------------
class Siblings:
'''Abstract class containing information for navigating from one object to
its siblings.'''
siblingTypes = ('previous', 'next', 'first', 'last')
# Buttons for going to siblings of the current object.
pxNavigate = Px('''
<!-- Go to the source URL (search or referred object) -->
<a if="not inPopup" href=":self.sourceUrl"><img
var="goBack='%s - %s' % (self.getBackText(), _('goto_source'))"
src=":url('gotoSource')" title=":goBack"/></a>
<!-- Go to the first or previous page -->
<a if="self.firstUrl" href=":self.firstUrl"><img title=":_('goto_first')"
src=":url('arrowsLeft')"/></a><a
if="self.previousUrl" href=":self.previousUrl"><img
title=":_('goto_previous')" src=":url('arrowLeft')"/></a>
<!-- Explain which element is currently shown -->
<span class="discreet">
<x>:self.number</x> <b>//</b>
<x>:self.total</x> </span>
<!-- Go to the next or last page -->
<a if="self.nextUrl" href=":self.nextUrl"><img title=":_('goto_next')"
src=":url('arrowRight')"/></a><a
if="self.lastUrl" href=":self.lastUrl"><img title=":_('goto_last')"
src=":url('arrowsRight')"/></a>
<!-- Go to the element number... -->
<x if="self.showGotoNumber()"
var2="field=self.field; sourceUrl=self.sourceObject.absolute_url();
totalNumber=self.total"><br/><x>:obj.pxGotoNumber</x></x>''')
@staticmethod
def get(nav, tool, inPopup):
'''This method analyses the navigation info p_nav and returns the
corresponding concrete Siblings instance.'''
elems = nav.split('.')
params = elems[1:]
if elems[0] == 'ref': return RefSiblings(tool, inPopup, *params)
elif elems[0] == 'search': return SearchSiblings(tool, inPopup, *params)
def computeStartNumber(self):
'''Returns the start number of the batch where the current element
lies.'''
# First index starts at O, so we calibrate self.number
number = self.number - 1
batchSize = self.getBatchSize()
res = 0
while (res < self.total):
if (number < res + batchSize): return res
res += batchSize
return res
def __init__(self, tool, inPopup, number, total):
self.tool = tool
self.request = tool.REQUEST
# Are we in a popup window or not?
self.inPopup = inPopup
# The number of the current element
self.number = int(number)
# The total number of siblings
self.total = int(total)
# Do I need to navigate to first, previous, next and/or last sibling ?
self.previousNeeded = False # Previous ?
self.previousIndex = self.number - 2
if (self.previousIndex > -1) and (self.total > self.previousIndex):
self.previousNeeded = True
self.nextNeeded = False # Next ?
self.nextIndex = self.number
if self.nextIndex < self.total: self.nextNeeded = True
self.firstNeeded = False # First ?
self.firstIndex = 0
if self.previousIndex > 0: self.firstNeeded = True
self.lastNeeded = False # Last ?
self.lastIndex = self.total - 1
if (self.nextIndex < self.lastIndex): self.lastNeeded = True
# Compute the UIDs of the siblings of the current object
self.siblings = self.getSiblings()
# Compute back URL and URLs to siblings
self.sourceUrl = self.getSourceUrl()
siblingNav = self.getNavKey()
siblingPage = self.request.get('page', 'main')
for urlType in self.siblingTypes:
exec 'needIt = self.%sNeeded' % urlType
urlKey = '%sUrl' % urlType
setattr(self, urlKey, None)
if not needIt: continue
exec 'index = self.%sIndex' % urlType
uid = None
try:
# self.siblings can be a list (ref) or a dict (search)
uid = self.siblings[index]
except KeyError: continue
except IndexError: continue
if not uid: continue
sibling = self.tool.getObject(uid)
if not sibling: continue
setattr(self, urlKey, sibling.getUrl(nav=siblingNav % (index + 1),
page=siblingPage, inPopup=inPopup))
# ------------------------------------------------------------------------------
class RefSiblings(Siblings):
'''Class containing information for navigating from one object to another
within tied objects from a Ref field.'''
prefix = 'ref'
def __init__(self, tool, inPopup, sourceUid, fieldName, number, total):
# The source object of the Ref field
self.sourceObject = tool.getObject(sourceUid)
# The Ref field in itself
self.field = self.sourceObject.getAppyType(fieldName)
# Call the base constructor
Siblings.__init__(self, tool, inPopup, number, total)
def getNavKey(self):
'''Returns the general navigation key for navigating to another
sibling.'''
return self.field.getNavInfo(self.sourceObject, None, self.total)
def getBackText(self):
'''Computes the text to display when the user want to navigate back to
the list of tied objects.'''
_ = self.tool.translate
return '%s - %s' % (self.sourceObject.Title(), _(self.field.labelId))
def getBatchSize(self):
'''Returns the maximum number of shown objects at a time for this
ref.'''
return self.field.maxPerPage
def getSiblings(self):
'''Returns the siblings of the current object.'''
return getattr(self.sourceObject, self.field.name, ())
def getSourceUrl(self):
'''Computes the URL allowing to go back to self.sourceObject's page
where self.field lies and shows the list of tied objects, at the
batch where the current object lies.'''
# Allow to go back to the batch where the current object lies
field = self.field
startNumberKey = '%s_%s_objs_startNumber' % \
(self.sourceObject.id,field.name)
startNumber = str(self.computeStartNumber())
return self.sourceObject.getUrl(**{startNumberKey:startNumber,
'page':field.pageName, 'nav':''})
def showGotoNumber(self):
'''Show "goto number" if the Ref field is numbered.'''
return self.field.isNumbered(self.sourceObject)
# ------------------------------------------------------------------------------
class SearchSiblings(Siblings):
'''Class containing information for navigating from one object to another
within results of a search.'''
prefix = 'search'
def __init__(self, tool, inPopup, className, searchName, number, total):
# The class determining the type of searched objects
self.className = className
# Get the search object
self.searchName = searchName
self.uiSearch = tool.getSearch(className, searchName, ui=True)
self.search = self.uiSearch.search
Siblings.__init__(self, tool, inPopup, number, total)
def getNavKey(self):
'''Returns the general navigation key for navigating to another
sibling.'''
return 'search.%s.%s.%%d.%d' % (self.className, self.searchName,
self.total)
def getBackText(self):
'''Computes the text to display when the user want to navigate back to
the list of searched objects.'''
return self.uiSearch.translated
def getBatchSize(self):
'''Returns the maximum number of shown objects at a time for this
search.'''
return self.search.maxPerPage
def getSiblings(self):
'''Returns the siblings of the current object. For performance reasons,
only a part of the is stored, in the session object.'''
session = self.request.SESSION
searchKey = self.search.getSessionKey(self.className)
if session.has_key(searchKey): res = session[searchKey]
else: res = {}
if (self.previousNeeded and not res.has_key(self.previousIndex)) or \
(self.nextNeeded and not res.has_key(self.nextIndex)):
# The needed sibling UID is not in session. We will need to
# retrigger the query by querying all objects surrounding this one.
newStartNumber = (self.number-1) - (self.search.maxPerPage / 2)
if newStartNumber < 0: newStartNumber = 0
self.tool.executeQuery(self.className, search=self.search,
startNumber=newStartNumber, remember=True)
res = session[searchKey]
# For the moment, for first and last, we get them only if we have them
# in session.
if not res.has_key(0): self.firstNeeded = False
if not res.has_key(self.lastIndex): self.lastNeeded = False
return res
def getSourceUrl(self):
'''Computes the (non-Ajax) URL allowing to go back to the search
results, at the batch where the current object lies.'''
params = 'className=%s&search=%s&startNumber=%d' % \
(self.className, self.searchName, self.computeStartNumber())
ref = self.request.get('ref', None)
if ref: params += '&ref=%s' % ref
return '%s/query?%s' % (self.tool.absolute_url(), params)
def showGotoNumber(self): return
# ------------------------------------------------------------------------------

View file

@ -275,6 +275,10 @@ msgstr ""
msgid "goto_source"
msgstr ""
#. Default: "Go to number"
msgid "goto_number"
msgstr ""
#. Default: "Whatever"
msgid "whatever"
msgstr ""

View file

@ -275,6 +275,10 @@ msgstr ""
msgid "goto_source"
msgstr ""
#. Default: "Go to number"
msgid "goto_number"
msgstr ""
#. Default: "Whatever"
msgid "whatever"
msgstr ""

View file

@ -275,6 +275,10 @@ msgstr "Gehen Sie zum Ende"
msgid "goto_source"
msgstr "Zurück"
#. Default: "Go to number"
msgid "goto_number"
msgstr ""
#. Default: "Whatever"
msgid "whatever"
msgstr "Ohne Bedeutung"

View file

@ -276,6 +276,10 @@ msgstr "Go to end"
msgid "goto_source"
msgstr "Go back"
#. Default: "Go to number"
msgid "goto_number"
msgstr "Go to number"
#. Default: "Whatever"
msgid "whatever"
msgstr "Whatever"

View file

@ -275,6 +275,10 @@ msgstr "Ir al final"
msgid "goto_source"
msgstr "Volver"
#. Default: "Go to number"
msgid "goto_number"
msgstr ""
#. Default: "Whatever"
msgid "whatever"
msgstr "No importa"

View file

@ -276,6 +276,10 @@ msgstr "Aller à la fin"
msgid "goto_source"
msgstr "Retour"
#. Default: "Go to number"
msgid "goto_number"
msgstr "Aller au numéro"
#. Default: "Whatever"
msgid "whatever"
msgstr "Peu importe"

View file

@ -275,6 +275,10 @@ msgstr "Andare alla fine"
msgid "goto_source"
msgstr "Andare indietro"
#. Default: "Go to number"
msgid "goto_number"
msgstr ""
#. Default: "Whatever"
msgid "whatever"
msgstr "Qualunque"

View file

@ -275,6 +275,10 @@ msgstr "Ga naar het einde"
msgid "goto_source"
msgstr "Terug"
#. Default: "Go to number"
msgid "goto_number"
msgstr ""
#. Default: "Whatever"
msgid "whatever"
msgstr "Maakt niets uit"

View file

@ -282,6 +282,19 @@ function askRefField(hookId, objectUrl, innerRef, startNumber, action,
evalInnerScripts);
}
function gotoTied(objectUrl, field, numberWidget, total) {
// Check that the number is correct
try {
var number = parseInt(numberWidget.value);
if (!isNaN(number)) {
if ((number >= 1) && (number <= total)) {
goto(objectUrl + '/gotoTied?field=' + field + '&number=' + number);
}
else numberWidget.style.background = wrongTextInput; }
else numberWidget.style.background = wrongTextInput; }
catch (err) { numberWidget.style.background = wrongTextInput; }
}
function askField(hookId, objectUrl, layoutType, customParams, showChanges,
masterValues, requestValue, error, className){
// Sends an Ajax request for getting the content of any field.

BIN
gen/ui/gotoNumber.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

View file

@ -47,51 +47,47 @@ class ToolWrapper(AbstractWrapper):
# Buttons for navigating among a list of objects (from a Ref field or a
# query): next,back,first,last...
pxNavigate = Px('''
<div if="totalNumber &gt; batchSize" align=":dright">
<table class="listNavigate"
var="mustSortAndFilter=ajaxHookId == 'queryResult';
<div if="totalNumber &gt; batchSize" align=":dright"
var2="mustSortAndFilter=ajaxHookId == 'queryResult';
sortAndFilter=mustSortAndFilter and \
',%s,%s,%s' % (q(sortKey),q(sortOrder),q(filterKey)) or ''">
<tr valign="bottom">
<!-- Go to the first page -->
<td if="(startNumber != 0) and (startNumber != batchSize)"><img
class="clickable" src=":url('arrowsLeft')"
title=":_('goto_first')"
onClick=":navBaseCall.replace('**v**', '0'+sortAndFilter)"/></td>
<img if="(startNumber != 0) and (startNumber != batchSize)"
class="clickable" src=":url('arrowsLeft')" title=":_('goto_first')"
onClick=":navBaseCall.replace('**v**', '0'+sortAndFilter)"/>
<!-- Go to the previous page -->
<td var="sNumber=startNumber - batchSize" if="startNumber != 0"><img
class="clickable" src=":url('arrowLeft')"
title=":_('goto_previous')"
onClick=":navBaseCall.replace('**v**', \
str(sNumber)+sortAndFilter)"/></td>
<img var="sNumber=startNumber - batchSize" if="startNumber != 0"
class="clickable" src=":url('arrowLeft')" title=":_('goto_previous')"
onClick=":navBaseCall.replace('**v**', str(sNumber)+sortAndFilter)"/>
<!-- Explain which elements are currently shown -->
<td class="discreet">
<span class="discreet">
<x>:startNumber + 1</x> <img src=":url('to')"/>
<x>:startNumber + batchNumber</x> <b>//</b>
<x>:totalNumber</x> </td>
<x>:totalNumber</x>
</span>
<!-- Go to the next page -->
<td var="sNumber=startNumber + batchSize"
if="sNumber &lt; totalNumber"><img class="clickable"
src=":url('arrowRight')" title=":_('goto_next')"
onClick=":navBaseCall.replace('**v**', \
str(sNumber)+sortAndFilter)"/></td>
<img var="sNumber=startNumber + batchSize" if="sNumber &lt; totalNumber"
class="clickable" src=":url('arrowRight')" title=":_('goto_next')"
onClick=":navBaseCall.replace('**v**', str(sNumber)+sortAndFilter)"/>
<!-- Go to the last page -->
<td var="lastPageIsIncomplete=totalNumber % batchSize;
<img var="lastPageIsIncomplete=totalNumber % batchSize;
nbOfCompletePages=totalNumber/batchSize;
nbOfCountedPages=lastPageIsIncomplete and \
nbOfCompletePages or nbOfCompletePages-1;
sNumber= nbOfCountedPages * batchSize"
if="(startNumber != sNumber) and \
(startNumber != sNumber-batchSize)"><img class="clickable"
(startNumber != sNumber-batchSize)" class="clickable"
src=":url('arrowsRight')" title=":_('goto_last')"
onClick=":navBaseCall.replace('**v**', \
str(sNumber)+sortAndFilter)"/></td>
</tr>
</table>
onClick=":navBaseCall.replace('**v**', str(sNumber)+sortAndFilter)"/>
<!-- Go to the element number... -->
<x var="gotoNumber=gotoNumber|False" if="gotoNumber"
var2="sourceUrl=obj.url">:obj.pxGotoNumber</x>
</div>''')
# --------------------------------------------------------------------------
@ -508,7 +504,7 @@ class ToolWrapper(AbstractWrapper):
<span class="discreet">:uiSearch.translatedDescr</span><br/>
</td>
<!-- (Top) navigation -->
<td align=":dright" width="150px"><x>:tool.pxNavigate</x></td>
<td align=":dright" width="150px">:tool.pxNavigate</td>
</tr>
</table>

View file

@ -19,34 +19,19 @@ class AbstractWrapper(object):
'''Any real Appy-managed Zope object has a companion object that is an
instance of this class.'''
# Buttons for going to next/previous objects if this one is among bunch of
# referenced or searched objects. currentNumber starts with 1.
pxNavigateSiblings = Px('''
<div if="req.get('nav', None)" var2="ni=ztool.getNavigationInfo(inPopup)">
<!-- Go to the source URL (search or referred object) -->
<a if="not inPopup and ni.sourceUrl" href=":ni.sourceUrl"><img
var="gotoSource=_('goto_source');
goBack=ni.backText and ('%s - %s' % (ni.backText, gotoSource)) \
or gotoSource"
src=":url('gotoSource')" title=":goBack"/></a>
<!-- Go to the first or previous page -->
<a if="ni.firstUrl" href=":ni.firstUrl"><img title=":_('goto_first')"
src=":url('arrowsLeft')"/></a><a
if="ni.previousUrl" href=":ni.previousUrl"><img
title=":_('goto_previous')" src=":url('arrowLeft')"/></a>
<!-- Explain which element is currently shown -->
<span class="discreet">
<x>:ni.currentNumber</x> <b>//</b>
<x>:ni.totalNumber</x> </span>
<!-- Go to the next or last page -->
<a if="ni.nextUrl" href=":ni.nextUrl"><img title=":_('goto_next')"
src=":url('arrowRight')"/></a><a
if="ni.lastUrl" href=":ni.lastUrl"><img title=":_('goto_last')"
src=":url('arrowsRight')"/></a>
</div>''')
# Input field for going to element number ...
pxGotoNumber = Px('''
<x var2="label=_('goto_number');
gotoName='%s_%s_goto' % (obj.id, field.name)">
<span class="discreet" style="padding-left: 5px">:label</span>
<input type="text" size=":(len(str(totalNumber))-1) or 1"
onclick="this.select()"
onkeydown=":'if (event.keyCode==13) document.getElementById' \
'(%s).click()' % q(gotoName)"/><img
id=":gotoName" name=":gotoName"
class="clickable" src=":url('gotoNumber')" title=":label"
onClick=":'gotoTied(%s,%s,this.previousSibling,%s)' % \
(q(sourceUrl), q(field.name), totalNumber)"/></x>''')
pxNavigationStrip = Px('''
<table width="100%">
@ -66,7 +51,9 @@ class AbstractWrapper(object):
<x if="sub">::sub</x>
</td>
<!-- Object navigation -->
<td align=":dright" width="150px">:obj.pxNavigateSiblings</td>
<td var="nav=req.get('nav', None)" if="nav"
var2="self=ztool.getNavigationInfo(nav, inPopup)" align=":dright"
width="150px">:self.pxNavigate</td>
</tr>
</table>
<!-- Object phases and pages -->