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:
helmutm 2006-08-08 19:00:23 +00:00
parent b4131bfcaf
commit 3bd8e181be
10 changed files with 231 additions and 44 deletions

View file

@ -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):

View file

@ -74,3 +74,13 @@ div.image {
margin-right: 5px;
}
/* search stuff */
.searchForm input.button, input.submit {
padding: 2px;
}
.searchForm input.submit {
font-weight: bold;
}

View file

@ -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;
}

View file

@ -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" />

View file

@ -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''

View file

@ -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" />

View file

@ -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")'

View file

@ -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)

View file

@ -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>

View file

@ -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="&minus;"
title="Remove search parameter"
tal:condition="python: selection not in ['type', 'text']" />&nbsp;
</td>
<td>
<input type="button" value="&minus;" />&nbsp;
<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" />&nbsp;
</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>&nbsp;&nbsp;
<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" />&nbsp;
</div>
</metal:text>
<!-- obsolete -->
<tr metal:define-macro="search_row_selectable" id="search.row.1.1">
<td>
<input type="button" value="&minus;"
title="Remove search parameter" />&nbsp;
</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>&nbsp;&nbsp;
<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="+" />&nbsp;
</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="+" />&nbsp;
</div>
</metal:text>