Ready for an 'advanced search' functionality.
This commit is contained in:
parent
2ff08258bc
commit
f8baeee4f7
|
@ -90,47 +90,52 @@ class Generator(AbstractGenerator):
|
|||
# Some global i18n messages
|
||||
poMsg = msg(app, '', app); poMsg.produceNiceDefault()
|
||||
self.labels += [poMsg,
|
||||
msg('workflow_state', '', msg.WORKFLOW_STATE),
|
||||
msg('data_change', '', msg.DATA_CHANGE),
|
||||
msg('modified_field', '', msg.MODIFIED_FIELD),
|
||||
msg('previous_value', '', msg.PREVIOUS_VALUE),
|
||||
msg('phase', '', msg.PHASE),
|
||||
msg('root_type', '', msg.ROOT_TYPE),
|
||||
msg('workflow_comment', '', msg.WORKFLOW_COMMENT),
|
||||
msg('choose_a_value', '', msg.CHOOSE_A_VALUE),
|
||||
msg('choose_a_doc', '', msg.CHOOSE_A_DOC),
|
||||
msg('min_ref_violated', '', msg.MIN_REF_VIOLATED),
|
||||
msg('max_ref_violated', '', msg.MAX_REF_VIOLATED),
|
||||
msg('no_ref', '', msg.REF_NO),
|
||||
msg('add_ref', '', msg.REF_ADD),
|
||||
msg('ref_name', '', msg.REF_NAME),
|
||||
msg('ref_actions', '', msg.REF_ACTIONS),
|
||||
msg('move_up', '', msg.REF_MOVE_UP),
|
||||
msg('move_down', '', msg.REF_MOVE_DOWN),
|
||||
msg('query_create', '', msg.QUERY_CREATE),
|
||||
msg('query_import', '', msg.QUERY_IMPORT),
|
||||
msg('query_no_result', '', msg.QUERY_NO_RESULT),
|
||||
msg('query_consult_all', '', msg.QUERY_CONSULT_ALL),
|
||||
msg('import_title', '', msg.IMPORT_TITLE),
|
||||
msg('import_show_hide', '', msg.IMPORT_SHOW_HIDE),
|
||||
msg('import_already', '', msg.IMPORT_ALREADY),
|
||||
msg('import_many', '', msg.IMPORT_MANY),
|
||||
msg('import_done', '', msg.IMPORT_DONE),
|
||||
msg('ref_invalid_index', '', msg.REF_INVALID_INDEX),
|
||||
msg('bad_int', '', msg.BAD_INT),
|
||||
msg('bad_float', '', msg.BAD_FLOAT),
|
||||
msg('bad_email', '', msg.BAD_EMAIL),
|
||||
msg('bad_url', '', msg.BAD_URL),
|
||||
msg('bad_alphanumeric', '', msg.BAD_ALPHANUMERIC),
|
||||
msg('select_delesect', '', msg.SELECT_DESELECT),
|
||||
msg('no_elem_selected', '', msg.NO_SELECTION),
|
||||
msg('delete_confirm', '', msg.DELETE_CONFIRM),
|
||||
msg('delete_done', '', msg.DELETE_DONE),
|
||||
msg('goto_first', '', msg.GOTO_FIRST),
|
||||
msg('goto_previous', '', msg.GOTO_PREVIOUS),
|
||||
msg('goto_next', '', msg.GOTO_NEXT),
|
||||
msg('goto_last', '', msg.GOTO_LAST),
|
||||
msg('goto_source', '', msg.GOTO_SOURCE),
|
||||
msg('workflow_state', '', msg.WORKFLOW_STATE),
|
||||
msg('data_change', '', msg.DATA_CHANGE),
|
||||
msg('modified_field', '', msg.MODIFIED_FIELD),
|
||||
msg('previous_value', '', msg.PREVIOUS_VALUE),
|
||||
msg('phase', '', msg.PHASE),
|
||||
msg('root_type', '', msg.ROOT_TYPE),
|
||||
msg('workflow_comment', '', msg.WORKFLOW_COMMENT),
|
||||
msg('choose_a_value', '', msg.CHOOSE_A_VALUE),
|
||||
msg('choose_a_doc', '', msg.CHOOSE_A_DOC),
|
||||
msg('min_ref_violated', '', msg.MIN_REF_VIOLATED),
|
||||
msg('max_ref_violated', '', msg.MAX_REF_VIOLATED),
|
||||
msg('no_ref', '', msg.REF_NO),
|
||||
msg('add_ref', '', msg.REF_ADD),
|
||||
msg('ref_name', '', msg.REF_NAME),
|
||||
msg('ref_actions', '', msg.REF_ACTIONS),
|
||||
msg('move_up', '', msg.REF_MOVE_UP),
|
||||
msg('move_down', '', msg.REF_MOVE_DOWN),
|
||||
msg('query_create', '', msg.QUERY_CREATE),
|
||||
msg('query_import', '', msg.QUERY_IMPORT),
|
||||
msg('query_no_result', '', msg.QUERY_NO_RESULT),
|
||||
msg('query_consult_all', '', msg.QUERY_CONSULT_ALL),
|
||||
msg('import_title', '', msg.IMPORT_TITLE),
|
||||
msg('import_show_hide', '', msg.IMPORT_SHOW_HIDE),
|
||||
msg('import_already', '', msg.IMPORT_ALREADY),
|
||||
msg('import_many', '', msg.IMPORT_MANY),
|
||||
msg('import_done', '', msg.IMPORT_DONE),
|
||||
msg('search_title', '', msg.SEARCH_TITLE),
|
||||
msg('search_button', '', msg.SEARCH_BUTTON),
|
||||
msg('search_objects', '', msg.SEARCH_OBJECTS),
|
||||
msg('search_results', '', msg.SEARCH_RESULTS),
|
||||
msg('search_results_descr', '', ' '),
|
||||
msg('ref_invalid_index', '', msg.REF_INVALID_INDEX),
|
||||
msg('bad_int', '', msg.BAD_INT),
|
||||
msg('bad_float', '', msg.BAD_FLOAT),
|
||||
msg('bad_email', '', msg.BAD_EMAIL),
|
||||
msg('bad_url', '', msg.BAD_URL),
|
||||
msg('bad_alphanumeric', '', msg.BAD_ALPHANUMERIC),
|
||||
msg('select_delesect', '', msg.SELECT_DESELECT),
|
||||
msg('no_elem_selected', '', msg.NO_SELECTION),
|
||||
msg('delete_confirm', '', msg.DELETE_CONFIRM),
|
||||
msg('delete_done', '', msg.DELETE_DONE),
|
||||
msg('goto_first', '', msg.GOTO_FIRST),
|
||||
msg('goto_previous', '', msg.GOTO_PREVIOUS),
|
||||
msg('goto_next', '', msg.GOTO_NEXT),
|
||||
msg('goto_last', '', msg.GOTO_LAST),
|
||||
msg('goto_source', '', msg.GOTO_SOURCE),
|
||||
]
|
||||
# Create basic files (config.py, Install.py, etc)
|
||||
self.generateTool()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
import re, os, os.path, Cookie
|
||||
from appy.gen import Type
|
||||
from appy.gen.utils import FieldDescr, SomeObjects
|
||||
from appy.gen.plone25.mixins import AbstractMixin
|
||||
from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
|
||||
|
@ -111,12 +112,19 @@ class ToolMixin(AbstractMixin):
|
|||
'''Executes a query on a given p_contentType (or several, separated
|
||||
with commas) in Plone's portal_catalog. Portal types are from the
|
||||
flavour numbered p_flavourNumber. If p_searchName is specified, it
|
||||
corresponds to a search defined on p_contentType: additional search
|
||||
criteria will be added to the query. We will retrieve objects from
|
||||
p_startNumber. If p_search is defined, it corresponds to a custom
|
||||
Search instance (instead of a predefined named search like in
|
||||
p_searchName). If both p_searchName and p_search are given, p_search
|
||||
is ignored. This method returns a list of objects in the form of the
|
||||
corresponds to:
|
||||
1) a search defined on p_contentType: additional search criteria
|
||||
will be added to the query, or;
|
||||
2) "_advanced": in this case, additional search criteria will also
|
||||
be added to the query, but those criteria come from the session
|
||||
and were created from search.pt.
|
||||
|
||||
We will retrieve objects from p_startNumber. If p_search is defined,
|
||||
it corresponds to a custom Search instance (instead of a predefined
|
||||
named search like in p_searchName). If both p_searchName and p_search
|
||||
are given, p_search is ignored.
|
||||
|
||||
This method returns a list of objects in the form of the
|
||||
__dict__ attribute of an instance of SomeObjects (see in
|
||||
appy.gen.utils). We return the __dict__ attribute instead of real
|
||||
instance: that way, it can be used in ZPTs without security problems.
|
||||
|
@ -143,8 +151,9 @@ class ToolMixin(AbstractMixin):
|
|||
# In this case, contentType must contain a single content type.
|
||||
appyClass = self.getAppyClass(contentType)
|
||||
if searchName:
|
||||
search = ArchetypesClassDescriptor.getSearch(
|
||||
appyClass, searchName)
|
||||
if searchName != '_advanced':
|
||||
search = ArchetypesClassDescriptor.getSearch(
|
||||
appyClass, searchName)
|
||||
if search:
|
||||
# Add additional search criteria
|
||||
for fieldName, fieldValue in search.fields.iteritems():
|
||||
|
@ -362,6 +371,26 @@ class ToolMixin(AbstractMixin):
|
|||
else:
|
||||
return False
|
||||
|
||||
def getSearchableFields(self, contentType):
|
||||
'''Returns the list of fields that may be searched on objects on type
|
||||
p_contentType (=indexed fields).'''
|
||||
appyClass = self.getAppyClass(contentType)
|
||||
res = []
|
||||
for attrName in dir(appyClass):
|
||||
attr = getattr(appyClass, attrName)
|
||||
if isinstance(attr, Type) and attr.indexed:
|
||||
dAttr = self._appy_getTypeAsDict(attrName, attr, appyClass)
|
||||
res.append((attrName, dAttr))
|
||||
return res
|
||||
|
||||
def onSearchObjects(self):
|
||||
'''This method is called when the user triggers a search from
|
||||
search.pt.'''
|
||||
rq = self.REQUEST
|
||||
backUrl = '%s/query?type_name=%s&flavourNumber=%d&search=_advanced' % \
|
||||
(os.path.dirname(rq['URL']), rq['type_name'], rq['flavourNumber'])
|
||||
return self.goto(backUrl)
|
||||
|
||||
def getJavascriptMessages(self):
|
||||
'''Returns the translated version of messages that must be shown in
|
||||
Javascript popups.'''
|
||||
|
|
|
@ -639,7 +639,7 @@
|
|||
startNumber request/startNumber|python:'0';
|
||||
startNumber python: int(startNumber);
|
||||
searchName request/search;
|
||||
searchLabel python: '%s_search_%s' % (contentType, searchName);
|
||||
searchLabel python: test(searchName=='_advanced', 'search_results', '%s_search_%s' % (contentType, searchName));
|
||||
searchDescr python: '%s_descr' % searchLabel;
|
||||
severalTypes python: contentType and (contentType.find(',') != -1);
|
||||
queryResult python: tool.executeQuery(contentType, flavourNumber, searchName, startNumber, remember=True);
|
||||
|
@ -909,6 +909,11 @@
|
|||
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/import?type_name=%s\'' % (appFolder.absolute_url(), rootClass);
|
||||
src string: $portal_url/skyn/import.png;
|
||||
title python: tool.translate('query_import')"/>
|
||||
<tal:comment replace="nothing">Search objects of this type (todo: update flavourNumber)</tal:comment>
|
||||
<img style="cursor:pointer"
|
||||
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/search?type_name=%s&flavourNumber=1\'' % (appFolder.absolute_url(), rootClass);
|
||||
src string: $portal_url/skyn/search.gif;
|
||||
title python: tool.translate('search_objects')"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
BIN
gen/plone25/skin/search.gif
Executable file
BIN
gen/plone25/skin/search.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 433 B |
44
gen/plone25/skin/search.pt
Normal file
44
gen/plone25/skin/search.pt
Normal file
|
@ -0,0 +1,44 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
|
||||
lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal"
|
||||
xmlns:metal="http://xml.zope.org/namespaces/metal"
|
||||
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
|
||||
metal:use-macro="here/main_template/macros/master">
|
||||
|
||||
<tal:comment replace="nothing">Disable standard Plone green tabs</tal:comment>
|
||||
<div metal:fill-slot="top_slot">
|
||||
<metal:block metal:use-macro="here/global_defines/macros/defines" />
|
||||
<div tal:define="dummy python:request.set('disable_border', 1)" />
|
||||
</div>
|
||||
|
||||
<tal:comment replace="nothing">Fill main slot of Plone main_template</tal:comment>
|
||||
<body>
|
||||
<metal:fill fill-slot="main"
|
||||
tal:define="appFolder context/getParentNode;
|
||||
contentType request/type_name;
|
||||
tool python: portal.get('portal_%s' % appFolder.id.lower());
|
||||
searchableFields python: tool.getSearchableFields(contentType)">
|
||||
|
||||
<tal:comment replace="nothing">Search title</tal:comment>
|
||||
<h1 tal:content="python: tool.translate('search_title')"></h1><br/>
|
||||
|
||||
<tal:comment replace="nothing">Form for searching objects of request/type_name.</tal:comment>
|
||||
<form name="search" tal:attributes="action python: appFolder.absolute_url()+'/skyn/do'" method="post">
|
||||
<input type="hidden" name="action" value="SearchObjects"/>
|
||||
<input type="hidden" name="type_name" tal:attributes="value contentType"/>
|
||||
<input type="hidden" name="flavourNumber:int" tal:attributes="value request/flavourNumber"/>
|
||||
|
||||
<tal:searchFields repeat="searchField searchableFields">
|
||||
<tal:showSearchField define="fieldName python:searchField[0];
|
||||
appyType python:searchField[1]">
|
||||
<metal:searchField use-macro="python: appFolder.skyn.widgets.macros.get('search%s' % searchField[1]['type'])"/>
|
||||
</tal:showSearchField>
|
||||
</tal:searchFields>
|
||||
|
||||
<tal:comment replace="nothing">Submit button</tal:comment>
|
||||
<p align="right"><br/>
|
||||
<input type="submit" tal:attributes="value python:tool.translate('search_button')"/>
|
||||
</p>
|
||||
</form>
|
||||
</metal:fill>
|
||||
</body>
|
||||
</html>
|
39
gen/plone25/skin/widgets.pt
Normal file
39
gen/plone25/skin/widgets.pt
Normal file
|
@ -0,0 +1,39 @@
|
|||
<metal:searchInteger define-macro="searchInteger">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchInteger>
|
||||
|
||||
<metal:searchFloat define-macro="searchFloat">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchFloat>
|
||||
|
||||
<metal:searchString define-macro="searchString">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchString>
|
||||
|
||||
<metal:searchBoolean define-macro="searchBoolean">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchBoolean>
|
||||
|
||||
<metal:searchDate define-macro="searchDate">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchDate>
|
||||
|
||||
<metal:searchFile define-macro="searchFile">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchFile>
|
||||
|
||||
<metal:searchRef define-macro="searchRef">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchRef>
|
||||
|
||||
<metal:searchComputed define-macro="searchComputed">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchComputed>
|
||||
|
||||
<metal:searchAction define-macro="searchAction">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchAction>
|
||||
|
||||
<metal:searchInfo define-macro="searchInfo">
|
||||
<p tal:content="fieldName">Hello</p>
|
||||
</metal:searchInfo>
|
|
@ -57,6 +57,10 @@ class PoMessage:
|
|||
IMPORT_ALREADY = 'Already imported.'
|
||||
IMPORT_MANY = 'Import selected elements'
|
||||
IMPORT_DONE = 'Import terminated successfully.'
|
||||
SEARCH_TITLE = 'Advanced search'
|
||||
SEARCH_BUTTON = 'Search'
|
||||
SEARCH_OBJECTS = 'Search objects of this type.'
|
||||
SEARCH_RESULTS = 'Search results'
|
||||
WORKFLOW_COMMENT = 'Optional comment'
|
||||
WORKFLOW_STATE = 'state'
|
||||
DATA_CHANGE = 'Data change'
|
||||
|
|
2
version.py
Normal file
2
version.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
short='dev'
|
||||
verbose='dev'
|
Loading…
Reference in a new issue