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:
parent
94a14aac45
commit
1437934070
13 changed files with 149 additions and 65 deletions
30
README.txt
30
README.txt
|
@ -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
|
||||
=============
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -86,9 +86,9 @@ div.image {
|
|||
|
||||
/* dojo stuff */
|
||||
|
||||
.dojoComboBox {
|
||||
/*.dojoComboBox {
|
||||
width: 200px;
|
||||
}
|
||||
}*/
|
||||
|
||||
.dojoDialog {
|
||||
background: #eee;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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')))
|
||||
|
||||
|
||||
|
|
|
@ -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...
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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" />
|
||||
</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>
|
||||
|
|
Loading…
Add table
Reference in a new issue