221 lines
9.6 KiB
Python
221 lines
9.6 KiB
Python
|
# ------------------------------------------------------------------------------
|
||
|
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
|
||
|
# ------------------------------------------------------------------------------
|