loops - work in progress: assign concepts via dojo.Dialog

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1379 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-10-02 08:22:05 +00:00
parent 94a14aac45
commit 1437934070
13 changed files with 149 additions and 65 deletions

View file

@ -618,8 +618,11 @@ End-user Forms
The browser.form and related modules provide additional support for forms
that are shown in the end-user interface.
Creating an object
------------------
>>> from loops.browser.form import CreateObjectForm, CreateObject, ResourceNameChooser
>>> form = CreateObjectForm(m112, TestRequest)
>>> form = CreateObjectForm(m112, TestRequest())
>>> from loops.interfaces import INote, ITypeConcept
>>> from loops.type import TypeConcept
@ -631,8 +634,8 @@ that are shown in the end-user interface.
>>> ITypeConcept(note_tc).typeInterface = INote
>>> component.provideAdapter(ResourceNameChooser)
>>> request = TestRequest(form={'form.title': 'Test Note',
... 'form.type': '.loops/concepts/note'})
>>> request = TestRequest(form={'form.title': u'Test Note',
... 'form.type': u'.loops/concepts/note'})
>>> view = NodeView(m112, request)
>>> cont = CreateObject(view, request)
>>> cont.update()
@ -640,15 +643,15 @@ that are shown in the end-user interface.
>>> sorted(resources.keys())
[...u'test_note'...]
>>> resources['test_note'].title
'Test Note'
u'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.type': '.loops/concepts/note',
>>> request = TestRequest(form={'form.title': u'Test Note',
... 'form.type': u'.loops/concepts/note',
... 'form.concept.search.text_selected': str(topicUid)})
>>> view = NodeView(m112, request)
>>> cont = CreateObject(view, request)
@ -660,6 +663,21 @@ created object:
>>> sorted(t.__name__ for t in note.getConcepts())
[u'note', u'topic']
Editing an object
-----------------
>>> from loops.browser.form import EditObjectForm, EditObject
>>> m112.target = resources['test_note']
>>> form = EditObjectForm(m112, TestRequest())
>>> request = TestRequest(form={'form.title': u'Test Note - changed'})
>>> view = NodeView(m112, request)
>>> cont = EditObject(view, request)
>>> cont.update()
True
>>> resources['test_note'].title
u'Test Note - changed'
Import/Export
=============

View file

@ -37,8 +37,9 @@ 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, INote
from loops.interfaces import IResourceManager, INote, IDocument
from loops.browser.node import NodeView
from loops.browser.concept import ConceptRelationView
from loops.resource import Resource
from loops.type import ITypeConcept
from loops import util
@ -54,6 +55,7 @@ class ObjectForm(NodeView):
def setUp(self):
self.setUpWidgets()
# TODO: such stuff should depend on self.typeInterface
self.widgets['data'].height = 3
def __call__(self):
@ -67,6 +69,7 @@ class CreateObjectForm(ObjectForm, Form):
title = _(u'Create Resource, Type = ')
form_action = 'create_resource'
dialog_name = 'create'
@property
def form_fields(self):
@ -76,9 +79,16 @@ class CreateObjectForm(ObjectForm, Form):
ifc = ITypeConcept(t).typeInterface
else:
ifc = INote
self.typeInterface = ifc
return FormFields(ifc)
class InnerForm(CreateObjectForm):
@property
def macro(self): return self.template.macros['fields']
class EditObjectForm(ObjectForm, EditForm):
@property
@ -86,26 +96,26 @@ class EditObjectForm(ObjectForm, EditForm):
title = _(u'Edit Resource')
form_action = 'edit_resource'
dialog_name = 'edit'
@Lazy
def typeInterface(self):
return IType(self.context).typeInterface
return IType(self.context).typeInterface or IDocument
@property
def form_fields(self):
return FormFields(self.typeInterface)
@property
def assignments(self):
for c in self.context.getConceptRelations():
yield ConceptRelationView(c, self.request)
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

View file

@ -5,7 +5,7 @@
<table cellpadding="3" class="form">
<tbody>
<tr>
<th colspan="4">
<th colspan="5">
<br />
<span tal:replace="view/title"
i18n:translate="">Edit Information Object
@ -20,8 +20,9 @@
<tbody>
<tr>
<td colspan="4" class="headline">Assign Concept(s)</td>
<td colspan="5" class="headline">Concept Assignments</td>
</tr>
<tr metal:use-macro="view/template/macros/assignments" />
<tr metal:use-macro="view/template/macros/search_concepts" />
<tr metal:use-macro="view/template/macros/buttons" />
</tbody>
@ -37,7 +38,7 @@
<table cellpadding="3" class="form">
<tbody>
<tr>
<th colspan="4">
<th colspan="5">
<br />
<span tal:replace="view/title"
i18n:translate="">Create Information Object</span>
@ -65,7 +66,7 @@
<tbody>
<tr>
<td colspan="4" class="headline">Assign Concept(s)</td>
<td colspan="5" class="headline">Assign Concept(s)</td>
</tr>
<tr metal:use-macro="view/template/macros/search_concepts" />
<tr metal:use-macro="view/template/macros/buttons" />
@ -86,7 +87,7 @@
tal:content="widget/label">label</span>
</label>
</td>
<td class="field" colspan="3"
<td class="field" colspan="4"
tal:define="hint widget/hint">
<div class="widget" tal:content="structure widget">
<input type="text" />
@ -101,6 +102,21 @@
</metal:fields>
<metal:assignments define-macro="assignments">
<tbody id="form.assignments">
<tr tal:repeat="relation view/assignments">
<td colspan="5">
<input type="hidden" name="form.assignments.tokens:list"
tal:attributes="value relation/token" />
<input type="checkbox" checked />
<span tal:content="relation/title">Something</span>
(<span tal:content="relation/typeTitle">Topic</span>)
</td>
</tr>
</tbody>
</metal:assignments>
<tr metal:define-macro="search_concepts">
<td><label for="form.concept.search.type">Type:</label></td>
<td>
@ -123,14 +139,19 @@
tal:attributes="dataUrl
string:${context/@@absolute_url}/listConceptsForComboBox.js?searchString=%{searchString}&searchType=" />
</td>
<td>
<input type="button" value="Select"
onClick="addConceptAssignment()" />
</td>
</tr>
<tr metal:define-macro="buttons">
<td colspan="4">
<input type="button" value="Cancel"
onclick="objectDlg.hide()">
<input type="submit" value="Save"
onclick="objectDlg.hide()">
<td colspan="5"
tal:define="dlgName view/dialog_name">
<input type="button" value="Cancel" onClick="dlg.hide();"
tal:attributes="onClick string:dialogs['$dlgName'].hide()">
<input type="submit" value="Save" onClick="dlg.hide()"
tal:attributes="onClick string:dialogs['$dlgName'].hide()">
</td>
</tr>

View file

@ -86,9 +86,9 @@ div.image {
/* dojo stuff */
.dojoComboBox {
/*.dojoComboBox {
width: 200px;
}
}*/
.dojoDialog {
background: #eee;

View file

@ -33,13 +33,15 @@ function inlineEdit(id, saveUrl) {
//dojo.require('dojo.widget.Editor');
var iconNode = dojo.byId('inlineedit_icon');
iconNode.style.visibility = 'hidden';
var editor = dojo.widget.fromScript('Editor',
//var editor = dojo.widget.fromScript('Editor',
editor = dojo.widget.createWidget('Editor',
{items: ['save', '|', 'formatblock', '|',
'insertunorderedlist', 'insertorderedlist', '|',
'bold', 'italic', '|', 'createLink', 'insertimage'],
saveUrl: saveUrl,
closeOnSave: true,
htmlEditing: true,
//onClose: function() {
onSave: function() {
this.disableToolbar(true);
iconNode.style.visibility = 'visible';
@ -57,17 +59,34 @@ function setConceptTypeForComboBox(typeId, cbId) {
dp.searchUrl = newUrl;
}
var objectDlg = false;
var dialogs = {}
function objectDialog(url) {
function objectDialog(dlgName, url) {
dojo.require('dojo.widget.Dialog');
dojo.require('dojo.widget.ComboBox');
if (!objectDlg) {
objectDlg = dojo.widget.fromScript('Dialog',
dlg = dialogs[dlgName];
if (!dlg) {
//dlg = dojo.widget.fromScript('Dialog',
dlg = dojo.widget.createWidget('Dialog',
{bgColor: 'white', bgOpacity: 0.5, toggle: 'fade', toggleDuration: 250,
executeScripts: true,
href: url
}, dojo.byId('objectDialog'));
}, dojo.byId('dialog.' + dlgName));
dialogs[dlgName] = dlg;
}
objectDlg.show();
dlg.show();
}
function addConceptAssignment() {
node = dojo.byId('form.assignments');
token = document.getElementsByName('form.concept.search.text_selected')[0].value;
if (token.length == 0) {return false;}
title = document.getElementsByName('form.concept.search.text')[0].value;
var td = document.createElement('td');
td.setAttribute('colspan', '5');
td.innerHTML = '<input type="hidden" name="form.assignments.tokens:list" value="' + token + '" /><input type="checkbox" checked /><span>' + title + '</span>';
var tr = document.createElement('tr');
tr.appendChild(td);
node.appendChild(tr);
}

View file

@ -291,6 +291,10 @@ class NodeView(BaseView):
if target is not None:
return BaseView(target, self.request).url
@Lazy
def hasEditableTarget(self):
return IResource.providedBy(self.virtualTargetObject)
@Lazy
def inlineEditable(self):
target = self.virtualTarget

View file

@ -26,24 +26,26 @@
<div tal:define="target nocall:item/target"
tal:condition="nocall:target">
<tal:ignore condition="nothing">
<metal:editicons define-macro="editicons">
<div class="subcolumn" id="xedit_icon"
<div metal:define-macro="editicons"
style="float: right; border: 1px solid #ccc;
margin-top: 1em">
<span id="xedit_icon"
tal:condition="item/xeditable | nothing">
<a href="#" title="Edit" style="padding: 5px"
tal:attributes="href string:${item/realTargetUrl}/external_edit;
title string:Edit '${target/title}' with External Editor"><img
src="edit.gif" alt="Edit"
tal:attributes="src context/++resource++edit.gif" /></a>
</div>
<div class="subcolumn" id="inlineedit_icon"
</span>
<span id="inlineedit_icon"
tal:condition="item/inlineEditable">
<a href="#" title="Edit" style="padding: 5px"
tal:attributes="title string:Edit '${target/title}' with Inline Editor;
onclick python: item.inlineEdit(id)"><img
src="edit.gif" alt="Edit"
tal:attributes="src context/++resource++edit.gif" /></a>
</div>
</metal:editicons>
</span>
</div>
</tal:ignore>
<div class="content-1 subcolumn" id="1.body"
tal:define="node nocall:item;
@ -204,18 +206,23 @@
<metal:actions define-macro="actions">
<div class="menu-2"
tal:define="dummy view/registerDojo">
<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>
</div>
<span id="objectDialog"></span>
<tal:actions define="dummy view/registerDojo">
<div class="menu-2">
<a href="#"
onclick="objectDialog('create', 'create_object.html'); return false;">
Create Resource...
</a>
</div>
<div class="menu-2"
tal:condition="view/hasEditableTarget">
<a href="#"
onclick="objectDialog('edit', 'edit_object.html'); return false;">
Edit Resource...
</a>
</div>
</tal:actions>
<span id="dialog.create"></span>
<span id="dialog.edit"></span>
</metal:actions>

View file

@ -122,6 +122,11 @@ class ResourceView(BaseView):
for r in self.context.getConceptRelations():
yield ConceptRelationView(r, self.request)
def relatedConcepts(self):
for c in self.concepts():
if c.isProtected: continue
yield c
def clients(self):
for node in self.context.getClients():
yield NodeView(node, self.request)

View file

@ -1,12 +1,12 @@
<metal:block define-macro="render">
<div tal:attributes="ondblclick python: item.openEditWindow('configure.html')">
<h1 tal:content="item/title">Title</h1>
<tal:body define="itemNum view/itemNum;
id string:$itemNum.body;">
<tal:edit define="target nocall:item;
item nocall:node|nocall:view;">
<div metal:use-macro="views/node_macros/editicons" />
</tal:edit>
<h1 tal:content="item/title">Title</h1>
<div class="content-1" id="1.body"
tal:attributes="id id;"
tal:content="structure item/render">
@ -66,11 +66,11 @@
<metal:actions define-macro="related">
<div class="menu-2"
tal:repeat="concept macro/info/concepts">
tal:repeat="concept macro/info/relatedConcepts">
<a href="#"
tal:content="concept/title"
tal:attributes="href string:${view/url}/.target${concept/uniqueId}">
Concept
<span tal:replace="concept/title">Concept</span>
(<i tal:content="concept/typeTitle">Type</i>)
</a>
</div>
</metal:actions>

View file

@ -46,7 +46,7 @@ from cybertools.typology.interfaces import ITypeManager
from interfaces import IBaseResource, IResource
from interfaces import IFile, INote
from interfaces import IDocument, IDocumentSchema, IDocumentView
from interfaces import IDocument, ITextDocument, IDocumentSchema, IDocumentView
from interfaces import IMediaAsset, IMediaAssetView
from interfaces import IResourceManager, IResourceManagerContained
from interfaces import ILoopsContained
@ -222,7 +222,7 @@ class DocumentWriteFileAdapter(object):
self.context = context
def write(self, data):
self.context.data = unicode(data.replace('\r', ''), 'UTF-8')
ITextDocument(self.context).data = unicode(data.replace('\r', ''), 'UTF-8')
notify(ObjectModifiedEvent(self.context, Attributes(IDocument, 'data')))

View file

@ -1,4 +1,4 @@
===================================================================
4===================================================================
loops.search - Provide search functionality for the loops framework
===================================================================
@ -198,7 +198,7 @@ of the concepts' titles:
>>> request = TestRequest(form=form)
>>> view = Search(page, request)
>>> view.listConcepts()
"[['Zope', '23']]"
"[['Zope (Topic)', '23']]"
TODO - more to come...

View file

@ -80,7 +80,7 @@ class Search(BaseView):
result = ConceptQuery(self).query(title=title, type=type)
registry = component.getUtility(IRelationRegistry)
# simple way to provide JSON format:
return str(sorted([[`o.title`[2:-1],
return str(sorted([[`o.title`[2:-1] + ' (%s)' % `o.conceptType.title`[2:-1],
`registry.getUniqueIdForObject(o)`]
for o in result
if o.getLoopsRoot() == self.loopsRoot])).replace('\\\\x', '\\x')

View file

@ -28,7 +28,7 @@
</tr>
<tr>
<td></td>
<td colspan="2">
<td colspan="3">
<input type="submit" name="button.search" value="Search" class="submit"
tal:attributes="onclick python:
item.submitReplacing(resultsId, formId, view)" />
@ -83,7 +83,7 @@
<metal:text define-macro="type">
<tr>
<td metal:use-macro="macros/minus"/>
<td colspan="2">
<td colspan="3">
<h3>Type(s) to search for</h3>
</td>
<tr>
@ -105,7 +105,7 @@
title="Add type"
tal:condition="nothing" />&nbsp;
</td>
<td></td>
<td colspan="2"></td>
</tr>
</metal:text>
@ -113,7 +113,7 @@
<metal:text define-macro="text">
<tr>
<td metal:use-macro="macros/minus"/>
<td colspan="2">
<td colspan="3">
<h3>Search text</h3>
</td>
<tr>
@ -151,7 +151,7 @@
<metal:text define-macro="concept">
<tr>
<td metal:use-macro="macros/minus"/>
<td colspan="2">
<td colspan="3">
<h3>Search via related concepts</h3>
</td>
<tr>