[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:
parent
4577855d60
commit
7484fbca93
|
@ -38,9 +38,8 @@ class Ref(Field):
|
||||||
# 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 one.
|
# the URL for allowing to navigate from one object to the next/previous one.
|
||||||
pxObjectTitle = Px('''
|
pxObjectTitle = Px('''
|
||||||
<x var="navInfo='ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
|
<x var="navInfo=field.getNavInfo(zobj, loop.tied.nb + 1 + startNumber, \
|
||||||
field.pageName, loop.tied.nb + 1 + startNumber, totalNumber);
|
totalNumber, inPickList);
|
||||||
navInfo=(not field.isBack and not inPickList) and navInfo or '';
|
|
||||||
pageName=field.isBack and field.back.pageName or 'main'">
|
pageName=field.isBack and field.back.pageName or 'main'">
|
||||||
<x>::tied.o.getSupTitle(navInfo)</x>
|
<x>::tied.o.getSupTitle(navInfo)</x>
|
||||||
<x>::tied.o.getListTitle(nav=navInfo, target=target, page=pageName, \
|
<x>::tied.o.getListTitle(nav=navInfo, target=target, page=pageName, \
|
||||||
|
@ -105,8 +104,8 @@ class Ref(Field):
|
||||||
</td>
|
</td>
|
||||||
<!-- 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=field.getNavInfo(zobj, loop.tied.nb + 1 + startNumber, \
|
||||||
field.pageName, loop.tied.nb + 1 + startNumber, totalNumber);
|
totalNumber);
|
||||||
linkInPopup=inPopup or (target.target != '_self')"
|
linkInPopup=inPopup or (target.target != '_self')"
|
||||||
href=":tied.o.getUrl(mode='edit', page='main', nav=navInfo, \
|
href=":tied.o.getUrl(mode='edit', page='main', nav=navInfo, \
|
||||||
inPopup=linkInPopup)"
|
inPopup=linkInPopup)"
|
||||||
|
@ -149,8 +148,7 @@ class Ref(Field):
|
||||||
<input type="hidden" name="action" value="Create"/>
|
<input type="hidden" name="action" value="Create"/>
|
||||||
<input type="hidden" name="className" value=":tiedClassName"/>
|
<input type="hidden" name="className" value=":tiedClassName"/>
|
||||||
<input type="hidden" name="nav"
|
<input type="hidden" name="nav"
|
||||||
value=":'ref.%s.%s:%s.%d.%d' % (zobj.id, field.name, \
|
value=":field.getNavInfo(zobj, 0, totalNumber)"/>
|
||||||
field.pageName, 0, totalNumber)"/>
|
|
||||||
<input type="hidden" name="popup"
|
<input type="hidden" name="popup"
|
||||||
value=":(inPopup or (target.target != '_self')) and '1' or '0'"/>
|
value=":(inPopup or (target.target != '_self')) and '1' or '0'"/>
|
||||||
<input
|
<input
|
||||||
|
@ -436,6 +434,7 @@ class Ref(Field):
|
||||||
changeOrder=mayEdit and field.getAttribute(zobj, 'changeOrder');
|
changeOrder=mayEdit and field.getAttribute(zobj, 'changeOrder');
|
||||||
sortConfirm=changeOrder and _('sort_confirm');
|
sortConfirm=changeOrder and _('sort_confirm');
|
||||||
numbered=field.isNumbered(zobj);
|
numbered=field.isNumbered(zobj);
|
||||||
|
gotoNumber=numbered;
|
||||||
changeNumber=not inPickList and numbered and changeOrder and \
|
changeNumber=not inPickList and numbered and changeOrder and \
|
||||||
(totalNumber > 3);
|
(totalNumber > 3);
|
||||||
checkboxesEnabled=field.getAttribute(zobj, 'checkboxes') and \
|
checkboxesEnabled=field.getAttribute(zobj, 'checkboxes') and \
|
||||||
|
@ -1419,6 +1418,25 @@ class Ref(Field):
|
||||||
appyObj.say(msg)
|
appyObj.say(msg)
|
||||||
tool.goto(urlBack)
|
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):
|
def autoref(klass, field):
|
||||||
'''klass.field is a Ref to p_klass. This kind of auto-reference can't be
|
'''klass.field is a Ref to p_klass. This kind of auto-reference can't be
|
||||||
declared in the "normal" way, like this:
|
declared in the "normal" way, like this:
|
||||||
|
|
|
@ -155,6 +155,15 @@ class Search:
|
||||||
node['_appy_objs_cbs'] = {};
|
node['_appy_objs_cbs'] = {};
|
||||||
node['_appy_objs_sem'] = '%s';''' % (hookId, default)
|
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:
|
class UiSearch:
|
||||||
'''Instances of this class are generated on-the-fly for manipulating a
|
'''Instances of this class are generated on-the-fly for manipulating a
|
||||||
Search from the User Interface.'''
|
Search from the User Interface.'''
|
||||||
|
|
|
@ -45,7 +45,7 @@ cellDelms = ''.join(cellDelimiters.keys())
|
||||||
|
|
||||||
pxDict = {
|
pxDict = {
|
||||||
# Page-related elements
|
# Page-related elements
|
||||||
's': 'pxHeader', 'w': 'pxFields', 'n': 'pxNavigateSiblings', 'b': 'pxButtons',
|
's': 'pxHeader', 'w': 'pxFields', 'n': 'pxNavigationStrip', 'b': 'pxButtons',
|
||||||
# Field-related elements
|
# Field-related elements
|
||||||
'l': 'pxLabel', 'd': 'pxDescription', 'h': 'pxHelp', 'v': 'pxValidation',
|
'l': 'pxLabel', 'd': 'pxDescription', 'h': 'pxHelp', 'v': 'pxValidation',
|
||||||
'r': 'pxRequired', 'c': 'pxChanges'}
|
'r': 'pxRequired', 'c': 'pxChanges'}
|
||||||
|
|
|
@ -8,6 +8,7 @@ from appy.gen import utils as gutils
|
||||||
from appy.gen.mixins import BaseMixin
|
from appy.gen.mixins import BaseMixin
|
||||||
from appy.gen.wrappers import AbstractWrapper
|
from appy.gen.wrappers import AbstractWrapper
|
||||||
from appy.gen.descriptors import ClassDescriptor
|
from appy.gen.descriptors import ClassDescriptor
|
||||||
|
from appy.gen.navigate import Siblings
|
||||||
from appy.shared import mimeTypes
|
from appy.shared import mimeTypes
|
||||||
from appy.shared import utils as sutils
|
from appy.shared import utils as sutils
|
||||||
from appy.shared.data import languages
|
from appy.shared.data import languages
|
||||||
|
@ -375,15 +376,15 @@ class ToolMixin(BaseMixin):
|
||||||
# time a page for an element is consulted.
|
# time a page for an element is consulted.
|
||||||
if remember:
|
if remember:
|
||||||
if not searchName:
|
if not searchName:
|
||||||
if not search or (search.name == 'allSearch'):
|
if not search:
|
||||||
searchName = className
|
searchName = className
|
||||||
else:
|
else:
|
||||||
searchName = search.name
|
searchName = search.getSessionKey(className, full=False)
|
||||||
uids = {}
|
uids = {}
|
||||||
i = -1
|
i = -1
|
||||||
for obj in res.objects:
|
for obj in res.objects:
|
||||||
i += 1
|
i += 1
|
||||||
uids[startNumber+i] = obj.UID()
|
uids[startNumber+i] = obj.id
|
||||||
self.REQUEST.SESSION['search_%s' % searchName] = uids
|
self.REQUEST.SESSION['search_%s' % searchName] = uids
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@ -776,144 +777,9 @@ class ToolMixin(BaseMixin):
|
||||||
if not res: return ''
|
if not res: return ''
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def getQueryUrl(self, contentType, searchName, startNumber=None):
|
def getNavigationInfo(self, nav, inPopup):
|
||||||
'''This method creates the URL that allows to perform a (non-Ajax)
|
'''Produces a Siblings instance from navigation info p_nav.'''
|
||||||
request for getting queried objects from a search named p_searchName
|
return Siblings.get(nav, self, inPopup)
|
||||||
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 getGroupedSearchFields(self, searchInfo):
|
def getGroupedSearchFields(self, searchInfo):
|
||||||
'''This method transforms p_searchInfo.fields, which is a "flat"
|
'''This method transforms p_searchInfo.fields, which is a "flat"
|
||||||
|
|
|
@ -35,20 +35,17 @@ class BaseMixin:
|
||||||
|
|
||||||
def getInitiatorInfo(self, appy=False):
|
def getInitiatorInfo(self, appy=False):
|
||||||
'''Gets information about a potential initiator object from the request.
|
'''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;
|
* 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.
|
* field is the Ref instance.
|
||||||
'''
|
'''
|
||||||
rq = self.REQUEST
|
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('.')
|
splitted = rq['nav'].split('.')
|
||||||
initiator = self.getTool().getObject(splitted[1])
|
initiator = self.getTool().getObject(splitted[1])
|
||||||
fieldName, page = splitted[2].split(':')
|
field = initiator.getAppyType(splitted[2])
|
||||||
field = initiator.getAppyType(fieldName)
|
|
||||||
if appy: initiator = initiator.appy()
|
if appy: initiator = initiator.appy()
|
||||||
return initiator, page, field
|
return initiator, field
|
||||||
|
|
||||||
def createOrUpdate(self, created, values,
|
def createOrUpdate(self, created, values,
|
||||||
initiator=None, initiatorField=None):
|
initiator=None, initiatorField=None):
|
||||||
|
@ -203,7 +200,7 @@ class BaseMixin:
|
||||||
# create the object.
|
# create the object.
|
||||||
urlParams = {'mode':'edit', 'page':'main', 'nav':'',
|
urlParams = {'mode':'edit', 'page':'main', 'nav':'',
|
||||||
'inPopup':rq.get('popup') == '1'}
|
'inPopup':rq.get('popup') == '1'}
|
||||||
initiator, initiatorPage, initiatorField = self.getInitiatorInfo()
|
initiator, 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
|
||||||
# a Ref field. We create here a new navigation string with one more
|
# a Ref field. We create here a new navigation string with one more
|
||||||
|
@ -387,7 +384,8 @@ class BaseMixin:
|
||||||
isNew = self.isTemporary()
|
isNew = self.isTemporary()
|
||||||
inPopup = rq.get('popup') == '1'
|
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, initiatorField = self.getInitiatorInfo()
|
||||||
|
initiatorPage = initiatorField and initiatorField.pageName or None
|
||||||
# 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':
|
||||||
|
@ -696,6 +694,10 @@ class BaseMixin:
|
||||||
self.REQUEST.set(field.name, '')
|
self.REQUEST.set(field.name, '')
|
||||||
return self.edit()
|
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):
|
def getCreateFolder(self):
|
||||||
'''When an object must be created from this one through a Ref field, we
|
'''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
|
must know where to put the newly create object: within this one if it
|
||||||
|
|
220
gen/navigate.py
Normal file
220
gen/navigate.py
Normal 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
|
||||||
|
# ------------------------------------------------------------------------------
|
|
@ -275,6 +275,10 @@ msgstr ""
|
||||||
msgid "goto_source"
|
msgid "goto_source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Go to number"
|
||||||
|
msgid "goto_number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Whatever"
|
#. Default: "Whatever"
|
||||||
msgid "whatever"
|
msgid "whatever"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -275,6 +275,10 @@ msgstr ""
|
||||||
msgid "goto_source"
|
msgid "goto_source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. Default: "Go to number"
|
||||||
|
msgid "goto_number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Whatever"
|
#. Default: "Whatever"
|
||||||
msgid "whatever"
|
msgid "whatever"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -275,6 +275,10 @@ msgstr "Gehen Sie zum Ende"
|
||||||
msgid "goto_source"
|
msgid "goto_source"
|
||||||
msgstr "Zurück"
|
msgstr "Zurück"
|
||||||
|
|
||||||
|
#. Default: "Go to number"
|
||||||
|
msgid "goto_number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Whatever"
|
#. Default: "Whatever"
|
||||||
msgid "whatever"
|
msgid "whatever"
|
||||||
msgstr "Ohne Bedeutung"
|
msgstr "Ohne Bedeutung"
|
||||||
|
|
|
@ -276,6 +276,10 @@ msgstr "Go to end"
|
||||||
msgid "goto_source"
|
msgid "goto_source"
|
||||||
msgstr "Go back"
|
msgstr "Go back"
|
||||||
|
|
||||||
|
#. Default: "Go to number"
|
||||||
|
msgid "goto_number"
|
||||||
|
msgstr "Go to number"
|
||||||
|
|
||||||
#. Default: "Whatever"
|
#. Default: "Whatever"
|
||||||
msgid "whatever"
|
msgid "whatever"
|
||||||
msgstr "Whatever"
|
msgstr "Whatever"
|
||||||
|
|
|
@ -275,6 +275,10 @@ msgstr "Ir al final"
|
||||||
msgid "goto_source"
|
msgid "goto_source"
|
||||||
msgstr "Volver"
|
msgstr "Volver"
|
||||||
|
|
||||||
|
#. Default: "Go to number"
|
||||||
|
msgid "goto_number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Whatever"
|
#. Default: "Whatever"
|
||||||
msgid "whatever"
|
msgid "whatever"
|
||||||
msgstr "No importa"
|
msgstr "No importa"
|
||||||
|
|
|
@ -276,6 +276,10 @@ msgstr "Aller à la fin"
|
||||||
msgid "goto_source"
|
msgid "goto_source"
|
||||||
msgstr "Retour"
|
msgstr "Retour"
|
||||||
|
|
||||||
|
#. Default: "Go to number"
|
||||||
|
msgid "goto_number"
|
||||||
|
msgstr "Aller au numéro"
|
||||||
|
|
||||||
#. Default: "Whatever"
|
#. Default: "Whatever"
|
||||||
msgid "whatever"
|
msgid "whatever"
|
||||||
msgstr "Peu importe"
|
msgstr "Peu importe"
|
||||||
|
|
|
@ -275,6 +275,10 @@ msgstr "Andare alla fine"
|
||||||
msgid "goto_source"
|
msgid "goto_source"
|
||||||
msgstr "Andare indietro"
|
msgstr "Andare indietro"
|
||||||
|
|
||||||
|
#. Default: "Go to number"
|
||||||
|
msgid "goto_number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Whatever"
|
#. Default: "Whatever"
|
||||||
msgid "whatever"
|
msgid "whatever"
|
||||||
msgstr "Qualunque"
|
msgstr "Qualunque"
|
||||||
|
|
|
@ -275,6 +275,10 @@ msgstr "Ga naar het einde"
|
||||||
msgid "goto_source"
|
msgid "goto_source"
|
||||||
msgstr "Terug"
|
msgstr "Terug"
|
||||||
|
|
||||||
|
#. Default: "Go to number"
|
||||||
|
msgid "goto_number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. Default: "Whatever"
|
#. Default: "Whatever"
|
||||||
msgid "whatever"
|
msgid "whatever"
|
||||||
msgstr "Maakt niets uit"
|
msgstr "Maakt niets uit"
|
||||||
|
|
|
@ -282,6 +282,19 @@ function askRefField(hookId, objectUrl, innerRef, startNumber, action,
|
||||||
evalInnerScripts);
|
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,
|
function askField(hookId, objectUrl, layoutType, customParams, showChanges,
|
||||||
masterValues, requestValue, error, className){
|
masterValues, requestValue, error, className){
|
||||||
// Sends an Ajax request for getting the content of any field.
|
// Sends an Ajax request for getting the content of any field.
|
||||||
|
|
BIN
gen/ui/gotoNumber.png
Normal file
BIN
gen/ui/gotoNumber.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 235 B |
|
@ -47,51 +47,47 @@ class ToolWrapper(AbstractWrapper):
|
||||||
# Buttons for navigating among a list of objects (from a Ref field or a
|
# Buttons for navigating among a list of objects (from a Ref field or a
|
||||||
# query): next,back,first,last...
|
# query): next,back,first,last...
|
||||||
pxNavigate = Px('''
|
pxNavigate = Px('''
|
||||||
<div if="totalNumber > batchSize" align=":dright">
|
<div if="totalNumber > batchSize" align=":dright"
|
||||||
<table class="listNavigate"
|
var2="mustSortAndFilter=ajaxHookId == 'queryResult';
|
||||||
var="mustSortAndFilter=ajaxHookId == 'queryResult';
|
sortAndFilter=mustSortAndFilter and \
|
||||||
sortAndFilter=mustSortAndFilter and \
|
|
||||||
',%s,%s,%s' % (q(sortKey),q(sortOrder),q(filterKey)) or ''">
|
',%s,%s,%s' % (q(sortKey),q(sortOrder),q(filterKey)) or ''">
|
||||||
<tr valign="bottom">
|
|
||||||
<!-- Go to the first page -->
|
<!-- Go to the first page -->
|
||||||
<td if="(startNumber != 0) and (startNumber != batchSize)"><img
|
<img if="(startNumber != 0) and (startNumber != batchSize)"
|
||||||
class="clickable" src=":url('arrowsLeft')"
|
class="clickable" src=":url('arrowsLeft')" title=":_('goto_first')"
|
||||||
title=":_('goto_first')"
|
onClick=":navBaseCall.replace('**v**', '0'+sortAndFilter)"/>
|
||||||
onClick=":navBaseCall.replace('**v**', '0'+sortAndFilter)"/></td>
|
|
||||||
|
|
||||||
<!-- Go to the previous page -->
|
<!-- Go to the previous page -->
|
||||||
<td var="sNumber=startNumber - batchSize" if="startNumber != 0"><img
|
<img var="sNumber=startNumber - batchSize" if="startNumber != 0"
|
||||||
class="clickable" src=":url('arrowLeft')"
|
class="clickable" src=":url('arrowLeft')" title=":_('goto_previous')"
|
||||||
title=":_('goto_previous')"
|
onClick=":navBaseCall.replace('**v**', str(sNumber)+sortAndFilter)"/>
|
||||||
onClick=":navBaseCall.replace('**v**', \
|
|
||||||
str(sNumber)+sortAndFilter)"/></td>
|
|
||||||
|
|
||||||
<!-- Explain which elements are currently shown -->
|
<!-- Explain which elements are currently shown -->
|
||||||
<td class="discreet">
|
<span class="discreet">
|
||||||
<x>:startNumber + 1</x> <img src=":url('to')"/>
|
<x>:startNumber + 1</x> <img src=":url('to')"/>
|
||||||
<x>:startNumber + batchNumber</x> <b>//</b>
|
<x>:startNumber + batchNumber</x> <b>//</b>
|
||||||
<x>:totalNumber</x> </td>
|
<x>:totalNumber</x>
|
||||||
|
</span>
|
||||||
|
|
||||||
<!-- Go to the next page -->
|
<!-- Go to the next page -->
|
||||||
<td var="sNumber=startNumber + batchSize"
|
<img var="sNumber=startNumber + batchSize" if="sNumber < totalNumber"
|
||||||
if="sNumber < totalNumber"><img class="clickable"
|
class="clickable" src=":url('arrowRight')" title=":_('goto_next')"
|
||||||
src=":url('arrowRight')" title=":_('goto_next')"
|
onClick=":navBaseCall.replace('**v**', str(sNumber)+sortAndFilter)"/>
|
||||||
onClick=":navBaseCall.replace('**v**', \
|
|
||||||
str(sNumber)+sortAndFilter)"/></td>
|
|
||||||
|
|
||||||
<!-- Go to the last page -->
|
<!-- Go to the last page -->
|
||||||
<td var="lastPageIsIncomplete=totalNumber % batchSize;
|
<img var="lastPageIsIncomplete=totalNumber % batchSize;
|
||||||
nbOfCompletePages=totalNumber/batchSize;
|
nbOfCompletePages=totalNumber/batchSize;
|
||||||
nbOfCountedPages=lastPageIsIncomplete and \
|
nbOfCountedPages=lastPageIsIncomplete and \
|
||||||
nbOfCompletePages or nbOfCompletePages-1;
|
nbOfCompletePages or nbOfCompletePages-1;
|
||||||
sNumber= nbOfCountedPages * batchSize"
|
sNumber= nbOfCountedPages * batchSize"
|
||||||
if="(startNumber != sNumber) and \
|
if="(startNumber != sNumber) and \
|
||||||
(startNumber != sNumber-batchSize)"><img class="clickable"
|
(startNumber != sNumber-batchSize)" class="clickable"
|
||||||
src=":url('arrowsRight')" title=":_('goto_last')"
|
src=":url('arrowsRight')" title=":_('goto_last')"
|
||||||
onClick=":navBaseCall.replace('**v**', \
|
onClick=":navBaseCall.replace('**v**', str(sNumber)+sortAndFilter)"/>
|
||||||
str(sNumber)+sortAndFilter)"/></td>
|
|
||||||
</tr>
|
<!-- Go to the element number... -->
|
||||||
</table>
|
<x var="gotoNumber=gotoNumber|False" if="gotoNumber"
|
||||||
|
var2="sourceUrl=obj.url">:obj.pxGotoNumber</x>
|
||||||
</div>''')
|
</div>''')
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
@ -508,7 +504,7 @@ class ToolWrapper(AbstractWrapper):
|
||||||
<span class="discreet">:uiSearch.translatedDescr</span><br/>
|
<span class="discreet">:uiSearch.translatedDescr</span><br/>
|
||||||
</td>
|
</td>
|
||||||
<!-- (Top) navigation -->
|
<!-- (Top) navigation -->
|
||||||
<td align=":dright" width="150px"><x>:tool.pxNavigate</x></td>
|
<td align=":dright" width="150px">:tool.pxNavigate</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
|
@ -19,34 +19,19 @@ class AbstractWrapper(object):
|
||||||
'''Any real Appy-managed Zope object has a companion object that is an
|
'''Any real Appy-managed Zope object has a companion object that is an
|
||||||
instance of this class.'''
|
instance of this class.'''
|
||||||
|
|
||||||
# Buttons for going to next/previous objects if this one is among bunch of
|
# Input field for going to element number ...
|
||||||
# referenced or searched objects. currentNumber starts with 1.
|
pxGotoNumber = Px('''
|
||||||
pxNavigateSiblings = Px('''
|
<x var2="label=_('goto_number');
|
||||||
<div if="req.get('nav', None)" var2="ni=ztool.getNavigationInfo(inPopup)">
|
gotoName='%s_%s_goto' % (obj.id, field.name)">
|
||||||
<!-- Go to the source URL (search or referred object) -->
|
<span class="discreet" style="padding-left: 5px">:label</span>
|
||||||
<a if="not inPopup and ni.sourceUrl" href=":ni.sourceUrl"><img
|
<input type="text" size=":(len(str(totalNumber))-1) or 1"
|
||||||
var="gotoSource=_('goto_source');
|
onclick="this.select()"
|
||||||
goBack=ni.backText and ('%s - %s' % (ni.backText, gotoSource)) \
|
onkeydown=":'if (event.keyCode==13) document.getElementById' \
|
||||||
or gotoSource"
|
'(%s).click()' % q(gotoName)"/><img
|
||||||
src=":url('gotoSource')" title=":goBack"/></a>
|
id=":gotoName" name=":gotoName"
|
||||||
|
class="clickable" src=":url('gotoNumber')" title=":label"
|
||||||
<!-- Go to the first or previous page -->
|
onClick=":'gotoTied(%s,%s,this.previousSibling,%s)' % \
|
||||||
<a if="ni.firstUrl" href=":ni.firstUrl"><img title=":_('goto_first')"
|
(q(sourceUrl), q(field.name), totalNumber)"/></x>''')
|
||||||
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>''')
|
|
||||||
|
|
||||||
pxNavigationStrip = Px('''
|
pxNavigationStrip = Px('''
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
|
@ -66,7 +51,9 @@ class AbstractWrapper(object):
|
||||||
<x if="sub">::sub</x>
|
<x if="sub">::sub</x>
|
||||||
</td>
|
</td>
|
||||||
<!-- Object navigation -->
|
<!-- 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>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<!-- Object phases and pages -->
|
<!-- Object phases and pages -->
|
||||||
|
|
Loading…
Reference in a new issue