First working version: add resource (note) via dojo.Dialog
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1358 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
2743e01d78
commit
63a13d6854
7 changed files with 137 additions and 35 deletions
65
README.txt
65
README.txt
|
@ -346,20 +346,15 @@ We first need a view manager:
|
||||||
>>> nodeChecker = NamesChecker(('body',))
|
>>> nodeChecker = NamesChecker(('body',))
|
||||||
>>> defineChecker(Node, nodeChecker)
|
>>> defineChecker(Node, nodeChecker)
|
||||||
|
|
||||||
>>> loopsRoot['views'] = ViewManager()
|
>>> views = loopsRoot['views'] = ViewManager()
|
||||||
>>> views = loopsRoot['views']
|
|
||||||
|
|
||||||
The view space is typically built up with nodes; a node may be a top-level
|
The view space is typically built up with nodes; a node may be a top-level
|
||||||
menu that may contain other nodes as menu or content items:
|
menu that may contain other nodes as menu or content items:
|
||||||
|
|
||||||
>>> m1 = Node(u'Menu')
|
>>> m1 = views['m1'] = Node(u'Menu')
|
||||||
>>> views['m1'] = m1
|
>>> m11 = m1['m11'] = Node(u'Zope')
|
||||||
>>> m11 = Node(u'Zope')
|
>>> m111 = m11['m111'] = Node(u'Zope in General')
|
||||||
>>> m1['m11'] = m11
|
>>> m112 = m11['m112'] = Node(u'Zope 3')
|
||||||
>>> m111 = Node(u'Zope in General')
|
|
||||||
>>> m11['m111'] = m111
|
|
||||||
>>> m112 = Node(u'Zope 3')
|
|
||||||
>>> m11['m112'] = m112
|
|
||||||
>>> m112.title
|
>>> m112.title
|
||||||
u'Zope 3'
|
u'Zope 3'
|
||||||
>>> m112.description
|
>>> m112.description
|
||||||
|
@ -616,8 +611,56 @@ to the bottom, and to the top.
|
||||||
>>> m11.keys()
|
>>> m11.keys()
|
||||||
['m111', 'm114', 'm112', 'm113']
|
['m111', 'm114', 'm112', 'm113']
|
||||||
|
|
||||||
|
|
||||||
|
End-user Forms
|
||||||
|
==============
|
||||||
|
|
||||||
|
The browser.form and related modules provide additional support for forms
|
||||||
|
that are shown in the end-user interface.
|
||||||
|
|
||||||
|
>>> from loops.browser.form import CreateObjectForm, CreateObject, ResourceNameChooser
|
||||||
|
>>> form = CreateObjectForm(m112, TestRequest)
|
||||||
|
|
||||||
|
>>> from loops.interfaces import INote, ITypeConcept
|
||||||
|
>>> from loops.type import TypeConcept
|
||||||
|
>>> from loops.resource import NoteAdapter
|
||||||
|
>>> component.provideAdapter(TypeConcept)
|
||||||
|
>>> component.provideAdapter(NoteAdapter)
|
||||||
|
>>> note_tc = concepts['note'] = Concept('Note')
|
||||||
|
>>> note_tc.conceptType = typeObject
|
||||||
|
>>> ITypeConcept(note_tc).typeInterface = INote
|
||||||
|
|
||||||
|
>>> component.provideAdapter(ResourceNameChooser)
|
||||||
|
>>> request = TestRequest(form={'form.title': 'Test Note'})
|
||||||
|
>>> view = NodeView(m112, request)
|
||||||
|
>>> cont = CreateObject(view, request)
|
||||||
|
>>> cont.update()
|
||||||
|
True
|
||||||
|
>>> sorted(resources.keys())
|
||||||
|
[...u'test_note'...]
|
||||||
|
>>> resources['test_note'].title
|
||||||
|
'Test Note'
|
||||||
|
|
||||||
|
If there is a concept selected in the combo box we assign this to the newly
|
||||||
|
created object:
|
||||||
|
|
||||||
|
>>> from loops import util
|
||||||
|
>>> topicUid = util.getUidForObject(topic)
|
||||||
|
>>> request = TestRequest(form={'form.title': 'Test Note',
|
||||||
|
... 'form.concept.search.text_selected': topicUid})
|
||||||
|
>>> view = NodeView(m112, request)
|
||||||
|
>>> cont = CreateObject(view, request)
|
||||||
|
>>> cont.update()
|
||||||
|
True
|
||||||
|
>>> sorted(resources.keys())
|
||||||
|
[...u'test_note-2'...]
|
||||||
|
>>> note = resources['test_note-2']
|
||||||
|
>>> sorted(t.__name__ for t in note.getConcepts())
|
||||||
|
[u'note', u'topic']
|
||||||
|
|
||||||
|
|
||||||
Import/Export
|
Import/Export
|
||||||
-------------
|
=============
|
||||||
|
|
||||||
Nodes may be exported to and loaded from external sources, typically
|
Nodes may be exported to and loaded from external sources, typically
|
||||||
file representations that allow the transfer of nodes from one Zope
|
file representations that allow the transfer of nodes from one Zope
|
||||||
|
|
|
@ -574,6 +574,8 @@
|
||||||
permission="zope.ManageContent"
|
permission="zope.ManageContent"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<zope:adapter factory="loops.browser.form.ResourceNameChooser" />
|
||||||
|
|
||||||
<!-- inner HTML views -->
|
<!-- inner HTML views -->
|
||||||
|
|
||||||
<page
|
<page
|
||||||
|
|
|
@ -23,12 +23,25 @@ $Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope import component, interface, schema
|
from zope import component, interface, schema
|
||||||
|
from zope.component import adapts
|
||||||
|
from zope.event import notify
|
||||||
|
from zope.app.event.objectevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
|
|
||||||
|
from zope.app.container.interfaces import INameChooser
|
||||||
|
from zope.app.container.contained import NameChooser
|
||||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.formlib.form import Form, FormFields
|
from zope.formlib.form import Form, FormFields
|
||||||
|
from zope.publisher.interfaces import BadRequest
|
||||||
|
|
||||||
from cybertools.ajax import innerHtml
|
from cybertools.ajax import innerHtml
|
||||||
from cybertools.browser.controller import FormController
|
from cybertools.browser.form import FormController
|
||||||
|
from cybertools.typology.interfaces import IType
|
||||||
|
from loops.interfaces import IResourceManager
|
||||||
from loops.browser.node import NodeView
|
from loops.browser.node import NodeView
|
||||||
|
from loops.resource import Resource
|
||||||
|
from loops import util
|
||||||
|
from loops.util import _
|
||||||
|
|
||||||
class CreateObjectForm(NodeView, Form):
|
class CreateObjectForm(NodeView, Form):
|
||||||
|
|
||||||
|
@ -39,7 +52,7 @@ class CreateObjectForm(NodeView, Form):
|
||||||
|
|
||||||
form_fields = FormFields(
|
form_fields = FormFields(
|
||||||
schema.TextLine(__name__='title', title=_(u'Title')),
|
schema.TextLine(__name__='title', title=_(u'Title')),
|
||||||
schema.Text(__name__='body', title=_(u'Body Text')),
|
schema.Text(__name__='data', title=_(u'Body Text')),
|
||||||
schema.TextLine(__name__='linkUrl', title=_(u'Link'), required=False),
|
schema.TextLine(__name__='linkUrl', title=_(u'Link'), required=False),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,8 +61,10 @@ class CreateObjectForm(NodeView, Form):
|
||||||
|
|
||||||
def __init__(self, context, request):
|
def __init__(self, context, request):
|
||||||
super(CreateObjectForm, self).__init__(context, request)
|
super(CreateObjectForm, self).__init__(context, request)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
self.setUpWidgets()
|
self.setUpWidgets()
|
||||||
self.widgets['body'].height = 3
|
self.widgets['data'].height = 3
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
return innerHtml(self)
|
return innerHtml(self)
|
||||||
|
@ -57,22 +72,48 @@ class CreateObjectForm(NodeView, Form):
|
||||||
|
|
||||||
class CreateObject(FormController):
|
class CreateObject(FormController):
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def loopsRoot(self):
|
||||||
|
return self.view.loopsRoot
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
prefix = 'form.'
|
prefix = 'form.'
|
||||||
|
conceptPrefix = 'concept.'
|
||||||
form = self.request.form
|
form = self.request.form
|
||||||
print 'updating...'
|
obj = Resource()
|
||||||
# determine name
|
container = self.loopsRoot.getResourceManager()
|
||||||
# create object, assign basic concepts (type, ...)
|
title = form.get('form.title')
|
||||||
|
if not title:
|
||||||
|
raise BadRequest('Title field is empty')
|
||||||
|
name = INameChooser(container).chooseName(title, obj)
|
||||||
|
container[name] = obj
|
||||||
|
obj.resourceType = self.loopsRoot.getConceptManager()['note']
|
||||||
|
adapter = IType(obj).typeInterface(obj)
|
||||||
for k in form.keys():
|
for k in form.keys():
|
||||||
if k.startswith(prefix):
|
if k.startswith(prefix):
|
||||||
fn = k[len(prefix):]
|
fn = k[len(prefix):]
|
||||||
|
if fn in ('action',):
|
||||||
|
continue
|
||||||
value = form[k]
|
value = form[k]
|
||||||
if fn.startswith('concept.search.'):
|
if fn.startswith(conceptPrefix):
|
||||||
self.assignConcepts(fn, value)
|
self.assignConcepts(obj, fn[len(conceptPrefix):], value)
|
||||||
else:
|
else:
|
||||||
pass
|
setattr(adapter, fn, value)
|
||||||
#setattr(obj, fn, value)
|
notify(ObjectCreatedEvent(obj))
|
||||||
print fn, value
|
notify(ObjectModifiedEvent(obj))
|
||||||
|
return True
|
||||||
|
|
||||||
def assignConcepts(self, fieldName, value):
|
def assignConcepts(self, obj, fieldName, value):
|
||||||
pass
|
if fieldName == 'search.text_selected':
|
||||||
|
concept = util.getObjectForUid(value)
|
||||||
|
obj.assignConcept(concept)
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceNameChooser(NameChooser):
|
||||||
|
|
||||||
|
adapts(IResourceManager)
|
||||||
|
|
||||||
|
def chooseName(self, title, obj):
|
||||||
|
name = title.replace(' ', '_').lower()
|
||||||
|
name = super(ResourceNameChooser, self).chooseName(name, obj)
|
||||||
|
return name
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<metal:block define-macro="create">
|
<metal:block define-macro="create">
|
||||||
<div>
|
<div tal:define="dummy view/setUp">
|
||||||
<form method="get">
|
<form method="post">
|
||||||
<input type="hidden" name="form.action" value="create"
|
<input type="hidden" name="form.action" value="create"
|
||||||
tal:attributes="value view/form_action" />
|
tal:attributes="value view/form_action" />
|
||||||
<table cellpadding="3" class="form">
|
<table cellpadding="3" class="form">
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
i18n:translate="">Create Information Object</span>
|
i18n:translate="">Create Information Object</span>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr tal:repeat="widget view/widgets">
|
<tr tal:repeat="widget view/widgets">
|
||||||
<td class="label"
|
<td class="label"
|
||||||
tal:define="hint widget/hint">
|
tal:define="hint widget/hint">
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4" class="headline">Assign Concept(s)</td>
|
<td colspan="4" class="headline">Assign Concept(s)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
5
query.py
5
query.py
|
@ -26,12 +26,12 @@ from zope import schema, component
|
||||||
from zope.interface import Interface, Attribute, implements
|
from zope.interface import Interface, Attribute, implements
|
||||||
from zope.app import traversing
|
from zope.app import traversing
|
||||||
from zope.app.catalog.interfaces import ICatalog
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
from zope.app.intid.interfaces import IIntIds
|
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
|
||||||
from loops.interfaces import IConcept
|
from loops.interfaces import IConcept
|
||||||
from loops.common import AdapterBase
|
from loops.common import AdapterBase
|
||||||
from loops.type import TypeInterfaceSourceList
|
from loops.type import TypeInterfaceSourceList
|
||||||
|
from loops import util
|
||||||
from loops.util import _
|
from loops.util import _
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,8 +82,7 @@ class BaseQuery(object):
|
||||||
if not uid:
|
if not uid:
|
||||||
queue = list(self.queryConcepts(title=title, type=type))
|
queue = list(self.queryConcepts(title=title, type=type))
|
||||||
else:
|
else:
|
||||||
intIds = component.getUtility(IIntIds)
|
queue = [util.getObjectForUid(uid)]
|
||||||
queue = [intIds.getObject(int(uid))]
|
|
||||||
concepts = []
|
concepts = []
|
||||||
while queue:
|
while queue:
|
||||||
c = queue.pop(0)
|
c = queue.pop(0)
|
||||||
|
|
|
@ -119,6 +119,7 @@ purposes fairly primitive) catalog and a resource we can search for:
|
||||||
... implements(ICatalog)
|
... implements(ICatalog)
|
||||||
... def searchResults(self, **criteria):
|
... def searchResults(self, **criteria):
|
||||||
... name = criteria.get('loops_title')
|
... name = criteria.get('loops_title')
|
||||||
|
... if name.endswith('*'): name = name[:-1]
|
||||||
... type = criteria.get('loops_type', ('resource',))
|
... type = criteria.get('loops_type', ('resource',))
|
||||||
... if name:
|
... if name:
|
||||||
... if 'concept' in type[0]:
|
... if 'concept' in type[0]:
|
||||||
|
@ -156,10 +157,10 @@ Search via related concepts
|
||||||
We first have to prepare some test concepts (topics); we also assign our test
|
We first have to prepare some test concepts (topics); we also assign our test
|
||||||
resource (rplone) from above to one of the topics:
|
resource (rplone) from above to one of the topics:
|
||||||
|
|
||||||
>>> czope = concepts['zope'] = Concept('Zope')
|
>>> czope = concepts['zope'] = Concept(u'Zope')
|
||||||
>>> czope2 = concepts['zope2'] = Concept('Zope 2')
|
>>> czope2 = concepts['zope2'] = Concept(u'Zope 2')
|
||||||
>>> czope3 = concepts['zope3'] = Concept('Zope 3')
|
>>> czope3 = concepts['zope3'] = Concept(u'Zope 3')
|
||||||
>>> cplone = concepts['plone'] = Concept('Plone')
|
>>> cplone = concepts['plone'] = Concept(u'Plone')
|
||||||
>>> for c in (czope, czope2, czope3, cplone):
|
>>> for c in (czope, czope2, czope3, cplone):
|
||||||
... c.conceptType = topic
|
... c.conceptType = topic
|
||||||
>>> czope.assignChild(czope2)
|
>>> czope.assignChild(czope2)
|
||||||
|
@ -193,11 +194,11 @@ To support easy entry of concepts to search for we can preselect the available
|
||||||
concepts (optionally restricted to a certain type) by entering text parts
|
concepts (optionally restricted to a certain type) by entering text parts
|
||||||
of the concepts' titles:
|
of the concepts' titles:
|
||||||
|
|
||||||
>>> form = {'searchType': 'loops:concept:topic', 'searchString': u'zo'}
|
>>> form = {'searchType': 'loops:concept:topic', 'searchString': u'zope'}
|
||||||
>>> request = TestRequest(form=form)
|
>>> request = TestRequest(form=form)
|
||||||
>>> view = Search(page, request)
|
>>> view = Search(page, request)
|
||||||
>>> view.listConcepts()
|
>>> view.listConcepts()
|
||||||
'[]'
|
"[['Zope', '23']]"
|
||||||
|
|
||||||
TODO - more to come...
|
TODO - more to come...
|
||||||
|
|
||||||
|
|
14
util.py
14
util.py
|
@ -22,6 +22,8 @@ Utility functions.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from zope import component
|
||||||
|
from zope.app.intid.interfaces import IIntIds
|
||||||
from zope.interface import directlyProvides, directlyProvidedBy
|
from zope.interface import directlyProvides, directlyProvidedBy
|
||||||
from zope.i18nmessageid import MessageFactory
|
from zope.i18nmessageid import MessageFactory
|
||||||
from zope.schema import vocabulary
|
from zope.schema import vocabulary
|
||||||
|
@ -53,3 +55,15 @@ def nl2br(text):
|
||||||
return '<br />\n'.join(x.replace('\r', '') for x in text.split('\n'))
|
return '<br />\n'.join(x.replace('\r', '') for x in text.split('\n'))
|
||||||
else: # gracefully handle Mac line endings
|
else: # gracefully handle Mac line endings
|
||||||
return '<br />\n'.join(text.split('\r'))
|
return '<br />\n'.join(text.split('\r'))
|
||||||
|
|
||||||
|
def getObjectForUid(uid):
|
||||||
|
if uid == '*': # wild card
|
||||||
|
return '*'
|
||||||
|
intIds = component.getUtility(IIntIds)
|
||||||
|
return intIds.getObject(int(uid))
|
||||||
|
|
||||||
|
def getUidForObject(obj):
|
||||||
|
if obj == '*': # wild card
|
||||||
|
return '*'
|
||||||
|
intIds = component.getUtility(IIntIds)
|
||||||
|
return intIds.queryId(obj)
|
||||||
|
|
Loading…
Add table
Reference in a new issue