[gen] More work on Refs with popup='true'.

This commit is contained in:
Gaetan Delannay 2014-07-25 15:07:31 +02:00
parent a14bff45a7
commit 0bcd0055a3
7 changed files with 80 additions and 37 deletions

View file

@ -286,11 +286,8 @@ class Field:
def isMultiValued(self):
'''Does this type definition allow to define multiple values?'''
res = False
maxOccurs = self.multiplicity[1]
if (maxOccurs == None) or (maxOccurs > 1):
res = True
return res
return (maxOccurs == None) or (maxOccurs > 1)
def isSortable(self, usage):
'''Can fields of this type be used for sorting purposes (when sorting

View file

@ -1273,7 +1273,7 @@ class Ref(Field):
# No object can be selected if the popup has not been opened yet.
if 'semantics' not in rq:
# In this case, display already linked objects if any.
if not obj.isEmpty(self.name): return getattr(obj, self.name)
if not obj.isEmpty(self.name): return self.getValue(obj.o)
return res
uids = rq['selected'].split(',')
tool = obj.tool

View file

@ -24,16 +24,16 @@ from group import Group
# ------------------------------------------------------------------------------
class Search:
'''Used for specifying a search for a given class.'''
def __init__(self, name, group=None, sortBy='', sortOrder='asc', limit=None,
default=False, colspan=1, translated=None, show=True,
translatedDescr=None, checkboxes=False, checkboxesDefault=True,
**fields):
def __init__(self, name, group=None, sortBy='', sortOrder='asc',
maxPerPage=30, default=False, colspan=1, translated=None,
show=True, translatedDescr=None, checkboxes=False,
checkboxesDefault=True, **fields):
self.name = name
# Searches may be visually grouped in the portlet.
self.group = Group.get(group)
self.sortBy = sortBy
self.sortOrder = sortOrder
self.limit = limit
self.maxPerPage = maxPerPage
# If this search is the default one, it will be triggered by clicking
# on main link.
self.default = default
@ -188,4 +188,19 @@ class UiSearch:
_ = tool.translate
self.translated = label and _(label) or ''
self.translatedDescr = labelDescr and _(labelDescr) or ''
def setInitiator(self, initiator, field):
'''If the search is defined in an attribute Ref.select, we receive here
the p_initiator object and its Ref p_field.'''
self.initiator = initiator
self.initiatorField = field
def showCheckboxes(self):
'''If checkboxes are enabled for this search (and if an initiator field
is there), they must be visible only if the initiator field is
multivalued. Indeed, if it is not the case, it has no sense to select
multiple objects. But in this case, we still want checkboxes to be in
the DOM because they store object UIDs.'''
if not self.search.checkboxes: return
return not self.initiator or self.initiatorField.isMultiValued()
# ------------------------------------------------------------------------------

View file

@ -354,14 +354,17 @@ class ToolMixin(BaseMixin):
# Use index "Allowed" if noSecurity is False
if not noSecurity: params['Allowed'] = self.getAllowedValue()
brains = self.getPath("/catalog")(**params)
if brainsOnly:
# Return brains only.
if not maxResults or (maxResults == 'NO_LIMIT'): return brains
else: return brains[:maxResults]
# Compute maxResults
if not maxResults:
if refField: maxResults = refField.maxPerPage
else: maxResults = self.appy().numberOfResultsPerPage
elif maxResults == 'NO_LIMIT': maxResults = None
else: maxResults = search.maxPerPage or \
self.appy().numberOfResultsPerPage
elif maxResults == 'NO_LIMIT':
maxResults = None
# Return brains only if required.
if brainsOnly:
if not maxResults: return brains
else: return brains[:maxResults]
res = gutils.SomeObjects(brains, maxResults, startNumber,
noSecurity=noSecurity)
res.brainsToObjects()
@ -725,14 +728,18 @@ class ToolMixin(BaseMixin):
def getSearch(self, className, name, ui=False):
'''Gets the Search instance (or a UiSearch instance if p_ui is True)
corresponding to the search named p_name, on class p_className.'''
initiator = None
if name == 'customSearch':
# It is a custom search whose parameters are in the session.
fields = self.REQUEST.SESSION['searchCriteria']
res = Search('customSearch', **fields)
elif ':' in name:
# The search is defined in a Ref field with link=popup
refObject, ref = name.split(':')
res = getattr(self.getObject(refObject,appy=True).klass,ref).select
# The search is defined in a Ref field with link=popup. Get the
# search, the initiator object and the Ref field.
uid, ref = name.split(':')
initiator = self.getObject(uid, appy=True)
initiatorField = initiator.getField(ref)
res = getattr(initiator.klass, ref).select
elif name:
appyClass = self.getAppyClass(className)
# Search among static searches
@ -747,7 +754,9 @@ class ToolMixin(BaseMixin):
# It is the search for every instance of p_className
res = Search('allSearch')
# Return a UiSearch if required.
if ui: res = UiSearch(res, className, self)
if ui:
res = UiSearch(res, className, self)
if initiator: res.setInitiator(initiator, initiatorField)
return res
def advancedSearchEnabledFor(self, klass):

View file

@ -1041,7 +1041,6 @@ function onSelectObjects(nodeId, objectUrl, sortKey, sortOrder,
return;
}
// Close the popup.
var parent = window.parent;
closePopup('iframePopup');
/* Refresh the Ref edit widget to include the linked objects. All those
parameters are needed to replay the query in the popup. */
@ -1051,6 +1050,25 @@ function onSelectObjects(nodeId, objectUrl, sortKey, sortOrder,
'filterValue': filterValue});
}
function onSelectObject(tdId, nodeId, objectUrl) {
/* In a Ref field with link="popup", a single object has been clicked. If
multiple objects can be selected, simply update the corresponding checkbox
status. Else, close the popup and return the selected object. p_tdId is
the ID of the td that contains the checkbox. */
var td = document.getElementById(tdId);
// If the td is visible, simply click the checkbox.
var checkbox = td.getElementsByTagName('input')[0];
if (td.style.display == 'table-cell') { checkbox.click(); }
else {
/* Close the popup and directly refresh the initiator field with the
selected object. */
var uids=checkbox.value;
closePopup('iframePopup');
askField(':'+nodeId, objectUrl, 'edit', null, null, null, null, null,
{'selected': uids, 'semantics': 'checked'});
}
}
// Sets the focus on the correct element in some page.
function initFocus(pageId){
var id = pageId + '_title';

View file

@ -317,15 +317,18 @@ class ToolWrapper(AbstractWrapper):
var2="navInfo='search.%s.%s.%d.%d' % \
(className, searchName, startNumber+currentNumber, totalNumber);
cssClass=zobj.getCssFor('title')">
<x>::zobj.getSupTitle(navInfo)</x>
<x var="sup=zobj.getSupTitle(navInfo)" if="sup">::sup</x>
<a if="enableLinks" class=":cssClass"
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
style=":showSubTitles and 'display:inline' or 'display:none'"
name="subTitle">::zobj.getSubTitle()</span>
inPopup=linkInPopup)">:zobj.Title()</a>
<span if="not enableLinks"
class=":not checkboxes and cssClass or ('%s clickable' % cssClass)"
onclick=":checkboxes and ('onSelectObject(%s,%s,%s)' % (q(cbId), \
q(rootHookId), q(uiSearch.initiator.url))) or ''">:obj.title</span>
<span style=":showSubTitles and 'display:inline' or 'display:none'"
name="subTitle" var="sub=zobj.getSubTitle()" if="sub">::sub</span>
<!-- Actions -->
<table class="noStyle" if="not inPopup and zobj.mayAct()">
@ -368,7 +371,9 @@ class ToolWrapper(AbstractWrapper):
pxQueryResultList = Px('''
<x var="showHeaders=showHeaders|True;
checkboxes=uiSearch.search.checkboxes;
checkboxesId=rootHookId + '_objs'">
checkboxesId=rootHookId + '_objs';
cbShown=uiSearch.showCheckboxes();
cbDisplay=cbShown and 'display:table-cell' or 'display:none'">
<table class="list" width="100%">
<!-- Headers, with filters and sort arrows -->
<tr if="showHeaders">
@ -380,7 +385,7 @@ class ToolWrapper(AbstractWrapper):
<x>::ztool.truncateText(_(field.labelId))</x>
<x>:tool.pxSortAndFilter</x><x>:tool.pxShowDetails</x>
</th>
<th if="checkboxes" class="cbCell">
<th if="checkboxes" class="cbCell" style=":cbDisplay">
<img src=":url('checkall')" class="clickable"
title=":_('check_uncheck')"
onclick=":'toggleAllCbs(%s)' % q(checkboxesId)"/>
@ -391,30 +396,29 @@ class ToolWrapper(AbstractWrapper):
<tr if="not zobjects">
<td colspan=":len(columns)+1">:_('query_no_result')</td>
</tr>
<tr for="zobj in zobjects" id="query_row" valign="top"
<tr for="zobj in zobjects" valign="top"
var2="@currentNumber=currentNumber + 1;
obj=zobj.appy(); mayView=zobj.mayView()"
obj=zobj.appy(); mayView=zobj.mayView();
cbId='%s_%s' % (checkboxesId, currentNumber)"
class=":loop.zobj.odd and 'even' or 'odd'">
<td for="column in columns"
var2="field=column.field" id=":'field_%s' % field.name"
width=":column.width"
align=":column.align">:tool.pxQueryField</td>
<!-- A checkbox if required -->
<td if="checkboxes" class="cbCell">
<td if="checkboxes" class="cbCell" id=":cbId" style=":cbDisplay">
<input type="checkbox" name=":checkboxesId" checked="checked"
value=":zobj.id" onclick="toggleCb(this)"/>
</td>
</tr>
</table>
<!-- The button for selecting objects and closing the popup. -->
<div if="inPopup" align=":dright">
<div if="inPopup and cbShown" align=":dright">
<input type="button" class="button"
var="label=_('object_link_many');
initiator=ztool.getObject(searchName.split(':')[0], \
appy=True)"
var="label=_('object_link_many')"
value=":label"
onclick=":'onSelectObjects(%s,%s,%s,%s,%s,%s)' % (q(rootHookId), \
q(initiator.url), q(sortKey), q(sortOrder), \
q(uiSearch.initiator.url),q(sortKey),q(sortOrder), \
q(filterKey), q(filterValue))"
style=":'%s; %s' % (url('linkMany', bg=True), \
ztool.getButtonWidth(label))"/>

View file

@ -949,7 +949,7 @@ class AbstractWrapper(object):
contentType = tool.getPortalType(klass)
search = Search('customSearch', **fields)
res = tool.executeQuery(contentType, search=search, brainsOnly=True,
noSecurity=noSecurity)
noSecurity=noSecurity, maxResults='NO_LIMIT')
if res: return res._len # It is a LazyMap instance
else: return 0