add search on authors, complete with autocomplete and label boxes

This commit is contained in:
Frédéric Péters 2011-11-06 21:22:52 +01:00
parent 21dbad9943
commit 219a0b88e0
4 changed files with 139 additions and 29 deletions

View File

@ -0,0 +1,6 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal"
tal:omit-tag="">
<input type="hidden" tal:attributes="id view/id; name view/name;"/>
<input class="author-autocomplete" type="text" tal:attributes="name string:${view/name}-query"/>
</html>

View File

@ -5,6 +5,7 @@
xmlns:i18n="http://namespaces.zope.org/i18n"
xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:z3c="http://namespaces.zope.org/z3c"
i18n_domain="tabellio.searchform">
<!-- Include z3c.form as dependency -->
@ -19,6 +20,12 @@
template="docsearch.pt"
permission="zope2.View"/>
<browser:page
for=".form.IFolderWithDocuments"
name="listAuthors"
class=".form.ListAuthorsView"
permission="zope2.View"/>
<browser:page
for=".form.IFolderWithPfbDocuments"
name="folder_listing"
@ -39,4 +46,11 @@
template="guided-search.pt"
permission="zope2.View"/>
<z3c:widgetTemplate
mode="input"
widget=".form.IAuthorsWidget"
layer="z3c.form.interfaces.IFormLayer"
template="authors_input.pt"
/>
</configure>

View File

@ -159,6 +159,38 @@
<div tal:replace="structure provider:plone.belowcontentbody" />
<script type="text/javascript">
function update_authors_input(input) {
var s = '';
jq(input).nextAll('span.labelbox').each(function() {
s = s + ' ' + jq(this).attr('class').split(' ')[1];
});
jq(input).attr('value', s);
}
function author_autocomplete_ready(event, data, formatted) {
(function($) {
var input_box = $(event.target);
// XXX: don't insert item if it's already present
labelbox = $('<span class="labelbox ' + data[1] + '">' + data[0] + '<' + '/span>');
$(input_box).before(labelbox);
$(labelbox).click(function() {
$(this).remove();
update_authors_input(jq(input_box).prevAll('input')[0]);
});
update_authors_input(jq(input_box).prevAll('input')[0]);
$(input_box).attr('value', '');
}(jQuery));
}
(function($) {
$().ready(function() {
$('.author-autocomplete').autocomplete('./listAuthors', {
}).result(author_autocomplete_ready);
});
})(jQuery);
</script>
</tal:main-macro>
</metal:main>

View File

@ -1,11 +1,17 @@
# -*- coding: utf-8 -*-
from five import grok
from zope import interface, schema
from zope import interface, schema, component
from z3c.form import form, field, button
from plone.z3cform.layout import wrap_form
from Products.CMFCore.utils import getToolByName
from zope.interface import implements
from z3c.form.ptcompat import ViewPageTemplateFile
import z3c.form.interfaces
from z3c.form.browser import text
from z3c.form import widget
from z3c.form.interfaces import ITextWidget
from z3c.relationfield.schema import RelationChoice, RelationList
from plone.formwidget.contenttree import ObjPathSourceBinder
@ -17,9 +23,56 @@ from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from zope.schema.interfaces import IContextSourceBinder
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
from plone.registry.interfaces import IRegistry
from tabellio.config.interfaces import ITabellioSettings
import tabellio.config.utils
class ListAuthorsView(BrowserView):
def get_folder_at_path(self, path):
current = self.portal
for part in path.split('/'):
if not part:
continue
current = getattr(current, part)
return current
_deputies_folder = None
def deputies_folder(self):
if self._deputies_folder:
return self._deputies_folder
path = self.settings.deputiesPath
self._deputies_folder = self.get_folder_at_path(path)
return self._deputies_folder
deputies_folder = property(deputies_folder)
def __call__(self):
self.portal = getToolByName(self.context, 'portal_url').getPortalObject()
self.settings = component.getUtility(IRegistry).forInterface(ITabellioSettings, False)
self.request.response.setHeader('Content-type', 'text/plain')
s = []
q = self.request.form.get('q').lower()
for object in self.deputies_folder.objectValues():
if object.portal_type != 'themis.datatypes.deputy':
continue
if q in object.id or q in object.Title().lower():
s.append(object)
return '\n'.join(['%s|%s' % (x.Title(), x.id) for x in s])
class IAuthorsWidget(ITextWidget):
pass
class AuthorsWidget(text.TextWidget):
implements(IAuthorsWidget)
klass = u'authors'
def FieldAuthorsWidget(field, request):
return widget.FieldWidget(field, AuthorsWidget(request))
class IFolderWithDocuments(interface.Interface):
pass
@ -80,10 +133,8 @@ class IDocumentSearch(interface.Interface):
#subjects =
ttitle = schema.TextLine(title=_(u'Title'), required=False)
text = schema.TextLine(title=_(u'Text'), required=False)
authors = RelationList(title=_(u'Authors'), default=[], required=False,
value_type=RelationChoice(title=_(u'Author'),
source=ObjPathSourceBinder(
portal_type=['themis.datatypes.deputy'])))
authors = schema.TextLine(title=_(u'Authors'), required=False)
# polgroups
session = schema.Choice(title=_(u'Legislature / Session'), required=False,
source=possible_sessions)
@ -93,7 +144,9 @@ class IDocumentSearch(interface.Interface):
class DocumentSearchForm(form.Form):
method = 'get'
prefix = 'document'
fields = field.Fields(IDocumentSearch)
fields['authors'].widgetFactory = FieldAuthorsWidget
ignoreContext = True
template = ViewPageTemplateFile('form_templates/view_effectivesearch.pt')
@ -119,10 +172,7 @@ class IDossierSearch(interface.Interface):
source=possible_dossier_types)
#subjects =
ttitle = schema.TextLine(title=_(u'Title'), required=False)
authors = RelationList(title=_(u'Authors'), default=[], required=False,
value_type=RelationChoice(title=_(u'Author'),
source=ObjPathSourceBinder(
portal_type=['themis.datatypes.deputy'])))
authors = schema.TextLine(title=_(u'Authors'), required=False)
# polgroups
session = schema.Choice(title=_(u'Legislature / Session'), required=False,
source=possible_sessions)
@ -131,8 +181,10 @@ class IDossierSearch(interface.Interface):
class DossierSearchForm(form.Form):
prefix = 'dossier'
method = 'get'
fields = field.Fields(IDossierSearch)
fields['authors'].widgetFactory = FieldAuthorsWidget
ignoreContext = True
template = ViewPageTemplateFile('form_templates/view_dossier_search.pt')
@ -157,10 +209,7 @@ class IQuestionSearch(interface.Interface):
source=possible_question_types)
#subjects =
ttitle = schema.TextLine(title=_(u'Title'), required=False)
authors = RelationList(title=_(u'Authors'), default=[], required=False,
value_type=RelationChoice(title=_(u'Author'),
source=ObjPathSourceBinder(
portal_type=['themis.datatypes.deputy'])))
authors = schema.TextLine(title=_(u'Authors'), required=False)
# polgroups
session = schema.Choice(title=_(u'Legislature / Session'), required=False,
source=possible_sessions)
@ -169,7 +218,9 @@ class IQuestionSearch(interface.Interface):
class QuestionSearchForm(form.Form):
prefix = 'question'
fields = field.Fields(IQuestionSearch)
fields['authors'].widgetFactory = FieldAuthorsWidget
ignoreContext = True
template = ViewPageTemplateFile('form_templates/view_question_search.pt')
@ -196,10 +247,7 @@ class IDocumentPfbSearch(interface.Interface):
#subjects =
ttitle = schema.TextLine(title=_(u'Title'), required=False)
text = schema.TextLine(title=_(u'Text'), required=False)
authors = RelationList(title=_(u'Authors'), default=[], required=False,
value_type=RelationChoice(title=_(u'Author'),
source=ObjPathSourceBinder(
portal_type=['themis.datatypes.deputy'])))
authors = schema.TextLine(title=_(u'Authors'), required=False)
# polgroups
session = schema.Choice(title=_(u'Legislature / Session'), required=False,
source=possible_sessions)
@ -213,6 +261,7 @@ class IDocumentPfbSearch(interface.Interface):
class DocumentPfbSearchForm(form.Form):
method = 'get'
fields = field.Fields(IDocumentPfbSearch)
fields['authors'].widgetFactory = FieldAuthorsWidget
ignoreContext = True
template = ViewPageTemplateFile('form_templates/view_pfbdocsearch.pt')
@ -250,10 +299,7 @@ class IGlobalSearchForm(interface.Interface):
#subjects =
ttitle = schema.TextLine(title=_(u'Title'), required=False)
text = schema.TextLine(title=_(u'Text'), required=False)
authors = RelationList(title=_(u'Authors'), default=[], required=False,
value_type=RelationChoice(title=_(u'Author'),
source=ObjPathSourceBinder(
portal_type=['themis.datatypes.deputy'])))
authors = schema.TextLine(title=_(u'Authors'), required=False)
# polgroups
session = schema.Choice(title=_(u'Legislature / Session'), required=False,
source=possible_sessions)
@ -267,8 +313,17 @@ class GlobalSearchForm(form.Form):
class SearchView(BrowserView):
def search_results(self, search_type):
if self.request.form.get('document.widgets.search_type_is_document'):
GlobalSearchForm.prefix = 'document'
elif self.request.form.get('dossier.widgets.search_type_is_dossier'):
GlobalSearchForm.prefix = 'dossier'
elif self.request.form.get('question.widgets.search_type_is_question'):
GlobalSearchForm.prefix = 'question'
f = GlobalSearchForm(self.context, self.request)
f.update()
data, errors = f.extractData()
kw = {}
@ -276,16 +331,8 @@ class SearchView(BrowserView):
print 'data:', data
if not data.get('search_type_is_%s' % search_type):
print 'not the right pane'
return None
if data.get('search_type_is_document'):
kw['portal_type'] = 'tabellio.documents.document'
elif data.get('search_type_is_dossier'):
kw['portal_type'] = 'tabellio.documents.dossier'
elif data.get('search_type_is_question'):
kw['portal_type'] = 'tabellio.documents.question'
if data.get('ttitle'):
kw['Title'] = data.get('ttitle')
@ -313,6 +360,10 @@ class SearchView(BrowserView):
if data.get('session'):
kw['session'] = tabellio.config.utils.get_list_of_sessions(data.get('session'))
if data.get('authors'):
kw['authorsDoc'] = {'query': data.get('authors').strip().split(),
'operator': 'and'}
if data.get('polgroups'):
pass # XXX : kw['polgroupsDoc'] = {'query': ['ps', 'ecolo'], 'operator': 'and'}
@ -326,6 +377,13 @@ class SearchView(BrowserView):
if not kw:
return []
if data.get('search_type_is_document'):
kw['portal_type'] = 'tabellio.documents.document'
elif data.get('search_type_is_dossier'):
kw['portal_type'] = 'tabellio.documents.dossier'
elif data.get('search_type_is_question'):
kw['portal_type'] = 'tabellio.documents.question'
if not kw.get('sort_on') and data.get('search_type_is_document'):
kw['sort_on'] = 'dateDoc'
kw['sort_order'] = 'descending'