Improved advanced search screen.
This commit is contained in:
parent
d6607d7815
commit
24d0370892
|
@ -199,7 +199,12 @@ class String(Type):
|
|||
if complement:
|
||||
return (97 - (number % 97)) == checkNumber
|
||||
else:
|
||||
return (number % 97) == checkNumber
|
||||
# The check number can't be 0. In this case, we force it to be 97.
|
||||
# This is the way Belgian bank account numbers work. I hope this
|
||||
# behaviour is general enough to be implemented here.
|
||||
mod97 = (number % 97)
|
||||
if mod97 == 0: return checkNumber == 97
|
||||
else: return checkNumber == mod97
|
||||
@staticmethod
|
||||
def MODULO_97(obj, value): return String._MODULO_97(obj, value)
|
||||
@staticmethod
|
||||
|
|
|
@ -122,6 +122,8 @@ class Generator(AbstractGenerator):
|
|||
msg('search_results', '', msg.SEARCH_RESULTS),
|
||||
msg('search_results_descr', '', ' '),
|
||||
msg('search_new', '', msg.SEARCH_NEW),
|
||||
msg('search_from', '', msg.SEARCH_FROM),
|
||||
msg('search_to', '', msg.SEARCH_TO),
|
||||
msg('ref_invalid_index', '', msg.REF_INVALID_INDEX),
|
||||
msg('bad_int', '', msg.BAD_INT),
|
||||
msg('bad_float', '', msg.BAD_FLOAT),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
import re, os, os.path, Cookie
|
||||
from appy.gen import Type, Search
|
||||
from appy.gen.utils import FieldDescr, SomeObjects
|
||||
from appy.gen.utils import FieldDescr, SomeObjects, sequenceTypes
|
||||
from appy.gen.plone25.mixins import AbstractMixin
|
||||
from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
|
||||
from appy.gen.plone25.wrappers import AbstractWrapper
|
||||
|
@ -160,15 +160,30 @@ class ToolMixin(AbstractMixin):
|
|||
if search:
|
||||
# Add additional search criteria
|
||||
for fieldName, fieldValue in search.fields.iteritems():
|
||||
# Make the correspondance between the name of the field and the
|
||||
# name of the corresponding index.
|
||||
attrName = fieldName
|
||||
if attrName == 'title': attrName = 'Title'
|
||||
elif attrName == 'description': attrName = 'Description'
|
||||
elif attrName == 'state': attrName = 'review_state'
|
||||
else: attrName = 'get%s%s'% (fieldName[0].upper(),fieldName[1:])
|
||||
# Express the field value in the way needed by the index
|
||||
if isinstance(fieldValue, basestring) and \
|
||||
fieldValue.endswith('*'):
|
||||
v = fieldValue[:-1]
|
||||
params[attrName] = {'query':[v,v+'Z'], 'range':'minmax'}
|
||||
params[attrName] = {'query':(v,v+'Z'), 'range':'minmax'}
|
||||
elif type(fieldValue) in sequenceTypes:
|
||||
# We have a range of values instead of a single value
|
||||
minv, maxv = fieldValue
|
||||
rangev = 'minmax'
|
||||
queryv = fieldValue
|
||||
if minv == None:
|
||||
rangev = 'max'
|
||||
queryv = maxv
|
||||
elif maxv == None:
|
||||
rangev = 'min'
|
||||
queryv = minv
|
||||
params[attrName] = {'query':queryv, 'range':rangev}
|
||||
else:
|
||||
params[attrName] = fieldValue
|
||||
# Add a sort order if specified
|
||||
|
@ -380,6 +395,48 @@ class ToolMixin(AbstractMixin):
|
|||
else:
|
||||
return False
|
||||
|
||||
def _searchValueIsEmpty(self, key):
|
||||
'''Returns True if request value in key p_key can be considered as
|
||||
empty.'''
|
||||
rq = self.REQUEST.form
|
||||
if key.endswith('*int'):
|
||||
# We return True if "from" AND "to" values are empty.
|
||||
toKey = '%s_to' % key[2:-4]
|
||||
return not rq[key].strip() and not rq[toKey].strip()
|
||||
elif key.endswith('*date'):
|
||||
# We return True if "from" AND "to" values are empty. A value is
|
||||
# considered as not empty if at least the year is specified.
|
||||
toKey = '%s_to_year' % key[2:-5]
|
||||
return not rq[key] and not rq[toKey]
|
||||
else:
|
||||
return not rq[key]
|
||||
|
||||
def _getDateTime(self, year, month, day, setMin):
|
||||
'''Gets a valid DateTime instance from date information coming from the
|
||||
request as strings in p_year, p_month and p_day. Returns None if
|
||||
p_year is empty. If p_setMin is True, when some
|
||||
information is missing (month or day), we will replace it with the
|
||||
minimum value (=1). Else, we will replace it with the maximum value
|
||||
(=12, =31).'''
|
||||
if not year: return None
|
||||
if not month:
|
||||
if setMin: month = 1
|
||||
else: month = 12
|
||||
if not day:
|
||||
if setMin: day = 1
|
||||
else: day = 31
|
||||
DateTime = self.getProductConfig().DateTime
|
||||
# We loop until we find a valid date. For example, we could loop from
|
||||
# 2009/02/31 to 2009/02/28.
|
||||
dateIsWrong = True
|
||||
while dateIsWrong:
|
||||
try:
|
||||
res = DateTime('%s/%s/%s' % (year, month, day))
|
||||
dateIsWrong = False
|
||||
except:
|
||||
day = int(day)-1
|
||||
return res
|
||||
|
||||
def onSearchObjects(self):
|
||||
'''This method is called when the user triggers a search from
|
||||
search.pt.'''
|
||||
|
@ -387,13 +444,37 @@ class ToolMixin(AbstractMixin):
|
|||
# Store the search criteria in the session
|
||||
criteria = {}
|
||||
for attrName in rq.form.keys():
|
||||
if attrName.startswith('w_'):
|
||||
if attrName.startswith('w_') and \
|
||||
not self._searchValueIsEmpty(attrName):
|
||||
# We have a(n interval of) value(s) that is not empty for a
|
||||
# given field.
|
||||
attrValue = rq.form[attrName]
|
||||
if attrValue:
|
||||
if attrName.find('*') != -1:
|
||||
attrName, attrType = attrName.split('*')
|
||||
if attrType == 'bool':
|
||||
exec 'attrValue = %s' % attrValue
|
||||
elif attrType == 'int':
|
||||
# Get the "from" value
|
||||
if not attrValue.strip(): attrValue = None
|
||||
else: attrValue = int(attrValue)
|
||||
# Get the "to" value
|
||||
toValue = rq.form['%s_to' % attrName[2:]].strip()
|
||||
if not toValue: toValue = None
|
||||
else: toValue = int(toValue)
|
||||
attrValue = (attrValue, toValue)
|
||||
elif attrType == 'date':
|
||||
prefix = attrName[2:]
|
||||
# Get the "from" value
|
||||
year = attrValue
|
||||
month = rq.form['%s_from_month' % prefix]
|
||||
day = rq.form['%s_from_day' % prefix]
|
||||
fromDate = self._getDateTime(year, month, day, True)
|
||||
# Get the "to" value"
|
||||
year = rq.form['%s_to_year' % prefix]
|
||||
month = rq.form['%s_to_month' % prefix]
|
||||
day = rq.form['%s_to_day' % prefix]
|
||||
toDate = self._getDateTime(year, month, day, False)
|
||||
attrValue = (fromDate, toDate)
|
||||
if isinstance(attrValue, list):
|
||||
attrValue = ' OR '.join(attrValue)
|
||||
criteria[attrName[2:]] = attrValue
|
||||
|
@ -594,4 +675,12 @@ class ToolMixin(AbstractMixin):
|
|||
'''Truncates string p_value to p_numberOfChars.'''
|
||||
if len(value) > numberOfChars: return value[:numberOfChars] + '...'
|
||||
return value
|
||||
|
||||
monthsIds = {
|
||||
1: 'month_jan', 2: 'month_feb', 3: 'month_mar', 4: 'month_apr',
|
||||
5: 'month_may', 6: 'month_jun', 7: 'month_jul', 8: 'month_aug',
|
||||
9: 'month_sep', 10: 'month_oct', 11: 'month_nov', 12: 'month_dec'}
|
||||
def getMonthName(self, monthNumber):
|
||||
'''Gets the translated month name of month numbered p_monthNumber.'''
|
||||
return self.translate(self.monthsIds[int(monthNumber)], domain='plone')
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -31,15 +31,15 @@
|
|||
|
||||
<table class="no-style-table" cellpadding="0" cellspacing="0" width="100%"
|
||||
tal:define="numberOfColumns python: flavour.getAttr('numberOfSearchColumnsFor%s' % contentType)">
|
||||
<tr tal:repeat="searchRow python: tool.tabularize(searchableFields, numberOfColumns)" valign="top" class="appySearchRow">
|
||||
<td tal:repeat="searchField searchRow">
|
||||
<tr tal:repeat="searchRow python: tool.tabularize(searchableFields, numberOfColumns)" valign="top">
|
||||
<td tal:repeat="searchField searchRow" tal:attributes="width python:'%d%%' % (100/numberOfColumns)">
|
||||
<tal:field condition="searchField">
|
||||
<tal:showSearchField define="fieldName python:searchField[0];
|
||||
appyType python:searchField[1];
|
||||
widgetName python: 'w_%s' % fieldName">
|
||||
<metal:searchField use-macro="python: appFolder.skyn.widgets.macros.get('search%s' % searchField[1]['type'])"/>
|
||||
</tal:showSearchField>
|
||||
</tal:field><br/><br class="discreet"/>
|
||||
</tal:field><br class="discreet"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<metal:searchInteger define-macro="searchInteger">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
<label tal:content="python: tool.translate(appyType['label'])"></label><br>
|
||||
<tal:from define="fromName python: '%s*int' % widgetName">
|
||||
<label tal:attributes="for fromName" tal:content="python: tool.translate('search_from')"></label>
|
||||
<input type="text" tal:attributes="name fromName" size="4"/>
|
||||
</tal:from>
|
||||
<tal:to define="toName python: '%s_to' % fieldName">
|
||||
<label tal:attributes="for toName" tal:content="python: tool.translate('search_to')"></label>
|
||||
<input type="text" tal:attributes="name toName" size="4"/>
|
||||
</tal:to><br/>
|
||||
</metal:searchInteger>
|
||||
|
||||
<metal:searchFloat define-macro="searchFloat">
|
||||
|
@ -19,10 +27,11 @@
|
|||
tal:content="python: tool.truncate(tool.translate('%s_list_%s' % (appyType['label'], v)), 70)">
|
||||
</option>
|
||||
</select>
|
||||
</tal:selectSearch>
|
||||
</tal:selectSearch><br/>
|
||||
</metal:searchString>
|
||||
|
||||
<metal:searchBoolean define-macro="searchBoolean" tal:define="typedWidget python:'%s*bool' % widgetName">
|
||||
<metal:searchBoolean define-macro="searchBoolean"
|
||||
tal:define="typedWidget python:'%s*bool' % widgetName">
|
||||
<label tal:attributes="for widgetName" tal:content="python: tool.translate(appyType['label'])"></label><br>
|
||||
<tal:yes define="valueId python:'%s_yes' % fieldName">
|
||||
<input type="radio" class="noborder" value="True" tal:attributes="name typedWidget; id valueId"/>
|
||||
|
@ -35,29 +44,79 @@
|
|||
<tal:whatever define="valueId python:'%s_whatever' % fieldName">
|
||||
<input type="radio" class="noborder" value="" tal:attributes="name typedWidget; id valueId" checked="checked"/>
|
||||
<label tal:attributes="for valueId" tal:content="python: tool.translate('whatever')"></label>
|
||||
</tal:whatever>
|
||||
</tal:whatever><br/>
|
||||
</metal:searchBoolean>
|
||||
|
||||
<metal:searchDate define-macro="searchDate">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
<label tal:content="python: tool.translate(appyType['label'])"></label>
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<tal:comment replace="nothing">From</tal:comment>
|
||||
<tr tal:define="fromName python: '%s*date' % widgetName">
|
||||
<td width="10px"> </td>
|
||||
<td>
|
||||
<label tal:content="python: tool.translate('search_from')"></label>
|
||||
</td>
|
||||
<td>
|
||||
<select tal:attributes="name fromName">
|
||||
<option value="">--</option>
|
||||
<option tal:repeat="value python:range(appyType['startYear'], appyType['endYear']+1)"
|
||||
tal:content="value" tal:attributes="value value"></option>
|
||||
</select> /
|
||||
<select tal:attributes="name python: '%s_from_month' % fieldName">
|
||||
<option value="">--</option>
|
||||
<option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 13)]"
|
||||
tal:content="python:tool.getMonthName(value)" tal:attributes="value value"></option>
|
||||
</select> /
|
||||
<select tal:attributes="name python: '%s_from_day' % fieldName">
|
||||
<option value="">--</option>
|
||||
<option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 32)]"
|
||||
tal:content="value" tal:attributes="value value"></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tal:comment replace="nothing">To</tal:comment>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<label tal:content="python: tool.translate('search_to')"></label>
|
||||
</td>
|
||||
<td>
|
||||
<select tal:attributes="name python: '%s_to_year' % fieldName">
|
||||
<option value="">--</option>
|
||||
<option tal:repeat="value python:range(appyType['startYear'], appyType['endYear']+1)"
|
||||
tal:content="value" tal:attributes="value value"></option>
|
||||
</select> /
|
||||
<select tal:attributes="name python: '%s_to_month' % fieldName">
|
||||
<option value="">--</option>
|
||||
<option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 13)]"
|
||||
tal:content="python:tool.getMonthName(value)" tal:attributes="value value"></option>
|
||||
</select> /
|
||||
<select tal:attributes="name python: '%s_to_day' % fieldName">
|
||||
<option value="">--</option>
|
||||
<option tal:repeat="value python: [str(v).zfill(2) for v in range(1, 32)]"
|
||||
tal:content="value" tal:attributes="value value"></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</metal:searchDate>
|
||||
|
||||
<metal:searchFile define-macro="searchFile">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
<p tal:content="fieldName"></p>
|
||||
</metal:searchFile>
|
||||
|
||||
<metal:searchRef define-macro="searchRef">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
<p tal:content="fieldName"></p>
|
||||
</metal:searchRef>
|
||||
|
||||
<metal:searchComputed define-macro="searchComputed">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
<p tal:content="fieldName"></p>
|
||||
</metal:searchComputed>
|
||||
|
||||
<metal:searchAction define-macro="searchAction">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
<p tal:content="fieldName"></p>
|
||||
</metal:searchAction>
|
||||
|
||||
<metal:searchInfo define-macro="searchInfo">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
<p tal:content="fieldName"></p>
|
||||
</metal:searchInfo>
|
||||
|
|
Loading…
Reference in a new issue