diff --git a/browser/common.py b/browser/common.py index 0fc769b..6a735b8 100644 --- a/browser/common.py +++ b/browser/common.py @@ -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): diff --git a/browser/loops.css b/browser/loops.css index 46e175f..a25fce8 100644 --- a/browser/loops.css +++ b/browser/loops.css @@ -74,3 +74,13 @@ div.image { margin-right: 5px; } +/* search stuff */ + +.searchForm input.button, input.submit { + padding: 2px; +} + +.searchForm input.submit { + font-weight: bold; +} + diff --git a/browser/loops.js b/browser/loops.js index 26ecb79..ea5374f 100644 --- a/browser/loops.js +++ b/browser/loops.js @@ -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; +} diff --git a/browser/node.pt b/browser/node.pt index b4d8c37..238f9f5 100644 --- a/browser/node.pt +++ b/browser/node.pt @@ -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');" /> diff --git a/browser/node.py b/browser/node.py index 05c0850..d615982 100644 --- a/browser/node.py +++ b/browser/node.py @@ -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'' diff --git a/configure.zcml b/configure.zcml index d1e75b0..0bf64b1 100644 --- a/configure.zcml +++ b/configure.zcml @@ -291,8 +291,6 @@ - diff --git a/search/README.txt b/search/README.txt index 94ee36f..91d4a9d 100755 --- a/search/README.txt +++ b/search/README.txt @@ -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")' + diff --git a/search/browser.py b/search/browser.py index e792680..bd961dd 100644 --- a/search/browser.py +++ b/search/browser.py @@ -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) + diff --git a/search/configure.zcml b/search/configure.zcml index f1f22ae..014a442 100644 --- a/search/configure.zcml +++ b/search/configure.zcml @@ -24,5 +24,11 @@ permission="zope.View" /> + diff --git a/search/search.pt b/search/search.pt index bfbbae8..63b83a0 100644 --- a/search/search.pt +++ b/search/search.pt @@ -1,24 +1,33 @@