diff --git a/README.txt b/README.txt index c4d8838..b8629f7 100755 --- a/README.txt +++ b/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 ============= diff --git a/browser/form.py b/browser/form.py index 4e03714..d60f077 100644 --- a/browser/form.py +++ b/browser/form.py @@ -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 diff --git a/browser/form_macros.pt b/browser/form_macros.pt index 7a83407..65aa458 100644 --- a/browser/form_macros.pt +++ b/browser/form_macros.pt @@ -5,7 +5,7 @@ - - + + @@ -37,7 +38,7 @@
+
Edit Information Object @@ -20,8 +20,9 @@
Assign Concept(s)Concept Assignments
- - + @@ -86,7 +87,7 @@ tal:content="widget/label">label - + + + + + + + + - diff --git a/browser/loops.css b/browser/loops.css index 53fb481..6fbe16c 100644 --- a/browser/loops.css +++ b/browser/loops.css @@ -86,9 +86,9 @@ div.image { /* dojo stuff */ -.dojoComboBox { +/*.dojoComboBox { width: 200px; -} +}*/ .dojoDialog { background: #eee; diff --git a/browser/loops.js b/browser/loops.js index 29a8ae5..4161b58 100644 --- a/browser/loops.js +++ b/browser/loops.js @@ -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 = '' + title + ''; + var tr = document.createElement('tr'); + tr.appendChild(td); + node.appendChild(tr); +} + diff --git a/browser/node.py b/browser/node.py index a25458f..ecd1ad6 100644 --- a/browser/node.py +++ b/browser/node.py @@ -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 diff --git a/browser/node_macros.pt b/browser/node_macros.pt index 8bd08df..f0acdf4 100644 --- a/browser/node_macros.pt +++ b/browser/node_macros.pt @@ -26,24 +26,26 @@
- -
+ Edit -
-
+ Edit -
-
+ +
- - + + + + + + diff --git a/browser/resource.py b/browser/resource.py index adc5f63..41907b0 100644 --- a/browser/resource.py +++ b/browser/resource.py @@ -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) diff --git a/browser/resource_macros.pt b/browser/resource_macros.pt index 72ad251..fcc1e5c 100644 --- a/browser/resource_macros.pt +++ b/browser/resource_macros.pt @@ -1,12 +1,12 @@
-

Title

+

Title

@@ -66,11 +66,11 @@ diff --git a/resource.py b/resource.py index 94cfd17..b3066e0 100644 --- a/resource.py +++ b/resource.py @@ -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'))) diff --git a/search/README.txt b/search/README.txt index d56f642..a29ee86 100755 --- a/search/README.txt +++ b/search/README.txt @@ -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... diff --git a/search/browser.py b/search/browser.py index dbbec1d..4630820 100644 --- a/search/browser.py +++ b/search/browser.py @@ -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') diff --git a/search/search.pt b/search/search.pt index ff71a14..050267b 100644 --- a/search/search.pt +++ b/search/search.pt @@ -28,7 +28,7 @@
- @@ -105,7 +105,7 @@ title="Add type" tal:condition="nothing" />  - + @@ -113,7 +113,7 @@ @@ -151,7 +151,7 @@
+
Create Information Object @@ -65,7 +66,7 @@
Assign Concept(s)Assign Concept(s)
@@ -101,6 +102,21 @@ + +
+ + + Something + (Topic) +
@@ -123,14 +139,19 @@ tal:attributes="dataUrl string:${context/@@absolute_url}/listConceptsForComboBox.js?searchString=%{searchString}&searchType=" /> + +
- - + + +
+ @@ -83,7 +83,7 @@
- +

Type(s) to search for

- +

Search text

- +

Search via related concepts