use dojo.Dialog for entry forms; set up INote resource as first example (and start to clean-up retrieving views for resources)
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1352 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
d5532f1c72
commit
980114d649
16 changed files with 341 additions and 44 deletions
|
@ -18,6 +18,7 @@ with lower-level aspects like type or state management.
|
||||||
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||||
>>> site = placefulSetUp(True)
|
>>> site = placefulSetUp(True)
|
||||||
|
|
||||||
|
>>> from zope import component
|
||||||
>>> from zope.app import zapi
|
>>> from zope.app import zapi
|
||||||
>>> from zope.app.tests import ztapi
|
>>> from zope.app.tests import ztapi
|
||||||
>>> from zope.interface import Interface
|
>>> from zope.interface import Interface
|
||||||
|
@ -122,7 +123,7 @@ type manager.
|
||||||
|
|
||||||
>>> from cybertools.typology.interfaces import ITypeManager
|
>>> from cybertools.typology.interfaces import ITypeManager
|
||||||
>>> from loops.interfaces import ILoopsObject
|
>>> from loops.interfaces import ILoopsObject
|
||||||
>>> from loops.type import LoopsTypeManager
|
>>> from loops.type import LoopsTypeManager, LoopsType
|
||||||
>>> ztapi.provideAdapter(ILoopsObject, ITypeManager, LoopsTypeManager)
|
>>> ztapi.provideAdapter(ILoopsObject, ITypeManager, LoopsTypeManager)
|
||||||
|
|
||||||
>>> from loops.concept import ConceptTypeSourceList
|
>>> from loops.concept import ConceptTypeSourceList
|
||||||
|
@ -545,6 +546,8 @@ and of a lot of other stuff needed for the rendering machine.
|
||||||
... with=(IBrowserRequest,))
|
... with=(IBrowserRequest,))
|
||||||
|
|
||||||
>>> m112.target = doc1
|
>>> m112.target = doc1
|
||||||
|
|
||||||
|
>>> component.provideAdapter(LoopsType)
|
||||||
>>> view = NodeView(m112, TestRequest())
|
>>> view = NodeView(m112, TestRequest())
|
||||||
>>> view.renderTarget()
|
>>> view.renderTarget()
|
||||||
u''
|
u''
|
||||||
|
|
|
@ -42,6 +42,7 @@ from cybertools.browser.view import GenericView
|
||||||
from cybertools.relation.interfaces import IRelationRegistry
|
from cybertools.relation.interfaces import IRelationRegistry
|
||||||
from cybertools.typology.interfaces import IType, ITypeManager
|
from cybertools.typology.interfaces import IType, ITypeManager
|
||||||
from loops.interfaces import IView
|
from loops.interfaces import IView
|
||||||
|
from loops.type import ITypeConcept
|
||||||
from loops import util
|
from loops import util
|
||||||
from loops.util import _
|
from loops.util import _
|
||||||
|
|
||||||
|
@ -135,16 +136,37 @@ class BaseView(GenericView):
|
||||||
def value(self):
|
def value(self):
|
||||||
return self.context
|
return self.context
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def type(self):
|
||||||
|
return IType(self.context)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def typeProvider(self):
|
||||||
|
type = self.type
|
||||||
|
if type is not None:
|
||||||
|
return type.typeProvider
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def typeInterface(self):
|
||||||
|
provider = self.typeProvider
|
||||||
|
if provider is not None:
|
||||||
|
tc = ITypeConcept(provider)
|
||||||
|
return tc.typeInterface
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def typeAdapter(self):
|
||||||
|
ifc = self.typeInterface
|
||||||
|
if ifc is not None:
|
||||||
|
return ifc(self.context)
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def typeTitle(self):
|
def typeTitle(self):
|
||||||
type = IType(self.context)
|
type = self.type
|
||||||
return type is not None and type.title or None
|
return type is not None and type.title or None
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def typeUrl(self):
|
def typeUrl(self):
|
||||||
type = IType(self.context)
|
provider = self.typeProvider
|
||||||
if type is not None:
|
|
||||||
provider = type.typeProvider
|
|
||||||
if provider is not None:
|
if provider is not None:
|
||||||
return zapi.absoluteURL(provider, self.request)
|
return zapi.absoluteURL(provider, self.request)
|
||||||
return None
|
return None
|
||||||
|
@ -161,6 +183,12 @@ class BaseView(GenericView):
|
||||||
for t in ITypeManager(self.context).types])
|
for t in ITypeManager(self.context).types])
|
||||||
+ [('loops:*', 'Any')])
|
+ [('loops:*', 'Any')])
|
||||||
|
|
||||||
|
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]))
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def uniqueId(self):
|
def uniqueId(self):
|
||||||
return zapi.getUtility(IRelationRegistry).getUniqueIdForObject(self.context)
|
return zapi.getUtility(IRelationRegistry).getUniqueIdForObject(self.context)
|
||||||
|
|
|
@ -324,6 +324,15 @@
|
||||||
permission="zope.View"
|
permission="zope.View"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="note.html"
|
||||||
|
for="loops.interfaces.IResource
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="loops.browser.resource.NoteView"
|
||||||
|
permission="zope.View"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- media asset -->
|
<!-- media asset -->
|
||||||
|
|
||||||
<!--<editform
|
<!--<editform
|
||||||
|
@ -548,6 +557,15 @@
|
||||||
permission="zope.View"
|
permission="zope.View"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- forms (end-user view) -->
|
||||||
|
|
||||||
|
<page
|
||||||
|
name="create_object.html"
|
||||||
|
for="loops.interfaces.INode"
|
||||||
|
class="loops.browser.node.CreateObject"
|
||||||
|
permission="zope.ManageContent"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- inner HTML views -->
|
<!-- inner HTML views -->
|
||||||
|
|
||||||
<page
|
<page
|
||||||
|
|
70
browser/form_macros.pt
Normal file
70
browser/form_macros.pt
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<metal:block define-macro="create">
|
||||||
|
<div>
|
||||||
|
<form method="get">
|
||||||
|
<input type="hidden" name="form.action" value="create"
|
||||||
|
tal:attributes="value view/form_action" />
|
||||||
|
<table cellpadding="3" class="form">
|
||||||
|
<tr>
|
||||||
|
<th colspan="4">
|
||||||
|
<span tal:replace="view/title"
|
||||||
|
i18n:translate="">Create Information Object</span>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr tal:repeat="widget view/widgets">
|
||||||
|
<td class="label"
|
||||||
|
tal:define="hint widget/hint">
|
||||||
|
<label tal:attributes="for widget/name">
|
||||||
|
<span class="required" tal:condition="widget/required"
|
||||||
|
>*</span><span i18n:translate=""
|
||||||
|
tal:content="widget/label">label</span>
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td class="field" colspan="3"
|
||||||
|
tal:define="hint widget/hint">
|
||||||
|
<div class="widget" tal:content="structure widget">
|
||||||
|
<input type="text" />
|
||||||
|
</div>
|
||||||
|
<div class="error"
|
||||||
|
tal:condition="widget/error">
|
||||||
|
<span tal:replace="structure widget/error">error</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="headline">Assign Concept(s)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="dlg.create.search.type">Type:</label></td>
|
||||||
|
<td>
|
||||||
|
<select name="dlg.create.search.type" id="dlg.create.search.type"
|
||||||
|
tal:attributes="onChange
|
||||||
|
string:setConceptTypeForComboBox(
|
||||||
|
'dlg.create.search.type', 'dlg.create.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>
|
||||||
|
</td>
|
||||||
|
<td><label for="dlg.create.search.text">Search text:</label></td>
|
||||||
|
<td>
|
||||||
|
<input dojoType="comboBox" mode="remote" autoComplete="False"
|
||||||
|
name="dlg.create.search.text" id="dlg.create.search.text"
|
||||||
|
tal:attributes="dataUrl
|
||||||
|
string:${context/@@absolute_url}/listConceptsForComboBox.js?searchString=%{searchString}&searchType=" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4">
|
||||||
|
<input type="button" value="Cancel"
|
||||||
|
onclick="createObjectDlg.hide()">
|
||||||
|
<input type="submit" value="Save"
|
||||||
|
onclick="createObjectDlg.hide()">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</metal:block>
|
|
@ -84,3 +84,34 @@ div.image {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* dojo stuff */
|
||||||
|
|
||||||
|
.dojoComboBox {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dojoDialog {
|
||||||
|
background: #eee;
|
||||||
|
border: 1px solid #999;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dojoDialog th {
|
||||||
|
font-size: 120%;
|
||||||
|
padding: 0 5px 8px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dojoDialog .headline {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dojoDialog input.text {
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dojoDialog input.submit {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@ function focusOpener() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function listConceptsForComboBox() {
|
/*function listConceptsForComboBox() {
|
||||||
return [['Zope', 'zope'], ]
|
return [['Zope', 'zope'], ]
|
||||||
}
|
}*/
|
||||||
|
|
||||||
function submitReplacing(targetId, formId, actionUrl) {
|
function submitReplacing(targetId, formId, actionUrl) {
|
||||||
dojo.io.updateNode(targetId, {
|
dojo.io.updateNode(targetId, {
|
||||||
|
@ -27,17 +27,21 @@ function submitReplacing(targetId, formId, actionUrl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function inlineEdit(id, saveUrl) {
|
function inlineEdit(id, saveUrl) {
|
||||||
var iconNode = dojo.byId("inlineedit_icon");
|
//dojo.require('dojo.widget.Editor');
|
||||||
iconNode.style.visibility = "hidden";
|
var iconNode = dojo.byId('inlineedit_icon');
|
||||||
var editor = dojo.widget.fromScript("Editor",
|
iconNode.style.visibility = 'hidden';
|
||||||
{items: ["save", "|", "formatblock", "|",
|
var editor = dojo.widget.fromScript('Editor',
|
||||||
"insertunorderedlist", "insertorderedlist", "|",
|
{items: ['save', '|', 'formatblock', '|',
|
||||||
"bold", "italic", "|", "createLink", "insertimage"],
|
'insertunorderedlist', 'insertorderedlist', '|',
|
||||||
|
'bold', 'italic', '|', 'createLink', 'insertimage'],
|
||||||
saveUrl: saveUrl,
|
saveUrl: saveUrl,
|
||||||
closeOnSave: true,
|
closeOnSave: true,
|
||||||
|
htmlEditing: true,
|
||||||
onSave: function() {
|
onSave: function() {
|
||||||
this.disableToolbar(true);
|
this.disableToolbar(true);
|
||||||
iconNode.style.visibility = "visible";}
|
iconNode.style.visibility = 'visible';
|
||||||
|
//window.location.reload();
|
||||||
|
}
|
||||||
}, dojo.byId(id));
|
}, dojo.byId(id));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -50,3 +54,19 @@ function setConceptTypeForComboBox(typeId, cbId) {
|
||||||
dp.searchUrl = newUrl;
|
dp.searchUrl = newUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var createObjectDlg = false;
|
||||||
|
|
||||||
|
function createObjectDialog() {
|
||||||
|
//createObjectDlg = dojo.widget.byId('createObject');
|
||||||
|
//createObjectDlg = false;
|
||||||
|
dojo.require('dojo.widget.Dialog');
|
||||||
|
dojo.require('dojo.widget.ComboBox');
|
||||||
|
if (!createObjectDlg) {
|
||||||
|
createObjectDlg = dojo.widget.fromScript('Dialog',
|
||||||
|
{bgColor: 'white', bgOpacity: 0.5, toggle: 'fade', toggleDuration: 250,
|
||||||
|
executeScripts: true,
|
||||||
|
href: 'create_object.html'
|
||||||
|
}, dojo.byId('createObject'));
|
||||||
|
}
|
||||||
|
createObjectDlg.show();
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ View class for Node objects.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope import component, interface
|
from zope import component, interface, schema
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.app import zapi
|
from zope.app import zapi
|
||||||
from zope.app.annotation.interfaces import IAnnotations
|
from zope.app.annotation.interfaces import IAnnotations
|
||||||
|
@ -34,6 +34,7 @@ from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||||
from zope.dottedname.resolve import resolve
|
from zope.dottedname.resolve import resolve
|
||||||
from zope.event import notify
|
from zope.event import notify
|
||||||
|
from zope.formlib.form import Form, FormFields
|
||||||
from zope.formlib.namedtemplate import NamedTemplate
|
from zope.formlib.namedtemplate import NamedTemplate
|
||||||
from zope.proxy import removeAllProxies
|
from zope.proxy import removeAllProxies
|
||||||
from zope.security import canAccess, canWrite
|
from zope.security import canAccess, canWrite
|
||||||
|
@ -50,6 +51,7 @@ from loops.interfaces import IConcept, IResource, IDocument, IMediaAsset, INode
|
||||||
from loops.interfaces import IViewConfiguratorSchema
|
from loops.interfaces import IViewConfiguratorSchema
|
||||||
from loops.resource import MediaAsset
|
from loops.resource import MediaAsset
|
||||||
from loops import util
|
from loops import util
|
||||||
|
from loops.util import _
|
||||||
from loops.browser.common import BaseView
|
from loops.browser.common import BaseView
|
||||||
from loops.browser.concept import ConceptView
|
from loops.browser.concept import ConceptView
|
||||||
|
|
||||||
|
@ -78,8 +80,8 @@ class NodeView(BaseView):
|
||||||
# from sub- (other) packages?
|
# from sub- (other) packages?
|
||||||
# see controller / configurator: use multiple configurators;
|
# see controller / configurator: use multiple configurators;
|
||||||
# register additional configurators (adapters) from within package.
|
# register additional configurators (adapters) from within package.
|
||||||
cm.register('portlet_right', 'worklist', title='Worklist',
|
cm.register('portlet_right', 'actions', title='Actions',
|
||||||
subMacro=self.template.macros['worklist'])
|
subMacro=self.template.macros['actions'])
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def view(self):
|
def view(self):
|
||||||
|
@ -156,6 +158,7 @@ class NodeView(BaseView):
|
||||||
|
|
||||||
def renderTarget(self):
|
def renderTarget(self):
|
||||||
target = self.target
|
target = self.target
|
||||||
|
#targetAdapter = target.typeAdapter
|
||||||
return target is not None and target.render() or u''
|
return target is not None and target.render() or u''
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -164,9 +167,10 @@ class NodeView(BaseView):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def bodyMacro(self):
|
def bodyMacro(self):
|
||||||
# TODO: replace by: return self.target.macroName
|
# TODO: replace by something like: return self.target.macroName
|
||||||
target = self.targetObject
|
target = self.targetObject
|
||||||
if target is None or IDocument.providedBy(target):
|
if (target is None or IDocument.providedBy(target)
|
||||||
|
or (IResource.providedBy(target) and target.contentType.startswith('text/'))):
|
||||||
return 'textbody'
|
return 'textbody'
|
||||||
if IConcept.providedBy(target):
|
if IConcept.providedBy(target):
|
||||||
return 'conceptbody'
|
return 'conceptbody'
|
||||||
|
@ -295,6 +299,12 @@ class NodeView(BaseView):
|
||||||
cm.register('js-execute', jsCall, jsCall=jsCall)
|
cm.register('js-execute', jsCall, jsCall=jsCall)
|
||||||
return 'return inlineEdit("%s", "%s/inline_save")' % (id, self.virtualTargetUrl)
|
return 'return inlineEdit("%s", "%s/inline_save")' % (id, self.virtualTargetUrl)
|
||||||
|
|
||||||
|
def registerDojoDialog(self):
|
||||||
|
self.registerDojo()
|
||||||
|
cm = self.controller.macros
|
||||||
|
jsCall = 'dojo.require("dojo.widget.Dialog")'
|
||||||
|
cm.register('js-execute', jsCall, jsCall=jsCall)
|
||||||
|
|
||||||
|
|
||||||
# inner HTML views
|
# inner HTML views
|
||||||
|
|
||||||
|
@ -314,10 +324,43 @@ class InlineEdit(NodeView):
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
target = self.virtualTargetObject
|
target = self.virtualTargetObject
|
||||||
target.data = self.request.form['editorContent']
|
data = self.request.form['editorContent']
|
||||||
|
if type(data) != unicode:
|
||||||
|
try:
|
||||||
|
data = data.decode('ISO-8859-15') # IE hack
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print 'loops.browser.node.InlineEdit.save():', data
|
||||||
|
return
|
||||||
|
# data = data.decode('UTF-8')
|
||||||
|
target.data = data
|
||||||
notify(ObjectModifiedEvent(target, Attributes(IResource, 'data')))
|
notify(ObjectModifiedEvent(target, Attributes(IResource, 'data')))
|
||||||
|
|
||||||
|
|
||||||
|
class CreateObject(NodeView, Form):
|
||||||
|
|
||||||
|
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__='body', title=_(u'Body Text')),
|
||||||
|
schema.TextLine(__name__='linkUrl', title=_(u'Link'), required=False),
|
||||||
|
)
|
||||||
|
|
||||||
|
title = _(u'Enter Note')
|
||||||
|
form_action = 'create_note'
|
||||||
|
|
||||||
|
def __init__(self, context, request):
|
||||||
|
super(CreateObject, self).__init__(context, request)
|
||||||
|
self.setUpWidgets()
|
||||||
|
self.widgets['body'].height = 3
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
return innerHtml(self)
|
||||||
|
|
||||||
|
|
||||||
# special (named) views for nodes
|
# special (named) views for nodes
|
||||||
|
|
||||||
class SpecialNodeView(NodeView):
|
class SpecialNodeView(NodeView):
|
||||||
|
|
|
@ -198,8 +198,16 @@
|
||||||
</metal:actions>
|
</metal:actions>
|
||||||
|
|
||||||
|
|
||||||
<metal:actions define-macro="worklist">
|
<metal:actions define-macro="actions">
|
||||||
<div class="menu-2">Create Resource...</div>
|
<div class="menu-2"
|
||||||
|
tal:define="dummy view/registerDojo">
|
||||||
|
<a href="#"
|
||||||
|
onclick="createObjectDialog(); return false;">
|
||||||
|
Create Resource...
|
||||||
|
</a>
|
||||||
|
<span id="createObject">
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</metal:actions>
|
</metal:actions>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ $Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope import component
|
||||||
from zope.app import zapi
|
from zope.app import zapi
|
||||||
from zope.app.catalog.interfaces import ICatalog
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
from zope.app.dublincore.interfaces import ICMFDublinCore
|
from zope.app.dublincore.interfaces import ICMFDublinCore
|
||||||
|
@ -39,6 +40,7 @@ from loops.interfaces import IBaseResource, IDocument, IMediaAsset
|
||||||
from loops.browser.common import EditForm, BaseView
|
from loops.browser.common import EditForm, BaseView
|
||||||
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
|
from loops.browser.concept import ConceptRelationView, ConceptConfigureView
|
||||||
from loops.browser.node import NodeView
|
from loops.browser.node import NodeView
|
||||||
|
from loops.interfaces import ITypeConcept
|
||||||
|
|
||||||
renderingFactories = {
|
renderingFactories = {
|
||||||
'text/plain': 'zope.source.plaintext',
|
'text/plain': 'zope.source.plaintext',
|
||||||
|
@ -60,7 +62,8 @@ class ResourceEditForm(EditForm):
|
||||||
fields = FormFields(IBaseResource)
|
fields = FormFields(IBaseResource)
|
||||||
typeInterface = self.typeInterface
|
typeInterface = self.typeInterface
|
||||||
if typeInterface is not None:
|
if typeInterface is not None:
|
||||||
fields = FormFields(fields, typeInterface)
|
omit = [f for f in typeInterface if f in IBaseResource]
|
||||||
|
fields = FormFields(fields.omit(*omit), typeInterface)
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,6 +97,20 @@ class ResourceView(BaseView):
|
||||||
subMacro=self.template.macros['related'],
|
subMacro=self.template.macros['related'],
|
||||||
position=0, info=self)
|
position=0, info=self)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def view(self):
|
||||||
|
context = self.context
|
||||||
|
tp = IType(context).typeProvider
|
||||||
|
if tp:
|
||||||
|
viewName = ITypeConcept(tp).viewName
|
||||||
|
if viewName:
|
||||||
|
return component.queryMultiAdapter((context, self.request),
|
||||||
|
name=viewName)
|
||||||
|
if context.contentType.startswith('text/'):
|
||||||
|
# TODO: This should be controlled by resourceType
|
||||||
|
return DocumentView(context, self.request)
|
||||||
|
return self
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
data = self.context.data
|
data = self.context.data
|
||||||
response = self.request.response
|
response = self.request.response
|
||||||
|
@ -173,6 +190,9 @@ class DocumentView(ResourceView):
|
||||||
def macro(self):
|
def macro(self):
|
||||||
return ResourceView.template.macros['render']
|
return ResourceView.template.macros['render']
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def view(self): return self
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
""" Return the rendered content (data) of the context object.
|
""" Return the rendered content (data) of the context object.
|
||||||
"""
|
"""
|
||||||
|
@ -189,3 +209,16 @@ class DocumentView(ResourceView):
|
||||||
return (self.inlineEditingActive
|
return (self.inlineEditingActive
|
||||||
and self.context.contentType == 'text/html'
|
and self.context.contentType == 'text/html'
|
||||||
and canWrite(self.context, 'data'))
|
and canWrite(self.context, 'data'))
|
||||||
|
|
||||||
|
|
||||||
|
class NoteView(DocumentView):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def macro(self):
|
||||||
|
return ResourceView.template.macros['render_note']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def linkUrl(self):
|
||||||
|
ad = self.typeAdapter
|
||||||
|
return ad and ad.linkUrl or ''
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,16 @@
|
||||||
</metal:block>
|
</metal:block>
|
||||||
|
|
||||||
|
|
||||||
|
<metal:block define-macro="render_note">
|
||||||
|
<metal:render use-macro="item/template/macros/render" />
|
||||||
|
<div class="content-1" id="1.link">
|
||||||
|
<a href="."
|
||||||
|
tal:attributes="href item/linkUrl"
|
||||||
|
tal:condition="item/linkUrl">more...</a>
|
||||||
|
</div>
|
||||||
|
</metal:block>
|
||||||
|
|
||||||
|
|
||||||
<metal:block define-macro="image">
|
<metal:block define-macro="image">
|
||||||
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
||||||
<h3 tal:content="item/title">Title</h3>
|
<h3 tal:content="item/title">Title</h3>
|
||||||
|
|
|
@ -319,6 +319,14 @@
|
||||||
set_schema="loops.interfaces.IFile" />
|
set_schema="loops.interfaces.IFile" />
|
||||||
</class>
|
</class>
|
||||||
|
|
||||||
|
<adapter factory="loops.resource.NoteAdapter" trusted="True" />
|
||||||
|
<class class="loops.resource.NoteAdapter">
|
||||||
|
<require permission="zope.View"
|
||||||
|
interface="loops.interfaces.INote" />
|
||||||
|
<require permission="zope.ManageContent"
|
||||||
|
set_schema="loops.interfaces.INote" />
|
||||||
|
</class>
|
||||||
|
|
||||||
|
|
||||||
<adapter factory="loops.setup.SetupManager" />
|
<adapter factory="loops.setup.SetupManager" />
|
||||||
<adapter factory="loops.external.NodesLoader" />
|
<adapter factory="loops.external.NodesLoader" />
|
||||||
|
|
|
@ -532,7 +532,13 @@ class ITypeConcept(Interface):
|
||||||
source="loops.TypeInterfaceSource",
|
source="loops.TypeInterfaceSource",
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
# viewName = schema.TextLine()
|
viewName = schema.TextLine(
|
||||||
|
title=_(u'View name'),
|
||||||
|
description=_(u'Name of a special view be used for presenting '
|
||||||
|
'objects of this type.'),
|
||||||
|
default=u'',
|
||||||
|
required=False)
|
||||||
|
|
||||||
# storage = schema.Choice()
|
# storage = schema.Choice()
|
||||||
|
|
||||||
|
|
||||||
|
@ -554,13 +560,24 @@ class IImage(IResourceAdapter):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ITextDocument(IResourceAdapter):
|
class ITextDocument(IResourceAdapter, IDocumentSchema):
|
||||||
""" A resource containing some sort of plain text that may be rendered and
|
""" A resource containing some sort of plain text that may be rendered and
|
||||||
edited without necessarily involving a special external application
|
edited without necessarily involving a special external application
|
||||||
(like e.g. OpenOffice); typical content types are text/html, text/xml,
|
(like e.g. OpenOffice); typical content types are text/html, text/xml,
|
||||||
text/restructured, etc.
|
text/restructured, etc.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
class INote(ITextDocument):
|
||||||
|
""" Typically a short piece of text; in addition a note may contain
|
||||||
|
a URL linking it to more information.
|
||||||
|
"""
|
||||||
|
|
||||||
|
linkUrl = schema.TextLine(
|
||||||
|
title=_(u'Link URL'),
|
||||||
|
description=_(u'An (optional) link associated with this note'),
|
||||||
|
default=u'',
|
||||||
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
# view configurator stuff
|
# view configurator stuff
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,7 @@ from zope.security.proxy import removeSecurityProxy
|
||||||
|
|
||||||
from cybertools.organize.interfaces import IPerson as IBasePerson
|
from cybertools.organize.interfaces import IPerson as IBasePerson
|
||||||
from loops.organize.util import getPrincipalFolder, authPluginId
|
from loops.organize.util import getPrincipalFolder, authPluginId
|
||||||
|
from loops.util import _
|
||||||
_ = MessageFactory('zope')
|
|
||||||
|
|
||||||
ANNOTATION_KEY = 'loops.organize.person'
|
ANNOTATION_KEY = 'loops.organize.person'
|
||||||
|
|
||||||
|
|
12
resource.py
12
resource.py
|
@ -45,7 +45,7 @@ from cybertools.relation.interfaces import IRelatable
|
||||||
from cybertools.typology.interfaces import ITypeManager
|
from cybertools.typology.interfaces import ITypeManager
|
||||||
|
|
||||||
from interfaces import IBaseResource, IResource
|
from interfaces import IBaseResource, IResource
|
||||||
from interfaces import IFile
|
from interfaces import IFile, INote
|
||||||
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
||||||
from interfaces import IMediaAsset, IMediaAssetView
|
from interfaces import IMediaAsset, IMediaAssetView
|
||||||
from interfaces import IResourceManager, IResourceManagerContained
|
from interfaces import IResourceManager, IResourceManagerContained
|
||||||
|
@ -196,6 +196,16 @@ class FileAdapter(ResourceAdapterBase):
|
||||||
implements(IFile)
|
implements(IFile)
|
||||||
|
|
||||||
|
|
||||||
|
class NoteAdapter(ResourceAdapterBase):
|
||||||
|
""" A type adapter for providing note functionality for resources.
|
||||||
|
"""
|
||||||
|
|
||||||
|
implements(INote)
|
||||||
|
_schemas = list(INote) + list(IBaseResource)
|
||||||
|
|
||||||
|
#contentType = u'text/restructured'
|
||||||
|
|
||||||
|
|
||||||
class DocumentWriteFileAdapter(object):
|
class DocumentWriteFileAdapter(object):
|
||||||
|
|
||||||
implements(IWriteFile)
|
implements(IWriteFile)
|
||||||
|
|
|
@ -63,12 +63,6 @@ class Search(BaseView):
|
||||||
self.maxRowNum = n
|
self.maxRowNum = n
|
||||||
return n
|
return n
|
||||||
|
|
||||||
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]))
|
|
||||||
|
|
||||||
def initDojo(self):
|
def initDojo(self):
|
||||||
self.registerDojo()
|
self.registerDojo()
|
||||||
cm = self.controller.macros
|
cm = self.controller.macros
|
||||||
|
|
11
type.py
11
type.py
|
@ -33,7 +33,7 @@ from cybertools.typology.type import BaseType, TypeManager
|
||||||
from cybertools.typology.interfaces import ITypeManager
|
from cybertools.typology.interfaces import ITypeManager
|
||||||
from loops.interfaces import ILoopsObject, IConcept, IResource
|
from loops.interfaces import ILoopsObject, IConcept, IResource
|
||||||
from loops.interfaces import ITypeConcept
|
from loops.interfaces import ITypeConcept
|
||||||
from loops.interfaces import IResourceAdapter, IFile, IImage, ITextDocument
|
from loops.interfaces import IResourceAdapter, IFile, IImage, ITextDocument, INote
|
||||||
from loops.concept import Concept
|
from loops.concept import Concept
|
||||||
from loops.resource import Resource, Document, MediaAsset
|
from loops.resource import Resource, Document, MediaAsset
|
||||||
from loops.common import AdapterBase
|
from loops.common import AdapterBase
|
||||||
|
@ -43,7 +43,7 @@ class LoopsType(BaseType):
|
||||||
|
|
||||||
adapts(ILoopsObject)
|
adapts(ILoopsObject)
|
||||||
|
|
||||||
factoryMapping = dict(concept=Concept, resource=Resource)
|
factoryMapping = dict(concept=Concept, resource=Resource, document=Document)
|
||||||
containerMapping = dict(concept='concepts', resource='resources')
|
containerMapping = dict(concept='concepts', resource='resources')
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -83,6 +83,11 @@ class LoopsType(BaseType):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def factory(self):
|
def factory(self):
|
||||||
|
ti = self.typeInterface
|
||||||
|
#if ti is not None:
|
||||||
|
# fn = getattr(ti, 'factoryName', None)
|
||||||
|
# if fn:
|
||||||
|
# return self.factoryMapping.get(fn, Concept)
|
||||||
return self.factoryMapping.get(self.qualifiers[0], Concept)
|
return self.factoryMapping.get(self.qualifiers[0], Concept)
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -241,7 +246,7 @@ class TypeInterfaceSourceList(object):
|
||||||
|
|
||||||
implements(schema.interfaces.IIterableSource)
|
implements(schema.interfaces.IIterableSource)
|
||||||
|
|
||||||
typeInterfaces = (ITypeConcept, IFile, ITextDocument)
|
typeInterfaces = (ITypeConcept, IFile, ITextDocument, INote)
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
Loading…
Add table
Reference in a new issue