diff --git a/browser/common.py b/browser/common.py index 68bc614..352761a 100644 --- a/browser/common.py +++ b/browser/common.py @@ -25,12 +25,10 @@ $Id$ from zope.app import zapi from zope.app.dublincore.interfaces import IZopeDublinCore from zope.app.form.browser.interfaces import ITerms -from zope.app.intid.interfaces import IIntIds from zope.cachedescriptors.property import Lazy from zope.dottedname.resolve import resolve +from zope.formlib import form from zope.formlib.form import FormFields -from zope.formlib.form import EditForm as BaseEditForm -from zope.formlib.form import AddForm as BaseAddForm from zope.formlib.namedtemplate import NamedTemplate from zope.interface import Interface, implements from zope.app.publisher.browser import applySkin @@ -44,7 +42,7 @@ from cybertools.browser.view import GenericView from cybertools.relation.interfaces import IRelationRegistry from cybertools.typology.interfaces import IType from loops.interfaces import IView -from loops import util +#from loops import util from loops.util import _ @@ -64,13 +62,13 @@ class IAddForm(Interface): ) -class AddForm(BaseAddForm): +class AddForm(form.AddForm): form_fields = FormFields(IAddForm) template = NamedTemplate('loops.pageform') -class EditForm(BaseEditForm): +class EditForm(form.EditForm): template = NamedTemplate('loops.pageform') @@ -181,10 +179,6 @@ class BaseView(GenericView): # this may depend on system and user settings... return True - #@Lazy - #def inlineEditable(self): - # return self.inlineEditingActive and canWrite(self.context, 'title') - inlineEditable = False def inlineEdit(self, id): diff --git a/browser/node.py b/browser/node.py index bc13e88..f16de3c 100644 --- a/browser/node.py +++ b/browser/node.py @@ -39,6 +39,9 @@ from zope.proxy import removeAllProxies from zope.security import canAccess, canWrite from zope.security.proxy import removeSecurityProxy +from zope.app.event.objectevent import ObjectModifiedEvent, Attributes +from zope.event import notify + from cybertools.ajax import innerHtml from cybertools.browser import configurator from cybertools.browser.view import GenericView @@ -299,6 +302,7 @@ class InlineEdit(NodeView): def save(self): target = self.virtualTargetObject target.data = self.request.form['editorContent'] + notify(ObjectModifiedEvent(target, Attributes(IResource, 'data'))) # special (named) views for nodes diff --git a/concept.py b/concept.py index fb8beae..7594388 100644 --- a/concept.py +++ b/concept.py @@ -76,13 +76,13 @@ class ResourceRelation(BaseRelation): # concept - + class Concept(Contained, Persistent): implements(IConcept, IConceptManagerContained, IRelatable) proxyInterface = IConceptView - + _title = u'' def getTitle(self): return self._title def setTitle(self, title): self._title = title @@ -132,7 +132,7 @@ class Concept(Contained, Persistent): relationships = [ConceptRelation(None, self, p) for p in predicates] # TODO: sort... return getRelations(first=parent, second=self, relationships=relationships) - + def getParents(self, predicates=None): return [r.first for r in self.getParentRelations(predicates)] @@ -158,7 +158,7 @@ class Concept(Contained, Persistent): def deassignParent(self, parent, predicates=None): parent.deassignChild(self, predicates) - + # resource relations def getResourceRelations(self, predicates=None, resource=None): @@ -184,7 +184,7 @@ class Concept(Contained, Persistent): # concept manager - + class ConceptManager(BTreeContainer): implements(IConceptManager, ILoopsContained) @@ -211,7 +211,7 @@ class ConceptManager(BTreeContainer): def getViewManager(self): return self.getLoopsRoot().getViewManager() - + # adapters and similar components @@ -291,10 +291,12 @@ class IndexAttributes(object): def __init__(self, context): self.context = context + # obsolete, use TextIndexNG (with indexableContent() method) instead def text(self): context = self.context return ' '.join((zapi.getName(context), context.title,)) def title(self): - return self.text() + context = self.context + return ' '.join((zapi.getName(context), context.title,)) diff --git a/configure.zcml b/configure.zcml index 0bf64b1..ba2774b 100644 --- a/configure.zcml +++ b/configure.zcml @@ -276,12 +276,22 @@ - - + + + + + + + + + + - + + + + @@ -350,6 +360,21 @@ name="loops.PredicateSource" /> + + + + + + + diff --git a/resource.py b/resource.py index 405b53c..425d30a 100644 --- a/resource.py +++ b/resource.py @@ -37,6 +37,9 @@ from zope import schema from persistent import Persistent from cStringIO import StringIO +from zope.app.event.objectevent import ObjectModifiedEvent, Attributes +from zope.event import notify + from textindexng.interfaces import IIndexableContent from textindexng.content import IndexContentCollector from cybertools.relation.registry import getRelations @@ -205,6 +208,7 @@ class DocumentWriteFileAdapter(object): def write(self, data): self.context.data = unicode(data.replace('\r', ''), 'UTF-8') + notify(ObjectModifiedEvent(self.context, Attributes(IDocument, 'data'))) class DocumentReadFileAdapter(object): @@ -230,6 +234,7 @@ class IndexAttributes(object): def __init__(self, context): self.context = context + # obsolete, use TextIndexNG (with indexableContent() method) instead def text(self): context = self.context return ' '.join((zapi.getName(context), context.title, context.data)).strip() diff --git a/search/README.txt b/search/README.txt index a961a78..7213eee 100755 --- a/search/README.txt +++ b/search/README.txt @@ -11,6 +11,7 @@ Let's do some basic set up >>> site = placefulSetUp(True) >>> from zope import component, interface + >>> from zope.interface import implements 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 @@ -81,3 +82,22 @@ a controller attribute for the search view. 'return submitReplacing("1.results", "1.search.form", "http://127.0.0.1/loops/views/page/.target19/@@searchresults.html")' +The searchresults.html view, i.e. the SearchResults view class provides the +result set of the search via its `results` property. + + >>> from loops.search.browser import SearchResults + >>> form = {'search.2.title': 'yes', 'search.2.text': u'foo' } + >>> request = TestRequest(form=form) + >>> resultsView = SearchResults(page, request) + +Before accessing the `results` property we have to prepare a catalog. + + >>> from zope.app.catalog.interfaces import ICatalog + >>> class DummyCat(object): + ... implements(ICatalog) + ... def searchResults(self, **criteria): + ... return [] + >>> component.provideUtility(DummyCat()) + + >>> resultsView.results + [] diff --git a/search/browser.py b/search/browser.py index 448c060..237d13e 100644 --- a/search/browser.py +++ b/search/browser.py @@ -24,6 +24,7 @@ $Id$ """ from zope import interface, component +from zope.app.catalog.interfaces import ICatalog from zope.app.pagetemplate import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy from zope.formlib.namedtemplate import NamedTemplate, NamedTemplateImplementation @@ -75,3 +76,22 @@ class SearchResults(BaseView): def __call__(self): return innerHtml(self) + @Lazy + def results(self): + request = self.request + text = request.get('search.2.text') + if not text: + return set() + useTitle = request.get('search.2.title') + useFull = request.get('search.2.full') + r1 = r2 = set() + cat = component.getUtility(ICatalog) + if useFull: + criteria = {'loops_resource_textng': {'query': text},} + r1 = set(cat.searchResults(**criteria)) + if useTitle: + criteria = {'loops_title': text,} + r2 = set(cat.searchResults(**criteria)) + result = [BaseView(r, request) for r in r1.union(r2)] + return result + diff --git a/search/search.pt b/search/search.pt index 8f40404..c1f287c 100644 --- a/search/search.pt +++ b/search/search.pt @@ -1,19 +1,23 @@ + tal:define="macros item/template/macros; + idPrefix string:${view/itemNum}.search; + formId string:$idPrefix.form; + resultsId string:$idPrefix.results"> Search - + + + - + @@ -24,10 +28,9 @@ - + @@ -35,11 +38,17 @@ - - - Search results - + + + Search results + + + + + @@ -47,18 +56,22 @@ - + + tal:condition="python: param not in ['type', 'text']" /> - + @@ -69,7 +82,7 @@ Type: Topic Document @@ -84,21 +97,21 @@ Search text Title Full text Search words: diff --git a/target.py b/target.py index 66639cc..dcab348 100644 --- a/target.py +++ b/target.py @@ -31,8 +31,10 @@ from zope.interface import implements from zope import schema from zope.security.proxy import removeSecurityProxy -from loops.interfaces import IResource -from loops.interfaces import IDocument, IMediaAsset +from zope.app.event.objectevent import ObjectModifiedEvent, Attributes +from zope.event import notify + +from loops.interfaces import ILoopsObject, IResource, IDocument, IMediaAsset from loops.interfaces import IDocumentView, IMediaAssetView from loops.interfaces import IView from loops.interfaces import IConcept, IConceptView @@ -52,10 +54,13 @@ class TargetProxy(object): @Lazy def target(self): return self.context.target - + def getTitle(self): return self.target.title - def setTitle(self, title): self.target.title = title + def setTitle(self, title): + self.target.title = title + notify(ObjectModifiedEvent(self.target, + Attributes(ILoopsObject, 'title'))) title = property(getTitle, setTitle) @@ -65,7 +70,9 @@ class ConceptProxy(TargetProxy): adapts(IConceptView) def getConceptType(self): return self.target.conceptType - def setConceptType(self, conceptType): self.target.conceptType = conceptType + def setConceptType(self, conceptType): + self.target.conceptType = conceptType + notify(ObjectModifiedEvent(self.target, Attributes(IConcept, 'conceptType'))) conceptType = property(getConceptType, setConceptType) def getChildren(self, predicates=None): @@ -81,6 +88,7 @@ class ConceptProxy(TargetProxy): class ResourceProxy(TargetProxy): def setContentType(self, contentType): + notify(ObjectModifiedEvent(self.target, Attributes(IResource, 'contentType'))) self.target.contentType = contentType def getContentType(self): return self.target.contentType contentType = property(getContentType, setContentType) @@ -91,7 +99,9 @@ class DocumentProxy(ResourceProxy): implements(IDocument) adapts(IDocumentView) - def setData(self, data): self.target.data = data + def setData(self, data): + self.target.data = data + notify(ObjectModifiedEvent(self.target, Attributes(IDocument, 'data'))) def getData(self): return self.target.data data = property(getData, setData)