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',))
|
||||
>>> defineChecker(Node, nodeChecker)
|
||||
|
||||
>>> loopsRoot['views'] = ViewManager()
|
||||
>>> views = loopsRoot['views']
|
||||
>>> views = loopsRoot['views'] = ViewManager()
|
||||
|
||||
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:
|
||||
|
||||
>>> m1 = Node(u'Menu')
|
||||
>>> views['m1'] = m1
|
||||
>>> m11 = Node(u'Zope')
|
||||
>>> m1['m11'] = m11
|
||||
>>> m111 = Node(u'Zope in General')
|
||||
>>> m11['m111'] = m111
|
||||
>>> m112 = Node(u'Zope 3')
|
||||
>>> m11['m112'] = m112
|
||||
>>> m1 = views['m1'] = Node(u'Menu')
|
||||
>>> m11 = m1['m11'] = Node(u'Zope')
|
||||
>>> m111 = m11['m111'] = Node(u'Zope in General')
|
||||
>>> m112 = m11['m112'] = Node(u'Zope 3')
|
||||
>>> m112.title
|
||||
u'Zope 3'
|
||||
>>> m112.description
|
||||
|
@ -616,8 +611,56 @@ to the bottom, and to the top.
|
|||
>>> m11.keys()
|
||||
['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
|
||||
-------------
|
||||
=============
|
||||
|
||||
Nodes may be exported to and loaded from external sources, typically
|
||||
file representations that allow the transfer of nodes from one Zope
|
||||
|
|
|
@ -574,6 +574,8 @@
|
|||
permission="zope.ManageContent"
|
||||
/>
|
||||
|
||||
<zope:adapter factory="loops.browser.form.ResourceNameChooser" />
|
||||
|
||||
<!-- inner HTML views -->
|
||||
|
||||
<page
|
||||
|
|
|
@ -23,12 +23,25 @@ $Id$
|
|||
"""
|
||||
|
||||
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.cachedescriptors.property import Lazy
|
||||
from zope.formlib.form import Form, FormFields
|
||||
from zope.publisher.interfaces import BadRequest
|
||||
|
||||
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.resource import Resource
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
|
||||
class CreateObjectForm(NodeView, Form):
|
||||
|
||||
|
@ -39,7 +52,7 @@ class CreateObjectForm(NodeView, Form):
|
|||
|
||||
form_fields = FormFields(
|
||||
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),
|
||||
)
|
||||
|
||||
|
@ -48,8 +61,10 @@ class CreateObjectForm(NodeView, Form):
|
|||
|
||||
def __init__(self, context, request):
|
||||
super(CreateObjectForm, self).__init__(context, request)
|
||||
|
||||
def setUp(self):
|
||||
self.setUpWidgets()
|
||||
self.widgets['body'].height = 3
|
||||
self.widgets['data'].height = 3
|
||||
|
||||
def __call__(self):
|
||||
return innerHtml(self)
|
||||
|
@ -57,22 +72,48 @@ class CreateObjectForm(NodeView, Form):
|
|||
|
||||
class CreateObject(FormController):
|
||||
|
||||
@Lazy
|
||||
def loopsRoot(self):
|
||||
return self.view.loopsRoot
|
||||
|
||||
def update(self):
|
||||
prefix = 'form.'
|
||||
conceptPrefix = 'concept.'
|
||||
form = self.request.form
|
||||
print 'updating...'
|
||||
# determine name
|
||||
# create object, assign basic concepts (type, ...)
|
||||
obj = Resource()
|
||||
container = self.loopsRoot.getResourceManager()
|
||||
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():
|
||||
if k.startswith(prefix):
|
||||
fn = k[len(prefix):]
|
||||
if fn in ('action',):
|
||||
continue
|
||||
value = form[k]
|
||||
if fn.startswith('concept.search.'):
|
||||
self.assignConcepts(fn, value)
|
||||
if fn.startswith(conceptPrefix):
|
||||
self.assignConcepts(obj, fn[len(conceptPrefix):], value)
|
||||
else:
|
||||
pass
|
||||
#setattr(obj, fn, value)
|
||||
print fn, value
|
||||
setattr(adapter, fn, value)
|
||||
notify(ObjectCreatedEvent(obj))
|
||||
notify(ObjectModifiedEvent(obj))
|
||||
return True
|
||||
|
||||
def assignConcepts(self, fieldName, value):
|
||||
pass
|
||||
def assignConcepts(self, obj, fieldName, value):
|
||||
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">
|
||||
<div>
|
||||
<form method="get">
|
||||
<div tal:define="dummy view/setUp">
|
||||
<form method="post">
|
||||
<input type="hidden" name="form.action" value="create"
|
||||
tal:attributes="value view/form_action" />
|
||||
<table cellpadding="3" class="form">
|
||||
|
@ -10,6 +10,7 @@
|
|||
i18n:translate="">Create Information Object</span>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr tal:repeat="widget view/widgets">
|
||||
<td class="label"
|
||||
tal:define="hint widget/hint">
|
||||
|
@ -30,6 +31,7 @@
|
|||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="4" class="headline">Assign Concept(s)</td>
|
||||
</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.app import traversing
|
||||
from zope.app.catalog.interfaces import ICatalog
|
||||
from zope.app.intid.interfaces import IIntIds
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
from loops.interfaces import IConcept
|
||||
from loops.common import AdapterBase
|
||||
from loops.type import TypeInterfaceSourceList
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
|
||||
|
||||
|
@ -82,8 +82,7 @@ class BaseQuery(object):
|
|||
if not uid:
|
||||
queue = list(self.queryConcepts(title=title, type=type))
|
||||
else:
|
||||
intIds = component.getUtility(IIntIds)
|
||||
queue = [intIds.getObject(int(uid))]
|
||||
queue = [util.getObjectForUid(uid)]
|
||||
concepts = []
|
||||
while queue:
|
||||
c = queue.pop(0)
|
||||
|
|
|
@ -119,6 +119,7 @@ purposes fairly primitive) catalog and a resource we can search for:
|
|||
... implements(ICatalog)
|
||||
... def searchResults(self, **criteria):
|
||||
... name = criteria.get('loops_title')
|
||||
... if name.endswith('*'): name = name[:-1]
|
||||
... type = criteria.get('loops_type', ('resource',))
|
||||
... if name:
|
||||
... 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
|
||||
resource (rplone) from above to one of the topics:
|
||||
|
||||
>>> czope = concepts['zope'] = Concept('Zope')
|
||||
>>> czope2 = concepts['zope2'] = Concept('Zope 2')
|
||||
>>> czope3 = concepts['zope3'] = Concept('Zope 3')
|
||||
>>> cplone = concepts['plone'] = Concept('Plone')
|
||||
>>> czope = concepts['zope'] = Concept(u'Zope')
|
||||
>>> czope2 = concepts['zope2'] = Concept(u'Zope 2')
|
||||
>>> czope3 = concepts['zope3'] = Concept(u'Zope 3')
|
||||
>>> cplone = concepts['plone'] = Concept(u'Plone')
|
||||
>>> for c in (czope, czope2, czope3, cplone):
|
||||
... c.conceptType = topic
|
||||
>>> 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
|
||||
of the concepts' titles:
|
||||
|
||||
>>> form = {'searchType': 'loops:concept:topic', 'searchString': u'zo'}
|
||||
>>> form = {'searchType': 'loops:concept:topic', 'searchString': u'zope'}
|
||||
>>> request = TestRequest(form=form)
|
||||
>>> view = Search(page, request)
|
||||
>>> view.listConcepts()
|
||||
'[]'
|
||||
"[['Zope', '23']]"
|
||||
|
||||
TODO - more to come...
|
||||
|
||||
|
|
14
util.py
14
util.py
|
@ -22,6 +22,8 @@ Utility functions.
|
|||
$Id$
|
||||
"""
|
||||
|
||||
from zope import component
|
||||
from zope.app.intid.interfaces import IIntIds
|
||||
from zope.interface import directlyProvides, directlyProvidedBy
|
||||
from zope.i18nmessageid import MessageFactory
|
||||
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'))
|
||||
else: # gracefully handle Mac line endings
|
||||
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