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