first running version of creating and roundtrip editing resources via dojo.Dialog

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1359 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-09-24 13:59:56 +00:00
parent 63a13d6854
commit 94a14aac45
10 changed files with 272 additions and 107 deletions

View file

@ -631,7 +631,8 @@ that are shown in the end-user interface.
>>> ITypeConcept(note_tc).typeInterface = INote
>>> component.provideAdapter(ResourceNameChooser)
>>> request = TestRequest(form={'form.title': 'Test Note'})
>>> request = TestRequest(form={'form.title': 'Test Note',
... 'form.type': '.loops/concepts/note'})
>>> view = NodeView(m112, request)
>>> cont = CreateObject(view, request)
>>> cont.update()
@ -647,7 +648,8 @@ created object:
>>> from loops import util
>>> topicUid = util.getUidForObject(topic)
>>> request = TestRequest(form={'form.title': 'Test Note',
... 'form.concept.search.text_selected': topicUid})
... 'form.type': '.loops/concepts/note',
... 'form.concept.search.text_selected': str(topicUid)})
>>> view = NodeView(m112, request)
>>> cont = CreateObject(view, request)
>>> cont.update()

View file

@ -42,6 +42,7 @@ from cybertools.browser.view import GenericView
from cybertools.relation.interfaces import IRelationRegistry
from cybertools.typology.interfaces import IType, ITypeManager
from loops.interfaces import IView
from loops.resource import Resource
from loops.type import ITypeConcept
from loops import util
from loops.util import _
@ -170,6 +171,15 @@ class BaseView(GenericView):
for o in objs:
yield BaseView(o, request)
def resourceTypes(self):
return util.KeywordVocabulary([(t.token, t.title)
for t in ITypeManager(self.context).listTypes(('resource',))
if t.factory == Resource])
def conceptTypes(self):
return util.KeywordVocabulary([(t.token, t.title)
for t in ITypeManager(self.context).listTypes(('concept',))])
def typesForSearch(self):
general = [('loops:resource:*', 'Any Resource'),
('loops:concept:*', 'Any Concept'),]
@ -179,9 +189,13 @@ class BaseView(GenericView):
def conceptTypesForSearch(self):
general = [('loops:concept:*', 'Any Concept'),]
return util.KeywordVocabulary(general + sorted([(t.tokenForSearch, t.title)
for t in ITypeManager(self.context).types
if 'concept' in t.qualifiers]))
return util.KeywordVocabulary(general + [(t.tokenForSearch, t.title)
for t in ITypeManager(self.context).listTypes(('concept',))])
def resourceTypesForSearch(self):
general = [('loops:resource:*', 'Any Resource'),]
return util.KeywordVocabulary(general + [(t.tokenForSearch, t.title)
for t in ITypeManager(self.context).listTypes(('resource',))])
@Lazy
def uniqueId(self):

View file

@ -244,24 +244,6 @@ class ConceptConfigureView(ConceptView):
result = [r for r in result if r.conceptType is None]
return self.viewIterator(result)
def conceptTypes(self):
return util.KeywordVocabulary([(t.token, t.title)
for t in ITypeManager(self.context).listTypes(('concept',))])
def conceptTypesForSearch(self):
general = [('loops:concept:*', 'Any'),]
return util.KeywordVocabulary(general + [(t.tokenForSearch, t.title)
for t in ITypeManager(self.context).listTypes(('concept',))])
def resourceTypes(self):
return util.KeywordVocabulary([(t.token, t.title)
for t in ITypeManager(self.context).listTypes(('resource',))])
def resourceTypesForSearch(self):
general = [('loops:resource:*', 'Any'),]
return util.KeywordVocabulary(general + [(t.tokenForSearch, t.title)
for t in ITypeManager(self.context).listTypes(('resource',))])
def predicates(self):
preds = PredicateSourceList(self.context)
terms = zapi.getMultiAdapter((preds, self.request), ITerms)

View file

@ -303,7 +303,7 @@
/>
<page
for="loops.interfaces.IDocument"
for="loops.interfaces.IResource"
name="document.html"
permission="zope.View"
template="document.pt"
@ -566,6 +566,20 @@
permission="zope.ManageContent"
/>
<page
name="edit_object.html"
for="loops.interfaces.INode"
class="loops.browser.form.EditObjectForm"
permission="zope.ManageContent"
/>
<page
name="inner_form.html"
for="loops.interfaces.INode"
class="loops.browser.form.InnerForm"
permission="zope.ManageContent"
/>
<zope:adapter
name="create_resource"
for="loops.browser.node.NodeView
@ -574,6 +588,14 @@
permission="zope.ManageContent"
/>
<zope:adapter
name="edit_resource"
for="loops.browser.node.NodeView
zope.publisher.interfaces.browser.IBrowserRequest"
factory="loops.browser.form.EditObject"
permission="zope.ManageContent"
/>
<zope:adapter factory="loops.browser.form.ResourceNameChooser" />
<!-- inner HTML views -->

View file

@ -31,36 +31,26 @@ 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.formlib.form import Form, EditForm, FormFields
from zope.publisher.interfaces import BadRequest
from cybertools.ajax import innerHtml
from cybertools.browser.form import FormController
from cybertools.typology.interfaces import IType
from loops.interfaces import IResourceManager
from loops.interfaces import IResourceManager, INote
from loops.browser.node import NodeView
from loops.resource import Resource
from loops.type import ITypeConcept
from loops import util
from loops.util import _
class CreateObjectForm(NodeView, Form):
class ObjectForm(NodeView):
template = ViewPageTemplateFile('form_macros.pt')
@property
def macro(self): return self.template.macros['create']
form_fields = FormFields(
schema.TextLine(__name__='title', title=_(u'Title')),
schema.Text(__name__='data', title=_(u'Body Text')),
schema.TextLine(__name__='linkUrl', title=_(u'Link'), required=False),
)
title = _(u'Enter Note')
form_action = 'create_resource'
def __init__(self, context, request):
super(CreateObjectForm, self).__init__(context, request)
super(ObjectForm, self).__init__(context, request)
def setUp(self):
self.setUpWidgets()
@ -70,6 +60,52 @@ class CreateObjectForm(NodeView, Form):
return innerHtml(self)
class CreateObjectForm(ObjectForm, Form):
@property
def macro(self): return self.template.macros['create']
title = _(u'Create Resource, Type = ')
form_action = 'create_resource'
@property
def form_fields(self):
typeToken = self.request.get('form.type')
if typeToken:
t = self.loopsRoot.loopsTraverse(typeToken)
ifc = ITypeConcept(t).typeInterface
else:
ifc = INote
return FormFields(ifc)
class EditObjectForm(ObjectForm, EditForm):
@property
def macro(self): return self.template.macros['edit']
title = _(u'Edit Resource')
form_action = 'edit_resource'
@Lazy
def typeInterface(self):
return IType(self.context).typeInterface
@property
def form_fields(self):
return FormFields(self.typeInterface)
def __init__(self, context, request):
super(EditObjectForm, self).__init__(context, request)
self.context = self.virtualTargetObject
class InnerForm(ObjectForm):
@property
def macro(self): return self.template.macros['fields']
class CreateObject(FormController):
@Lazy
@ -87,12 +123,13 @@ class CreateObject(FormController):
raise BadRequest('Title field is empty')
name = INameChooser(container).chooseName(title, obj)
container[name] = obj
obj.resourceType = self.loopsRoot.getConceptManager()['note']
tc = form.get('form.type') or '.loops/concepts/note'
obj.resourceType = self.loopsRoot.loopsTraverse(tc)
adapter = IType(obj).typeInterface(obj)
for k in form.keys():
if k.startswith(prefix):
fn = k[len(prefix):]
if fn in ('action',):
if fn in ('action', 'type',) or fn.endswith('-empty-marker'):
continue
value = form[k]
if fn.startswith(conceptPrefix):
@ -104,7 +141,7 @@ class CreateObject(FormController):
return True
def assignConcepts(self, obj, fieldName, value):
if fieldName == 'search.text_selected':
if value and fieldName == 'search.text_selected':
concept = util.getObjectForUid(value)
obj.assignConcept(concept)
@ -117,3 +154,36 @@ class ResourceNameChooser(NameChooser):
name = title.replace(' ', '_').lower()
name = super(ResourceNameChooser, self).chooseName(name, obj)
return name
class EditObject(FormController):
@Lazy
def loopsRoot(self):
return self.view.loopsRoot
def update(self):
prefix = 'form.'
conceptPrefix = 'concept.'
form = self.request.form
obj = self.view.virtualTargetObject
adapter = IType(obj).typeInterface(obj)
for k in form.keys():
if k.startswith(prefix):
fn = k[len(prefix):]
if fn in ('action', 'type',) or fn.endswith('-empty-marker'):
continue
value = form[k]
if fn.startswith(conceptPrefix):
self.assignConcepts(obj, fn[len(conceptPrefix):], value)
else:
setattr(adapter, fn, value)
notify(ObjectModifiedEvent(obj))
return True
def assignConcepts(self, obj, fieldName, value):
if value and fieldName == 'search.text_selected':
concept = util.getObjectForUid(value)
obj.assignConcept(concept)

View file

@ -1,16 +1,82 @@
<metal:block define-macro="create">
<div tal:define="dummy view/setUp">
<form method="post">
<input type="hidden" name="form.action" value="create"
<metal:block define-macro="edit">
<form method="post">
<input type="hidden" name="form.action" value="edit"
tal:attributes="value view/form_action" />
<table cellpadding="3" class="form">
<table cellpadding="3" class="form">
<tbody>
<tr>
<th colspan="4">
<br />
<span tal:replace="view/title"
i18n:translate="">Create Information Object</span>
i18n:translate="">Edit Information Object
</span>
</th>
</tr>
</tbody>
<tbody id="form.fields">
<metal:fields use-macro="view/template/macros/fields" />
</tbody>
<tbody>
<tr>
<td colspan="4" class="headline">Assign Concept(s)</td>
</tr>
<tr metal:use-macro="view/template/macros/search_concepts" />
<tr metal:use-macro="view/template/macros/buttons" />
</tbody>
</table>
</form>
</metal:block>
<metal:block define-macro="create">
<form method="post">
<input type="hidden" name="form.action" value="create"
tal:attributes="value view/form_action" />
<table cellpadding="3" class="form">
<tbody>
<tr>
<th colspan="4">
<br />
<span tal:replace="view/title"
i18n:translate="">Create Information Object</span>
<select name="form.type" id="form.type"
tal:attributes="onChange
string:return replaceFieldsNode(
'form.fields', 'form.type', 'inner_form.html')">
<option value=".loops/concepts/note"
tal:repeat="type view/resourceTypes"
tal:content="type/title"
tal:attributes="value type/token;
selected python:
type.token == (request.get('form.type')
or '.loops/concepts/note')">
Note
</option>
</select>
</th>
</tr>
</tbody>
<tbody id="form.fields">
<metal:fields use-macro="view/template/macros/fields" />
</tbody>
<tbody>
<tr>
<td colspan="4" class="headline">Assign Concept(s)</td>
</tr>
<tr metal:use-macro="view/template/macros/search_concepts" />
<tr metal:use-macro="view/template/macros/buttons" />
</tbody>
</table>
</form>
</metal:block>
<metal:fields define-macro="fields">
<tal:block tal:define="dummy view/setUp">
<tr tal:repeat="widget view/widgets">
<td class="label"
tal:define="hint widget/hint">
@ -31,42 +97,40 @@
</div>
</td>
</tr>
</tal:block>
</metal:fields>
<tr>
<td colspan="4" class="headline">Assign Concept(s)</td>
</tr>
<tr>
<td><label for="form.concept.search.type">Type:</label></td>
<td>
<select name="form.concept.search.type" id="form.concept.search.type"
tal:attributes="onChange
string:setConceptTypeForComboBox(
'form.concept.search.type', 'form.concept.search.text')">
<tal:types repeat="type view/conceptTypesForSearch">
<option value="loops:*"
i18n:translate=""
tal:attributes="value type/token"
tal:content="type/title">Topic</option>
</tal:types>
</select>&nbsp;&nbsp;
</td>
<td><label for="form.concept.search.text">Search text:</label></td>
<td>
<input dojoType="comboBox" mode="remote" autoComplete="False"
name="form.concept.search.text" id="form.concept.search.text"
tal:attributes="dataUrl
string:${context/@@absolute_url}/listConceptsForComboBox.js?searchString=%{searchString}&searchType=" />
</td>
</tr>
<tr>
<tr metal:define-macro="search_concepts">
<td><label for="form.concept.search.type">Type:</label></td>
<td>
<select name="form.concept.search.type" id="form.concept.search.type"
tal:attributes="onChange
string:setConceptTypeForComboBox(
'form.concept.search.type', 'form.concept.search.text')">
<tal:types repeat="type view/conceptTypesForSearch">
<option value="loops:*"
i18n:translate=""
tal:attributes="value type/token"
tal:content="type/title">Topic</option>
</tal:types>
</select>&nbsp;&nbsp;
</td>
<td><label for="form.concept.search.text">Search text:</label></td>
<td>
<input dojoType="comboBox" mode="remote" autoComplete="False"
name="form.concept.search.text" id="form.concept.search.text"
tal:attributes="dataUrl
string:${context/@@absolute_url}/listConceptsForComboBox.js?searchString=%{searchString}&searchType=" />
</td>
</tr>
<tr metal:define-macro="buttons">
<td colspan="4">
<input type="button" value="Cancel"
onclick="createObjectDlg.hide()">
onclick="objectDlg.hide()">
<input type="submit" value="Save"
onclick="createObjectDlg.hide()">
onclick="objectDlg.hide()">
</td>
</tr>
</table>
</form>
</div>
</metal:block>
</tr>

View file

@ -13,9 +13,12 @@ function focusOpener() {
}
}
/*function listConceptsForComboBox() {
return [['Zope', 'zope'], ]
}*/
function replaceFieldsNode(targetId, typeId, url) {
token = dojo.byId(typeId).value;
dojo.io.updateNode(targetId, {
url: url + '?form.type=' + token,
});
}
function submitReplacing(targetId, formId, actionUrl) {
dojo.io.updateNode(targetId, {
@ -54,19 +57,17 @@ function setConceptTypeForComboBox(typeId, cbId) {
dp.searchUrl = newUrl;
}
var createObjectDlg = false;
var objectDlg = false;
function createObjectDialog() {
//createObjectDlg = dojo.widget.byId('createObject');
//createObjectDlg = false;
function objectDialog(url) {
dojo.require('dojo.widget.Dialog');
dojo.require('dojo.widget.ComboBox');
if (!createObjectDlg) {
createObjectDlg = dojo.widget.fromScript('Dialog',
if (!objectDlg) {
objectDlg = dojo.widget.fromScript('Dialog',
{bgColor: 'white', bgOpacity: 0.5, toggle: 'fade', toggleDuration: 250,
executeScripts: true,
href: 'create_object.html'
}, dojo.byId('createObject'));
href: url
}, dojo.byId('objectDialog'));
}
createObjectDlg.show();
objectDlg.show();
}

View file

@ -206,13 +206,16 @@
<metal:actions define-macro="actions">
<div class="menu-2"
tal:define="dummy view/registerDojo">
<a href="javascript:createObjectDialog()"
onclick="createObjectDialog(); return false;">
<a href="#"
onclick="objectDialog('create_object.html'); return false;">
Create Resource...
</a><br />
<a href="#"
onclick="objectDialog('edit_object.html'); return false;">
Edit Resource...
</a>
<span id="createObject">
</span>
</div>
<span id="objectDialog"></span>
</metal:actions>

View file

@ -72,7 +72,7 @@ class IConcept(ILoopsObject, IPotentialTarget):
title=_(u'Title'),
description=_(u'Title of the concept'),
default=u'',
required=False)
required=True)
conceptType = schema.Choice(
title=_(u'Concept Type'),
@ -190,7 +190,7 @@ class IBaseResource(ILoopsObject):
description=_(u'Title of the resource'),
default=u'',
missing_value=u'',
required=False)
required=True)
resourceType = schema.Choice(
title=_(u'Resource Type'),
@ -228,7 +228,7 @@ class IResourceSchema(Interface):
description=_(u'Title of the resource'),
default=u'',
missing_value=u'',
required=False)
required=True)
data = schema.Bytes(
title=_(u'Data'),
@ -549,7 +549,7 @@ class IResourceAdapter(IBaseResourceSchema):
"""
class IFile(IResourceAdapter):
class IFile(IResourceAdapter, IResourceSchema):
""" A media asset that is not shown on a (web) page like an image but
may be downloaded instead.
"""

View file

@ -194,6 +194,15 @@ class FileAdapter(ResourceAdapterBase):
"""
implements(IFile)
_schemas = list(IFile) + list(IBaseResource)
class TextDocumentAdapter(ResourceAdapterBase):
""" A type adapter for providing text document functionality for resources.
"""
implements(IDocument)
_schemas = list(IDocument) + list(IBaseResource)
class NoteAdapter(ResourceAdapterBase):
@ -203,13 +212,11 @@ class NoteAdapter(ResourceAdapterBase):
implements(INote)
_schemas = list(INote) + list(IBaseResource)
#contentType = u'text/restructured'
class DocumentWriteFileAdapter(object):
implements(IWriteFile)
adapts(IDocument)
adapts(IResource)
def __init__(self, context):
self.context = context
@ -222,7 +229,7 @@ class DocumentWriteFileAdapter(object):
class DocumentReadFileAdapter(object):
implements(IReadFile)
adapts(IDocument)
adapts(IResource)
def __init__(self, context):
self.context = context