work in progress: search
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1294 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
b4131bfcaf
commit
3bd8e181be
10 changed files with 231 additions and 44 deletions
|
@ -40,6 +40,7 @@ from zope.schema.vocabulary import SimpleTerm
|
|||
from zope.security import canAccess, canWrite
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
|
||||
from cybertools.relation.interfaces import IRelationRegistry
|
||||
from cybertools.typology.interfaces import IType
|
||||
from loops.interfaces import IView
|
||||
from loops import util
|
||||
|
@ -167,7 +168,8 @@ class BaseView(object):
|
|||
|
||||
@Lazy
|
||||
def uniqueId(self):
|
||||
return zapi.getUtility(IIntIds).getId(self.context)
|
||||
return zapi.getUtility(IRelationRegistry).getUniqueIdForObject(self.context)
|
||||
#return zapi.getUtility(IIntIds).getId(self.context)
|
||||
|
||||
@Lazy
|
||||
def editable(self):
|
||||
|
|
|
@ -74,3 +74,13 @@ div.image {
|
|||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* search stuff */
|
||||
|
||||
.searchForm input.button, input.submit {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.searchForm input.submit {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,19 @@ function openEditWindow(url) {
|
|||
zmi.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
function focusOpener() {
|
||||
if (typeof(opener) != 'undefined' && opener != null) {
|
||||
opener.location.reload();
|
||||
opener.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function submitReplacing(targetId, formId, actionUrl) {
|
||||
dojo.io.updateNode(targetId, {
|
||||
url: actionUrl,
|
||||
formNode: dojo.byId(formId),
|
||||
method: 'post'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
tal:define="dummy python:
|
||||
controller.macros.register('css', resourceName='loops.css', media='all');
|
||||
dummy python:
|
||||
controller.macros.register('js', resourceName='loops.js');" />
|
||||
controller.macros.register('js', resourceName='loops.js');
|
||||
dummy python:
|
||||
controller.macros.register('js', resourceName='ajax.dojo/dojo.js');" />
|
||||
|
||||
|
||||
<metal:block fill-slot="actions" />
|
||||
|
|
|
@ -122,6 +122,13 @@ class NodeView(BaseView):
|
|||
basicView._viewName = self.context.viewName
|
||||
return basicView.view
|
||||
|
||||
@Lazy
|
||||
def targetUrl(self):
|
||||
t = self.target
|
||||
if t is not None:
|
||||
return '%s/.target%s' % (self.url, t.uniqueId)
|
||||
return ''
|
||||
|
||||
def renderTarget(self):
|
||||
target = self.target
|
||||
return target is not None and target.render() or u''
|
||||
|
|
|
@ -291,8 +291,6 @@
|
|||
<adapter factory="loops.type.ConceptType" />
|
||||
<adapter factory="loops.type.ResourceType"
|
||||
for="loops.interfaces.IDocument" />
|
||||
<!--<adapter factory="loops.type.ResourceType"
|
||||
for="loops.interfaces.IMediaAsset" />-->
|
||||
<adapter factory="loops.type.LoopsTypeManager" />
|
||||
|
||||
<adapter factory="loops.type.TypeConcept" trusted="True" />
|
||||
|
|
|
@ -4,3 +4,76 @@ loops.search - Provide search functionality for the loops framework
|
|||
|
||||
($Id$)
|
||||
|
||||
|
||||
Let's do some basic set up
|
||||
|
||||
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||
>>> site = placefulSetUp(True)
|
||||
|
||||
>>> from zope import component, interface
|
||||
|
||||
and setup a simple loops site with a concept manager and some concepts
|
||||
(with all the type machinery, what in real life is done via standard
|
||||
ZCML setup):
|
||||
|
||||
>>> from cybertools.relation.interfaces import IRelationRegistry
|
||||
>>> from cybertools.relation.registry import DummyRelationRegistry
|
||||
>>> relations = DummyRelationRegistry()
|
||||
>>> component.provideUtility(relations, IRelationRegistry)
|
||||
|
||||
>>> from loops.type import ConceptType, TypeConcept
|
||||
>>> from loops.interfaces import ITypeConcept
|
||||
>>> component.provideAdapter(ConceptType)
|
||||
>>> component.provideAdapter(TypeConcept)
|
||||
|
||||
>>> from loops import Loops
|
||||
>>> loopsRoot = site['loops'] = Loops()
|
||||
|
||||
>>> from loops.setup import SetupManager
|
||||
>>> setup = SetupManager(loopsRoot)
|
||||
>>> concepts, resources, views = setup.setup()
|
||||
>>> typeConcept = concepts['type']
|
||||
|
||||
>>> from loops.concept import Concept
|
||||
>>> query = concepts['query'] = Concept(u'Query')
|
||||
>>> topic = concepts['topic'] = Concept(u'Topic')
|
||||
>>> for c in (query, topic): c.conceptType = typeConcept
|
||||
|
||||
In addition we create a concept that holds the search page and a node
|
||||
(page) that links to this concept:
|
||||
|
||||
>>> search = concepts['search'] = Concept(u'Search')
|
||||
>>> search.conceptType = query
|
||||
|
||||
>>> from loops.view import Node
|
||||
>>> page = views['page'] = Node('Search Page')
|
||||
>>> page.target = search
|
||||
|
||||
Now we are ready to create a search view object:
|
||||
|
||||
>>> from zope.publisher.browser import TestRequest
|
||||
>>> from loops.search.browser import Search
|
||||
>>> searchView = Search(search, TestRequest())
|
||||
|
||||
The search view provides values for identifying the search form itself
|
||||
and the parameter rows; the rowNum is auto-incremented, so it should be
|
||||
accessed exactly once per row:
|
||||
|
||||
>>> searchView.itemNum
|
||||
1
|
||||
>>> searchView.rowNum
|
||||
1
|
||||
>>> searchView.rowNum
|
||||
2
|
||||
|
||||
To execute the search in the context of a node we have to set up a node
|
||||
view on our page. The submitReplacing method returns a JavaScript call
|
||||
that will replace the results part on the search page:
|
||||
|
||||
>>> from loops.browser.node import NodeView
|
||||
>>> pageView = NodeView(page, TestRequest())
|
||||
|
||||
>>> searchView.submitReplacing('1.results', '1.search.form', pageView)
|
||||
'return submitReplacing("1.results", "1.search.form",
|
||||
"http://127.0.0.1/loops/views/page/.target19/@@searchresults.html")'
|
||||
|
||||
|
|
|
@ -42,7 +42,42 @@ class Search(BaseView):
|
|||
|
||||
template = NamedTemplate('loops.search_macros')
|
||||
|
||||
maxRowNum = 0
|
||||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
return self.template.macros['search']
|
||||
|
||||
@Lazy
|
||||
def itemNum(self):
|
||||
""" Return a number identifying the item (the current search form)
|
||||
on the page.
|
||||
"""
|
||||
return self.request.get('loops.itemNum', 1)
|
||||
|
||||
@property
|
||||
def rowNum(self):
|
||||
""" Return the rowNum to be used for identifying the current row.
|
||||
"""
|
||||
n = self.request.get('loops.rowNum', 0)
|
||||
if n: # if given directly we don't use the calculation
|
||||
return n
|
||||
n = (self.maxRowNum or self.request.get('loops.maxRowNum', 0)) + 1
|
||||
self.maxRowNum = n
|
||||
return n
|
||||
|
||||
def submitReplacing(self, targetId, formId, view):
|
||||
return 'return submitReplacing("%s", "%s", "%s")' % (
|
||||
targetId, formId,
|
||||
'%s/.target%s/@@searchresults.html' % (view.url, self.uniqueId))
|
||||
|
||||
|
||||
class SearchResults(BaseView):
|
||||
|
||||
innerHtml_template = NamedTemplate('loops.search_macros')
|
||||
innerHtml_macro = 'search_results'
|
||||
template = NamedTemplate('ajax.inner.html')
|
||||
|
||||
def __call__(self):
|
||||
return self.template(self)
|
||||
|
||||
|
|
|
@ -24,5 +24,11 @@
|
|||
permission="zope.View"
|
||||
/>
|
||||
|
||||
<browser:page
|
||||
name="searchresults.html"
|
||||
for="loops.interfaces.ILoopsObject"
|
||||
class="loops.search.browser.SearchResults"
|
||||
permission="zope.View"
|
||||
/>
|
||||
|
||||
</configure>
|
||||
|
|
124
search/search.pt
124
search/search.pt
|
@ -1,24 +1,33 @@
|
|||
<metal:search define-macro="search">
|
||||
<div id="search"
|
||||
tal:define="template nocall:item/template">
|
||||
tal:define="macros item/template/macros">
|
||||
<h3 tal:attributes="class string:content-$level;
|
||||
ondblclick item/openEditWindow">
|
||||
Search
|
||||
</h3>
|
||||
|
||||
<div metal:define-macro="search_form">
|
||||
<div metal:define-macro="search_form" class="searchForm"
|
||||
tal:define="idPrefix string:${item/itemNum}.search;
|
||||
formId string:$idPrefix.form">
|
||||
<fieldset class="box">
|
||||
<form action=".">
|
||||
<form action="." method="post" id="1.search.form"
|
||||
tal:attributes="id formId">
|
||||
<table cellpadding="3">
|
||||
<tal:block define="search_selection string:type">
|
||||
<metal:row use-macro="template/macros/search_row" />
|
||||
</tal:block>
|
||||
<tal:block define="search_selection string:text">
|
||||
<metal:row use-macro="template/macros/search_row" />
|
||||
<tal:block repeat="search_selection python: ['type', 'text']">
|
||||
<metal:row use-macro="macros/search_row" />
|
||||
</tal:block>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="button" name="search.add.1" value=" Add filter " />
|
||||
<input type="button" value="Add concept filter" class="button" />
|
||||
<input type="button" value="Add attribute filter" class="button" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="submit" name="1.search" value="Search" class="submit"
|
||||
tal:attributes="name string:$idPrefix.submit;
|
||||
onclick python:
|
||||
item.submitReplacing('1.results', formId, view)" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -26,9 +35,11 @@
|
|||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div metal:define-macro="search_results">
|
||||
<div metal:define-macro="search_results"
|
||||
id="1.results">
|
||||
<fieldset class="box">
|
||||
Search results
|
||||
<p tal:content="python:request.get('1.search.1.text', 'nothing')" />
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
|
@ -36,9 +47,70 @@
|
|||
</metal:search>
|
||||
|
||||
|
||||
<tr metal:define-macro="search_row" id="search.row.1.1">
|
||||
<tr metal:define-macro="search_row" id="search.row.1.1"
|
||||
tal:define="rowNum item/rowNum;
|
||||
idPrefix string:$idPrefix.$rowNum;
|
||||
selection search_selection | item/searchSelection"
|
||||
tal:attributes="id string:$idPrefix.row">
|
||||
<td style="width: 30px">
|
||||
<input type="button" value="−"
|
||||
title="Remove search parameter"
|
||||
tal:condition="python: selection not in ['type', 'text']" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" value="−" />
|
||||
<div metal:use-macro="macros/?selection" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<metal:text define-macro="type">
|
||||
<div>
|
||||
<h3>Type(s) to search for</h3>
|
||||
<label for="text"
|
||||
tal:attributes="for string:$idPrefix.text">Type:</label>
|
||||
<select name="text"
|
||||
tal:attributes="name string:$idPrefix.text;
|
||||
id string:$idPrefix.text;">
|
||||
<option value=".loops/concepts/topic">Topic</option>
|
||||
<option value="loops.resource.Document">Document</option>
|
||||
</select>
|
||||
<input type="button" value="+"
|
||||
title="Add type" />
|
||||
</div>
|
||||
</metal:text>
|
||||
|
||||
|
||||
<metal:text define-macro="text">
|
||||
<div>
|
||||
<h3>Search text</h3>
|
||||
<input type="checkbox" checked
|
||||
name="title" id="title"
|
||||
tal:attributes="name string:$idPrefix.title;
|
||||
id string:$idPrefix.title;" />
|
||||
<label for="title"
|
||||
tal:attributes="for string:$idPrefix.title">Title</label>
|
||||
<input type="checkbox"
|
||||
name="full" id="full"
|
||||
tal:attributes="name string:$idPrefix.full;
|
||||
id string:$idPrefix.full;" />
|
||||
<label for="full"
|
||||
tal:attributes="for string:$idPrefix.full">Full text</label>
|
||||
<label for="text"
|
||||
tal:attributes="for string:$idPrefix.text">Search words:</label>
|
||||
<input type="text" name="text"
|
||||
tal:attributes="name string:$idPrefix.text;
|
||||
id string:$idPrefix.text;" />
|
||||
<input type="button" value="+"
|
||||
title="Add search word" />
|
||||
</div>
|
||||
</metal:text>
|
||||
|
||||
|
||||
<!-- obsolete -->
|
||||
<tr metal:define-macro="search_row_selectable" id="search.row.1.1">
|
||||
<td>
|
||||
<input type="button" value="−"
|
||||
title="Remove search parameter" />
|
||||
</td>
|
||||
<td tal:define="selection search_selection | string:type">
|
||||
<select>
|
||||
|
@ -54,31 +126,3 @@
|
|||
</tr>
|
||||
|
||||
|
||||
<metal:text define-macro="text">
|
||||
<div id="search.text.1.1">
|
||||
<input type="checkbox"
|
||||
name="search.text.title.1.1" id="search.text.title.1.1" />
|
||||
<label for="search.text.title.1.1">Title</label>
|
||||
<input type="checkbox"
|
||||
name="search.text.full.1.1" id="search.text.full.1.1" />
|
||||
<label for="search.text.full.1.1">Full text</label>
|
||||
<label for="search.text.text.1.1">Search words:</label>
|
||||
<input type="text" name="search.text.text.1.1" />
|
||||
<input type="text" name="search.text.text.1.1" />
|
||||
<input type="button" name="search.text.add.1.1" value="+" />
|
||||
</div>
|
||||
</metal:text>
|
||||
|
||||
|
||||
<metal:text define-macro="type">
|
||||
<div id="search.type.1.2">
|
||||
<label for="search.text.1.1">Type:</label>
|
||||
<select type="text" name="search.type.text.1.2">
|
||||
<option value=".loops/concepts/topic">Topic</option>
|
||||
<option value="loops.resource.Document">Document</option>
|
||||
</select>
|
||||
<input type="button" name="search.type.add.1.2" value="+" />
|
||||
</div>
|
||||
</metal:text>
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue