[gen] Allow to show checkboxes for search results.

This commit is contained in:
Gaetan Delannay 2014-07-19 13:42:39 +02:00
parent b2a2aa5210
commit 792db32f27
4 changed files with 83 additions and 42 deletions

View file

@ -241,7 +241,7 @@ class Ref(Field):
<th if="checkboxes" class="cbCell"> <th if="checkboxes" class="cbCell">
<img src=":url('checkall')" class="clickable" <img src=":url('checkall')" class="clickable"
title=":_('check_uncheck')" title=":_('check_uncheck')"
onclick=":'toggleAllRefCbs(%s)' % q(ajaxHookId)"/> onclick=":'toggleAllCbs(%s)' % q(ajaxHookId)"/>
</th> </th>
</tr> </tr>
<!-- Loop on every (tied or selectable) object. --> <!-- Loop on every (tied or selectable) object. -->
@ -272,7 +272,7 @@ class Ref(Field):
</td> </td>
<td if="checkboxes" class="cbCell"> <td if="checkboxes" class="cbCell">
<input if="mayView" type="checkbox" name=":ajaxHookId" checked="checked" <input if="mayView" type="checkbox" name=":ajaxHookId" checked="checked"
value=":tiedUid" onclick="toggleRefCb(this)"/> value=":tiedUid" onclick="toggleCb(this)"/>
</td> </td>
</tr> </tr>
</table> </table>
@ -286,7 +286,7 @@ class Ref(Field):
<!-- Init checkboxes if present. --> <!-- Init checkboxes if present. -->
<script if="checkboxes" <script if="checkboxes"
type="text/javascript">:'initRefCbs(%s)' % q(ajaxHookId) type="text/javascript">:'initCbs(%s)' % q(ajaxHookId)
</script>''') </script>''')
# PX that displays the list of objects the user may select to insert into a # PX that displays the list of objects the user may select to insert into a
@ -608,7 +608,10 @@ class Ref(Field):
# NOTE that when a method is defined in field "masterValue" (see parent # NOTE that when a method is defined in field "masterValue" (see parent
# class "Field"), it will be used instead of select (or sselect below). # class "Field"), it will be used instead of select (or sselect below).
self.select = select self.select = select
if isinstance(select, Search): self.select.name = '_field_' if isinstance(select, Search):
select.name = '_field_'
select.checkboxes = True
select.checkboxesDefault = False
# If you want to specify, for the search screen, a list of objects that # If you want to specify, for the search screen, a list of objects that
# is different from the one produced by self.select, define an # is different from the one produced by self.select, define an
# alternative method in field "sselect" below. # alternative method in field "sselect" below.
@ -1145,7 +1148,7 @@ class Ref(Field):
and may hold "unchecked" (initial semantics) or "checked" (inverted and may hold "unchecked" (initial semantics) or "checked" (inverted
semantics). Inverting semantics allows to keep the array small even semantics). Inverting semantics allows to keep the array small even
when checking/unchecking all checkboxes. when checking/unchecking all checkboxes.
The mentioned JS arrays and variables are stored as attributes of the The mentioned JS arrays and variables are stored as attributes of the
DOM node representing this field.''' DOM node representing this field.'''
# The initial semantics depends on the checkboxes default value. # The initial semantics depends on the checkboxes default value.

View file

@ -26,7 +26,8 @@ class Search:
'''Used for specifying a search for a given class.''' '''Used for specifying a search for a given class.'''
def __init__(self, name, group=None, sortBy='', sortOrder='asc', limit=None, def __init__(self, name, group=None, sortBy='', sortOrder='asc', limit=None,
default=False, colspan=1, translated=None, show=True, default=False, colspan=1, translated=None, show=True,
translatedDescr=None, **fields): translatedDescr=None, checkboxes=False, checkboxesDefault=True,
**fields):
self.name = name self.name = name
# Searches may be visually grouped in the portlet. # Searches may be visually grouped in the portlet.
self.group = Group.get(group) self.group = Group.get(group)
@ -46,6 +47,10 @@ class Search:
# In the dict below, keys are indexed field names or names of standard # In the dict below, keys are indexed field names or names of standard
# indexes, and values are search values. # indexes, and values are search values.
self.fields = fields self.fields = fields
# Do we need to display checkboxes for every object of the query result?
self.checkboxes = checkboxes
# Default value for checkboxes
self.checkboxesDefault = checkboxesDefault
@staticmethod @staticmethod
def getIndexName(fieldName, usage='search'): def getIndexName(fieldName, usage='search'):
@ -140,6 +145,14 @@ class Search:
return gutils.callMethod(tool, self.show, klass=klass) return gutils.callMethod(tool, self.show, klass=klass)
return self.show return self.show
def getCbJsInit(self, hookId):
'''Returns the code that creates JS data structures for storing the
status of checkboxes for every result of this search.'''
default = self.checkboxesDefault and 'unchecked' or 'checked'
return '''var node=document.getElementById('%s');
node['_appy_objs_cbs'] = {};
node['_appy_objs_sem'] = '%s';''' % (hookId, default)
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.'''

View file

@ -224,7 +224,8 @@ function askQueryResult(hookId, objectUrl, className, searchName, popup,
params['filterValue'] = filterWidget.value; params['filterValue'] = filterWidget.value;
} }
} }
askAjaxChunk(hookId, 'GET', objectUrl, 'pxQueryResult', params); askAjaxChunk(hookId, 'GET', objectUrl, 'pxQueryResult', params, null,
evalInnerScripts);
} }
function askObjectHistory(hookId, objectUrl, maxPerPage, startNumber) { function askObjectHistory(hookId, objectUrl, maxPerPage, startNumber) {
@ -316,7 +317,7 @@ function _rsplit(s, delimiter, limit) {
} }
// (Un)checks a checkbox corresponding to a linked object. // (Un)checks a checkbox corresponding to a linked object.
function toggleRefCb(checkbox) { function toggleCb(checkbox) {
var name = checkbox.getAttribute('name'); var name = checkbox.getAttribute('name');
var elems = _rsplit(name, '_', 3); var elems = _rsplit(name, '_', 3);
// Get the DOM node corresponding to the Ref field. // Get the DOM node corresponding to the Ref field.
@ -336,8 +337,8 @@ function toggleRefCb(checkbox) {
} }
} }
// Initialise checkboxes of a Ref field. // Initialise checkboxes of a Ref field or Search.
function initRefCbs(id) { function initCbs(id) {
var elems = _rsplit(id, '_', 3); var elems = _rsplit(id, '_', 3);
// Get the DOM node corresponding to the Ref field. // Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]); var node = document.getElementById(elems[0] + '_' + elems[1]);
@ -354,8 +355,8 @@ function initRefCbs(id) {
} }
} }
// Toggle all checkboxes of a Ref field. // Toggle all checkboxes of a Ref field or Search.
function toggleAllRefCbs(id) { function toggleAllCbs(id) {
var elems = _rsplit(id, '_', 3); var elems = _rsplit(id, '_', 3);
// Get the DOM node corresponding to the Ref field. // Get the DOM node corresponding to the Ref field.
var node = document.getElementById(elems[0] + '_' + elems[1]); var node = document.getElementById(elems[0] + '_' + elems[1]);
@ -367,7 +368,7 @@ function toggleAllRefCbs(id) {
if (node[semAttr] == 'unchecked') node[semAttr] = 'checked'; if (node[semAttr] == 'unchecked') node[semAttr] = 'checked';
else node[semAttr] = 'unchecked'; else node[semAttr] = 'unchecked';
// Update the visible checkboxes // Update the visible checkboxes
initRefCbs(id); initCbs(id);
} }
// Shows/hides a dropdown menu // Shows/hides a dropdown menu

View file

@ -361,30 +361,47 @@ class ToolWrapper(AbstractWrapper):
# Show query results as a list. # Show query results as a list.
pxQueryResultList = Px(''' pxQueryResultList = Px('''
<table class="list" width="100%" var="showHeaders=showHeaders|True"> <x var="showHeaders=showHeaders|True;
<!-- Headers, with filters and sort arrows --> checkboxes=uiSearch.search.checkboxes;
<tr if="showHeaders"> checkboxesId=rootHookId + '_objs'">
<th for="column in columns" <table class="list" width="100%">
var2="field=column.field; <!-- Headers, with filters and sort arrows -->
sortable=ztool.isSortable(field.name, className, 'search'); <tr if="showHeaders">
filterable=field.filterable" <th for="column in columns"
width=":column.width" align=":column.align"> var2="field=column.field;
<x>::ztool.truncateText(_(field.labelId))</x> sortable=ztool.isSortable(field.name, className, 'search');
<x>:tool.pxSortAndFilter</x><x>:tool.pxShowDetails</x> filterable=field.filterable"
</th> width=":column.width" align=":column.align">
</tr> <x>::ztool.truncateText(_(field.labelId))</x>
<x>:tool.pxSortAndFilter</x><x>:tool.pxShowDetails</x>
</th>
<th if="checkboxes" class="cbCell">
<img src=":url('checkall')" class="clickable"
title=":_('check_uncheck')"
onclick=":'toggleAllCbs(%s)' % q(checkboxesId)"/>
</th>
</tr>
<!-- Results --> <!-- Results -->
<tr for="zobj in zobjects" id="query_row" valign="top" <tr for="zobj in zobjects" id="query_row" valign="top"
var2="@currentNumber=currentNumber + 1; var2="@currentNumber=currentNumber + 1;
obj=zobj.appy(); mayView=zobj.mayView()" obj=zobj.appy(); mayView=zobj.mayView()"
class=":loop.zobj.odd and 'even' or 'odd'"> class=":loop.zobj.odd and 'even' or 'odd'">
<td for="column in columns" <td for="column in columns"
var2="field=column.field" id=":'field_%s' % field.name" var2="field=column.field" id=":'field_%s' % field.name"
width=":column.width" width=":column.width"
align=":column.align">:tool.pxQueryField</td> align=":column.align">:tool.pxQueryField</td>
</tr> <!-- A checkbox if required -->
</table>''') <td if="checkboxes" class="cbCell">
<input type="checkbox" name=":checkboxesId" checked="checked"
value=":zobj.id" onclick="toggleCb(this)"/>
</td>
</tr>
</table>
<!-- Init checkboxes if present. -->
<script if="checkboxes"
type="text/javascript">:'initCbs(%s)' % q(checkboxesId)
</script></x>''')
# Show query results as a grid. # Show query results as a grid.
pxQueryResultGrid = Px(''' pxQueryResultGrid = Px('''
@ -405,9 +422,12 @@ class ToolWrapper(AbstractWrapper):
# Show paginated query results as a list or grid. # Show paginated query results as a list or grid.
pxQueryResult = Px(''' pxQueryResult = Px('''
<div id="queryResult" <div var="ajaxHookId='queryResult';
var="_=ztool.translate; _=ztool.translate;
className=req['className']; className=req['className'];
searchName=req.get('search', '');
rootHookId=rootHookId|'%s_search' % className;
uiSearch=uiSearch|ztool.getSearch(className,searchName,ui=True);
refInfo=ztool.getRefInfo(); refInfo=ztool.getRefInfo();
refObject=refInfo[0]; refObject=refInfo[0];
refField=refInfo[1]; refField=refInfo[1];
@ -415,8 +435,6 @@ class ToolWrapper(AbstractWrapper):
refField)) or ''; refField)) or '';
startNumber=req.get('startNumber', '0'); startNumber=req.get('startNumber', '0');
startNumber=int(startNumber); startNumber=int(startNumber);
searchName=req.get('search', '');
uiSearch=ztool.getSearch(className, searchName, ui=True);
sortKey=req.get('sortKey', ''); sortKey=req.get('sortKey', '');
sortOrder=req.get('sortOrder', 'asc'); sortOrder=req.get('sortOrder', 'asc');
filterKey=req.get('filterKey', ''); filterKey=req.get('filterKey', '');
@ -430,7 +448,6 @@ class ToolWrapper(AbstractWrapper):
totalNumber=queryResult.totalNumber; totalNumber=queryResult.totalNumber;
batchSize=queryResult.batchSize; batchSize=queryResult.batchSize;
batchNumber=len(zobjects); batchNumber=len(zobjects);
ajaxHookId='queryResult';
navBaseCall='askQueryResult(%s,%s,%s,%s,%s,**v**)' % \ navBaseCall='askQueryResult(%s,%s,%s,%s,%s,**v**)' % \
(q(ajaxHookId), q(ztool.absolute_url()), q(className), \ (q(ajaxHookId), q(ztool.absolute_url()), q(className), \
q(searchName),int(inPopup)); q(searchName),int(inPopup));
@ -440,7 +457,8 @@ class ToolWrapper(AbstractWrapper):
(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))"> target=ztool.getLinksTargetInfo(ztool.getAppyClass(className))"
id=":ajaxHookId">
<x if="zobjects"> <x if="zobjects">
<!-- Display here POD templates if required. --> <!-- Display here POD templates if required. -->
@ -492,10 +510,16 @@ class ToolWrapper(AbstractWrapper):
</div>''') </div>''')
pxQuery = Px(''' pxQuery = Px('''
<x var="className=req['className']; searchName=req.get('search', ''); <div var="className=req['className'];
cssJs=None"> searchName=req.get('search', '');
<x>:tool.pxPagePrologue</x><x>:tool.pxQueryResult</x> uiSearch=ztool.getSearch(className, searchName, ui=True);
</x>''', template=AbstractWrapper.pxTemplate, hook='content') rootHookId='%s_search' % className;
cssJs=None"
id=":rootHookId">
<script type="text/javascript">:uiSearch.search.getCbJsInit(rootHookId)
</script>
<x if="not inPopup">:tool.pxPagePrologue</x><x>:tool.pxQueryResult</x>
</div>''', template=AbstractWrapper.pxTemplate, hook='content')
pxSearch = Px(''' pxSearch = Px('''
<x var="className=req['className']; <x var="className=req['className'];