2013-08-21 06:54:56 -05:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
# This file is part of Appy, a framework for building applications in the Python
|
|
|
|
# language. Copyright (C) 2007 Gaetan Delannay
|
|
|
|
|
|
|
|
# Appy is free software; you can redistribute it and/or modify it under the
|
|
|
|
# terms of the GNU General Public License as published by the Free Software
|
|
|
|
# Foundation; either version 3 of the License, or (at your option) any later
|
|
|
|
# version.
|
|
|
|
|
|
|
|
# Appy is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
|
|
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
|
# Appy. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
from appy.px import Px
|
|
|
|
from appy.gen import utils as gutils
|
|
|
|
from appy.gen.indexer import defaultIndexes
|
|
|
|
from appy.shared import utils as sutils
|
|
|
|
from group import Group
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
class Search:
|
|
|
|
'''Used for specifying a search for a given class.'''
|
2014-07-28 10:35:49 -05:00
|
|
|
def __init__(self, name=None, group=None, sortBy='', sortOrder='asc',
|
2014-07-25 08:07:31 -05:00
|
|
|
maxPerPage=30, default=False, colspan=1, translated=None,
|
2015-01-19 08:44:09 -06:00
|
|
|
show=True, showActions=True, translatedDescr=None,
|
|
|
|
checkboxes=False, checkboxesDefault=True, **fields):
|
2014-07-28 10:35:49 -05:00
|
|
|
# "name" is mandatory, excepted in some special cases (ie, when used as
|
|
|
|
# "select" param for a Ref field).
|
2013-08-21 06:54:56 -05:00
|
|
|
self.name = name
|
|
|
|
# Searches may be visually grouped in the portlet.
|
|
|
|
self.group = Group.get(group)
|
|
|
|
self.sortBy = sortBy
|
|
|
|
self.sortOrder = sortOrder
|
2014-07-25 08:07:31 -05:00
|
|
|
self.maxPerPage = maxPerPage
|
2013-08-21 06:54:56 -05:00
|
|
|
# If this search is the default one, it will be triggered by clicking
|
|
|
|
# on main link.
|
|
|
|
self.default = default
|
|
|
|
self.colspan = colspan
|
|
|
|
# If a translated name or description is already given here, we will
|
|
|
|
# use it instead of trying to translate from labels.
|
|
|
|
self.translated = translated
|
|
|
|
self.translatedDescr = translatedDescr
|
|
|
|
# Condition for showing or not this search
|
|
|
|
self.show = show
|
2015-01-19 08:44:09 -06:00
|
|
|
# Condition for showing or not actions on every result of this search.
|
|
|
|
# Can be: True, False or "inline". If True, actions will appear in a
|
|
|
|
# "div" tag, below the object title; if "inline", they will appear
|
|
|
|
# besides it, producing a more compact list of results.
|
|
|
|
self.showActions = showActions
|
2013-08-21 06:54:56 -05:00
|
|
|
# In the dict below, keys are indexed field names or names of standard
|
|
|
|
# indexes, and values are search values.
|
|
|
|
self.fields = fields
|
2014-07-19 06:42:39 -05:00
|
|
|
# Do we need to display checkboxes for every object of the query result?
|
|
|
|
self.checkboxes = checkboxes
|
|
|
|
# Default value for checkboxes
|
|
|
|
self.checkboxesDefault = checkboxesDefault
|
2013-08-21 06:54:56 -05:00
|
|
|
|
|
|
|
@staticmethod
|
2014-11-28 07:42:32 -06:00
|
|
|
def getIndexName(name, klass, usage='search'):
|
|
|
|
'''Gets the name of the Zope index that corresponds to p_name. Indexes
|
|
|
|
can be used for searching (p_usage="search") or for sorting
|
|
|
|
(usage="sort"). The method returns None if the field named
|
|
|
|
p_name can't be used for p_usage.'''
|
|
|
|
# Manage indexes that do not have a corresponding field
|
|
|
|
if name == 'created': return 'Created'
|
|
|
|
elif name == 'modified': return 'Modified'
|
|
|
|
elif name in defaultIndexes: return name
|
2013-08-21 06:54:56 -05:00
|
|
|
else:
|
2014-11-28 07:42:32 -06:00
|
|
|
# Manage indexes corresponding to fields
|
|
|
|
field = getattr(klass, name, None)
|
|
|
|
if field: return field.getIndexName(usage)
|
2013-08-21 06:54:56 -05:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def getSearchValue(fieldName, fieldValue, klass):
|
|
|
|
'''Returns a transformed p_fieldValue for producing a valid search
|
|
|
|
value as required for searching in the index corresponding to
|
|
|
|
p_fieldName.'''
|
|
|
|
field = getattr(klass, fieldName, None)
|
|
|
|
if (field and (field.getIndexType() == 'TextIndex')) or \
|
|
|
|
(fieldName == 'SearchableText'):
|
|
|
|
# For TextIndex indexes. We must split p_fieldValue into keywords.
|
|
|
|
res = gutils.Keywords(fieldValue).get()
|
|
|
|
elif isinstance(fieldValue, basestring) and fieldValue.endswith('*'):
|
|
|
|
v = fieldValue[:-1]
|
|
|
|
# Warning: 'z' is higher than 'Z'!
|
|
|
|
res = {'query':(v,v+'z'), 'range':'min:max'}
|
|
|
|
elif type(fieldValue) in sutils.sequenceTypes:
|
|
|
|
if fieldValue and isinstance(fieldValue[0], basestring):
|
|
|
|
# We have a list of string values (ie: we need to
|
|
|
|
# search v1 or v2 or...)
|
|
|
|
res = fieldValue
|
|
|
|
else:
|
|
|
|
# We have a range of (int, float, DateTime...) values
|
|
|
|
minv, maxv = fieldValue
|
|
|
|
rangev = 'minmax'
|
|
|
|
queryv = fieldValue
|
|
|
|
if minv == None:
|
|
|
|
rangev = 'max'
|
|
|
|
queryv = maxv
|
|
|
|
elif maxv == None:
|
|
|
|
rangev = 'min'
|
|
|
|
queryv = minv
|
|
|
|
res = {'query':queryv, 'range':rangev}
|
|
|
|
else:
|
|
|
|
res = fieldValue
|
|
|
|
return res
|
|
|
|
|
|
|
|
def updateSearchCriteria(self, criteria, klass, advanced=False):
|
|
|
|
'''This method updates dict p_criteria with all the search criteria
|
|
|
|
corresponding to this Search instance. If p_advanced is True,
|
|
|
|
p_criteria correspond to an advanced search, to be stored in the
|
|
|
|
session: in this case we need to keep the Appy names for parameters
|
|
|
|
sortBy and sortOrder (and not "resolve" them to Zope's sort_on and
|
|
|
|
sort_order).'''
|
|
|
|
# Put search criteria in p_criteria
|
2014-11-28 07:42:32 -06:00
|
|
|
for name, value in self.fields.iteritems():
|
2013-08-21 06:54:56 -05:00
|
|
|
# Management of searches restricted to objects linked through a
|
|
|
|
# Ref field: not implemented yet.
|
2014-11-28 07:42:32 -06:00
|
|
|
if name == '_ref': continue
|
2013-08-21 06:54:56 -05:00
|
|
|
# Make the correspondence between the name of the field and the
|
|
|
|
# name of the corresponding index, excepted if advanced is True: in
|
|
|
|
# that case, the correspondence will be done later.
|
|
|
|
if not advanced:
|
2014-11-28 07:42:32 -06:00
|
|
|
indexName = Search.getIndexName(name, klass)
|
2013-08-21 06:54:56 -05:00
|
|
|
# Express the field value in the way needed by the index
|
2014-11-28 07:42:32 -06:00
|
|
|
criteria[indexName] = Search.getSearchValue(name, value, klass)
|
2013-08-21 06:54:56 -05:00
|
|
|
else:
|
2014-11-28 07:42:32 -06:00
|
|
|
criteria[name] = value
|
2013-08-21 06:54:56 -05:00
|
|
|
# Add a sort order if specified
|
|
|
|
if self.sortBy:
|
2014-11-28 07:42:32 -06:00
|
|
|
c = criteria
|
2013-08-21 06:54:56 -05:00
|
|
|
if not advanced:
|
2014-11-28 07:42:32 -06:00
|
|
|
c['sort_on']=Search.getIndexName(self.sortBy,klass,usage='sort')
|
|
|
|
c['sort_order']= (self.sortOrder=='desc') and 'reverse' or None
|
2013-08-21 06:54:56 -05:00
|
|
|
else:
|
2014-11-28 07:42:32 -06:00
|
|
|
c['sortBy'] = self.sortBy
|
|
|
|
c['sortOrder'] = self.sortOrder
|
2013-08-21 06:54:56 -05:00
|
|
|
|
|
|
|
def isShowable(self, klass, tool):
|
|
|
|
'''Is this Search instance (defined in p_klass) showable?'''
|
|
|
|
if self.show.__class__.__name__ == 'staticmethod':
|
|
|
|
return gutils.callMethod(tool, self.show, klass=klass)
|
|
|
|
return self.show
|
|
|
|
|
2014-10-21 02:25:37 -05:00
|
|
|
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
|
|
|
|
|
2013-08-21 06:54:56 -05:00
|
|
|
class UiSearch:
|
|
|
|
'''Instances of this class are generated on-the-fly for manipulating a
|
|
|
|
Search from the User Interface.'''
|
2015-02-03 03:56:15 -06:00
|
|
|
# Rendering a search
|
2013-08-21 06:54:56 -05:00
|
|
|
pxView = Px('''
|
|
|
|
<div class="portletSearch">
|
|
|
|
<a href=":'%s?className=%s&search=%s' % \
|
2013-08-23 11:57:27 -05:00
|
|
|
(queryUrl, className, search.name)"
|
2014-04-29 12:02:06 -05:00
|
|
|
class=":(search.name == currentSearch) and 'current' or ''"
|
2013-08-21 15:25:27 -05:00
|
|
|
title=":search.translatedDescr">:search.translated</a>
|
2013-08-21 06:54:56 -05:00
|
|
|
</div>''')
|
|
|
|
|
2015-02-03 03:56:15 -06:00
|
|
|
# Search results, as a list (used by pxResult below)
|
|
|
|
pxResultList = Px('''
|
|
|
|
<x var="showHeaders=showHeaders|True;
|
|
|
|
checkboxes=uiSearch.search.checkboxes;
|
|
|
|
checkboxesId=rootHookId + '_objs';
|
|
|
|
cbShown=uiSearch.showCheckboxes();
|
|
|
|
cbDisplay=cbShown and 'table-cell' or 'none'">
|
|
|
|
<script>:uiSearch.getAjaxData(ajaxHookId, ztool, popup=inPopup, \
|
|
|
|
checkboxes=checkboxes, checkboxesId=checkboxesId, \
|
|
|
|
cbDisplay=cbDisplay, startNumber=startNumber, \
|
|
|
|
totalNumber=totalNumber)</script>
|
|
|
|
<table class="list" width="100%">
|
|
|
|
<!-- Headers, with filters and sort arrows -->
|
|
|
|
<tr if="showHeaders">
|
|
|
|
<th if="checkboxes" class="cbCell" style=":'display:%s' % cbDisplay">
|
|
|
|
<img src=":url('checkall')" class="clickable"
|
|
|
|
title=":_('check_uncheck')"
|
|
|
|
onclick=":'toggleAllCbs(%s)' % q(checkboxesId)"/>
|
|
|
|
</th>
|
|
|
|
<th for="column in columns"
|
|
|
|
var2="field=column.field;
|
|
|
|
sortable=field.isSortable(usage='search');
|
|
|
|
filterable=field.filterable"
|
|
|
|
width=":column.width" align=":column.align">
|
|
|
|
<x>::ztool.truncateText(_(field.labelId))</x>
|
|
|
|
<x if="(totalNumber > 1) or filterValue">:tool.pxSortAndFilter</x>
|
|
|
|
<x>:tool.pxShowDetails</x>
|
|
|
|
</th>
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
<!-- Results -->
|
|
|
|
<tr if="not zobjects">
|
|
|
|
<td colspan=":len(columns)+1">:_('query_no_result')</td>
|
|
|
|
</tr>
|
|
|
|
<x for="zobj in zobjects"
|
|
|
|
var2="@currentNumber=currentNumber + 1;
|
|
|
|
rowCss=loop.zobj.odd and 'even' or 'odd'">:obj.pxViewAsResult</x>
|
|
|
|
</table>
|
|
|
|
<!-- The button for selecting objects and closing the popup -->
|
|
|
|
<div if="inPopup and cbShown" align=":dleft">
|
|
|
|
<input type="button"
|
|
|
|
var="label=_('object_link_many'); css=ztool.getButtonCss(label)"
|
|
|
|
value=":label" class=":css" style=":url('linkMany', bg=True)"
|
|
|
|
onclick=":'onSelectObjects(%s,%s,%s,%s,%s,%s,%s)' % \
|
|
|
|
(q(rootHookId), q(uiSearch.initiator.url), \
|
|
|
|
q(uiSearch.initiatorMode), q(sortKey), q(sortOrder), \
|
|
|
|
q(filterKey), q(filterValue))"/>
|
|
|
|
</div>
|
|
|
|
<!-- Init checkboxes if present -->
|
|
|
|
<script if="checkboxes">:'initCbs(%s)' % q(checkboxesId)</script>
|
|
|
|
<script>:'initFocus(%s)' % q(ajaxHookId)</script></x>''')
|
|
|
|
|
|
|
|
# Search results, as a grid (used by pxResult below)
|
|
|
|
pxResultGrid = Px('''
|
|
|
|
<table width="100%"
|
|
|
|
var="modeElems=resultMode.split('_');
|
|
|
|
cols=(len(modeElems)==2) and int(modeElems[1]) or 4;
|
|
|
|
rows=ztool.splitList(zobjects, cols)">
|
|
|
|
<tr for="row in rows" valign="middle">
|
|
|
|
<td for="zobj in row" width=":'%d%%' % (100/cols)" align="center"
|
|
|
|
style="padding-top: 25px"
|
|
|
|
var2="obj=zobj.appy(); mayView=zobj.mayView()">
|
|
|
|
<x var="@currentNumber=currentNumber + 1"
|
|
|
|
for="column in columns"
|
|
|
|
var2="field=column.field">:field.pxRenderAsResult</x>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>''')
|
|
|
|
|
|
|
|
# Render search results
|
|
|
|
pxResult = Px('''
|
|
|
|
<div var="ajaxHookId='queryResult';
|
|
|
|
className=req['className'];
|
|
|
|
searchName=req.get('search', '');
|
|
|
|
uiSearch=uiSearch|ztool.getSearch(className,searchName,ui=True);
|
|
|
|
rootHookId=uiSearch.getRootHookId();
|
|
|
|
refInfo=ztool.getRefInfo();
|
|
|
|
refObject=refInfo[0];
|
|
|
|
refField=refInfo[1];
|
|
|
|
refUrlPart=refObject and ('&ref=%s:%s' % (refObject.id, \
|
|
|
|
refField)) or '';
|
|
|
|
startNumber=req.get('startNumber', '0');
|
|
|
|
startNumber=int(startNumber);
|
|
|
|
sortKey=req.get('sortKey', '');
|
|
|
|
sortOrder=req.get('sortOrder', 'asc');
|
|
|
|
filterKey=req.get('filterKey', '');
|
|
|
|
filterValue=req.get('filterValue', '');
|
|
|
|
queryResult=ztool.executeQuery(className, \
|
|
|
|
search=uiSearch.search, startNumber=startNumber, \
|
|
|
|
remember=True, sortBy=sortKey, sortOrder=sortOrder, \
|
|
|
|
filterKey=filterKey, filterValue=filterValue, \
|
|
|
|
refObject=refObject, refField=refField);
|
|
|
|
zobjects=queryResult.objects;
|
|
|
|
totalNumber=queryResult.totalNumber;
|
|
|
|
batchSize=queryResult.batchSize;
|
|
|
|
batchNumber=len(zobjects);
|
|
|
|
navBaseCall='askQueryResult(%s,%s,%s,%s,%s,**v**)' % \
|
|
|
|
(q(ajaxHookId), q(ztool.absolute_url()), q(className), \
|
|
|
|
q(searchName),int(inPopup));
|
|
|
|
showNewSearch=showNewSearch|True;
|
|
|
|
newSearchUrl='%s/search?className=%s%s' % \
|
|
|
|
(ztool.absolute_url(), className, refUrlPart);
|
|
|
|
showSubTitles=req.get('showSubTitles', 'true') == 'true';
|
|
|
|
klass=ztool.getAppyClass(className);
|
|
|
|
resultMode=uiSearch.getResultMode(klass);
|
|
|
|
target=ztool.getLinksTargetInfo(klass)"
|
|
|
|
id=":ajaxHookId">
|
|
|
|
|
|
|
|
<x if="zobjects or filterValue">
|
|
|
|
<!-- Display here POD templates if required -->
|
|
|
|
<table var="fields=ztool.getResultPodFields(className);
|
|
|
|
layoutType='view'"
|
|
|
|
if="not inPopup and zobjects and fields" align=":dright">
|
|
|
|
<tr>
|
|
|
|
<td var="zobj=zobjects[0]; obj=zobj.appy()"
|
|
|
|
for="field in fields"
|
|
|
|
class=":not loop.field.last and 'pod' or ''">:field.pxRender</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
<!-- The title of the search -->
|
|
|
|
<p if="not inPopup">
|
|
|
|
<x>::uiSearch.translated</x> (<span class="discreet">:totalNumber</span>)
|
|
|
|
<x if="showNewSearch and (searchName == 'customSearch')"> —
|
|
|
|
<i><a href=":newSearchUrl">:_('search_new')</a></i>
|
|
|
|
</x>
|
|
|
|
</p>
|
|
|
|
<table width="100%">
|
|
|
|
<tr valign="top">
|
|
|
|
<!-- Search description -->
|
|
|
|
<td if="uiSearch.translatedDescr">
|
|
|
|
<span class="discreet">:uiSearch.translatedDescr</span><br/>
|
|
|
|
</td>
|
|
|
|
<!-- (Top) navigation -->
|
|
|
|
<td align=":dright" width="150px">:tool.pxNavigate</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
|
|
<!-- Results, as a list or grid -->
|
|
|
|
<x var="columnLayouts=ztool.getResultColumnsLayouts(className, refInfo);
|
|
|
|
columns=ztool.getColumnsSpecifiers(className,columnLayouts,dir);
|
|
|
|
currentNumber=0">
|
|
|
|
<x if="resultMode == 'list'">:uiSearch.pxResultList</x>
|
|
|
|
<x if="resultMode != 'list'">:uiSearch.pxResultGrid</x>
|
|
|
|
</x>
|
|
|
|
|
|
|
|
<!-- (Bottom) navigation -->
|
|
|
|
<x>:tool.pxNavigate</x>
|
|
|
|
</x>
|
|
|
|
|
|
|
|
<x if="not zobjects and not filterValue">
|
|
|
|
<x>:_('query_no_result')</x>
|
|
|
|
<x if="showNewSearch and (searchName == 'customSearch')"><br/>
|
|
|
|
<i class="discreet"><a href=":newSearchUrl">:_('search_new')</a></i></x>
|
|
|
|
</x>
|
|
|
|
</div>''')
|
|
|
|
|
2013-08-21 06:54:56 -05:00
|
|
|
def __init__(self, search, className, tool):
|
|
|
|
self.search = search
|
|
|
|
self.name = search.name
|
|
|
|
self.type = 'search'
|
|
|
|
self.colspan = search.colspan
|
2015-02-03 03:56:15 -06:00
|
|
|
self.className = className
|
2015-01-19 08:44:09 -06:00
|
|
|
# Property "display" of the div tag containing actions for every search
|
|
|
|
# result.
|
|
|
|
self.showActions = search.showActions
|
|
|
|
if search.showActions == True: self.showActions = 'block'
|
2013-08-21 06:54:56 -05:00
|
|
|
if search.translated:
|
|
|
|
self.translated = search.translated
|
|
|
|
self.translatedDescr = search.translatedDescr
|
|
|
|
else:
|
2015-02-03 03:56:15 -06:00
|
|
|
# The label may be specific in some special cases
|
2013-08-21 06:54:56 -05:00
|
|
|
labelDescr = ''
|
|
|
|
if search.name == 'allSearch':
|
|
|
|
label = '%s_plural' % className
|
|
|
|
elif search.name == 'customSearch':
|
|
|
|
label = 'search_results'
|
2014-07-18 09:54:11 -05:00
|
|
|
elif search.name == '_field_':
|
|
|
|
label = None
|
2013-08-21 06:54:56 -05:00
|
|
|
else:
|
|
|
|
label = '%s_search_%s' % (className, search.name)
|
|
|
|
labelDescr = label + '_descr'
|
2014-07-18 09:54:11 -05:00
|
|
|
_ = tool.translate
|
|
|
|
self.translated = label and _(label) or ''
|
|
|
|
self.translatedDescr = labelDescr and _(labelDescr) or ''
|
2014-07-25 08:07:31 -05:00
|
|
|
|
2014-07-28 05:29:16 -05:00
|
|
|
def setInitiator(self, initiator, field, mode):
|
2014-07-25 08:07:31 -05:00
|
|
|
'''If the search is defined in an attribute Ref.select, we receive here
|
2014-07-28 05:29:16 -05:00
|
|
|
the p_initiator object, its Ref p_field and the p_mode, that can be:
|
|
|
|
- "repl" if the objects selected in the popup will replace already
|
|
|
|
tied objects;
|
|
|
|
- "add" if those objects will be added to the already tied ones.
|
|
|
|
.'''
|
2014-07-25 08:07:31 -05:00
|
|
|
self.initiator = initiator
|
|
|
|
self.initiatorField = field
|
2014-07-28 05:29:16 -05:00
|
|
|
self.initiatorMode = mode
|
|
|
|
# "initiatorHook" is the ID of the initiator field's XHTML tag.
|
|
|
|
self.initiatorHook = '%s_%s' % (initiator.uid, field.name)
|
|
|
|
|
|
|
|
def getRootHookId(self):
|
|
|
|
'''If an initiator field is there, return the initiator hook.
|
|
|
|
Else, simply return the name of the search.'''
|
|
|
|
return getattr(self, 'initiatorHook', self.name)
|
2014-07-25 08:07:31 -05:00
|
|
|
|
2015-02-03 03:56:15 -06:00
|
|
|
def getResultMode(self, klass):
|
|
|
|
'''Must we show, on pxResult, instances of p_klass as a list or
|
|
|
|
as a grid?'''
|
|
|
|
return getattr(klass, 'resultMode', 'list')
|
|
|
|
|
2014-07-25 08:07:31 -05:00
|
|
|
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()
|
2015-02-03 03:56:15 -06:00
|
|
|
|
|
|
|
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.search.checkboxesDefault and 'unchecked' or 'checked'
|
|
|
|
return '''var node=document.getElementById('%s');
|
|
|
|
node['_appy_objs_cbs'] = {};
|
|
|
|
node['_appy_objs_sem'] = '%s';''' % (hookId, default)
|
|
|
|
|
|
|
|
def getAjaxData(self, hook, ztool, **params):
|
|
|
|
'''Initializes an AjaxData object on the DOM node corresponding to
|
|
|
|
p_hook = the whole search result.'''
|
|
|
|
# Complete params with default parameters
|
|
|
|
params['className'] = self.className
|
|
|
|
params['searchName'] = self.name
|
|
|
|
params = sutils.getStringDict(params)
|
2015-02-04 11:33:27 -06:00
|
|
|
return "getAjaxHook('%s',true)['ajax']=new AjaxData('%s', " \
|
2015-02-03 03:56:15 -06:00
|
|
|
"'pxResult', %s, null, '%s')" % \
|
|
|
|
(hook, hook, params, ztool.absolute_url())
|
|
|
|
|
|
|
|
def getAjaxDataRow(self, zobj, parentHook, **params):
|
|
|
|
'''Initializes an AjaxData object on the DOM node corresponding to
|
|
|
|
p_hook = a row within the list of results.'''
|
|
|
|
hook = zobj.id
|
2015-02-04 11:33:27 -06:00
|
|
|
return "getAjaxHook('%s',true)['ajax']=new AjaxData('%s', " \
|
2015-02-03 03:56:15 -06:00
|
|
|
"'pxViewAsResultFromAjax',%s,'%s','%s')" % \
|
|
|
|
(hook, hook, sutils.getStringDict(params), parentHook,
|
|
|
|
zobj.absolute_url())
|
2013-08-21 06:54:56 -05:00
|
|
|
# ------------------------------------------------------------------------------
|