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
|
||||
>>> site = placefulSetUp(True)
|
||||
|
||||
>>> from zope import component
|
||||
>>> from zope.app import zapi
|
||||
>>> from zope.app.tests import ztapi
|
||||
>>> from zope.interface import Interface
|
||||
|
@ -122,7 +123,7 @@ type manager.
|
|||
|
||||
>>> from cybertools.typology.interfaces import ITypeManager
|
||||
>>> from loops.interfaces import ILoopsObject
|
||||
>>> from loops.type import LoopsTypeManager
|
||||
>>> from loops.type import LoopsTypeManager, LoopsType
|
||||
>>> ztapi.provideAdapter(ILoopsObject, ITypeManager, LoopsTypeManager)
|
||||
|
||||
>>> from loops.concept import ConceptTypeSourceList
|
||||
|
@ -545,6 +546,8 @@ and of a lot of other stuff needed for the rendering machine.
|
|||
... with=(IBrowserRequest,))
|
||||
|
||||
>>> m112.target = doc1
|
||||
|
||||
>>> component.provideAdapter(LoopsType)
|
||||
>>> view = NodeView(m112, TestRequest())
|
||||
>>> view.renderTarget()
|
||||
u''
|
||||
|
|
|
@ -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.type import ITypeConcept
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
|
||||
|
@ -135,18 +136,39 @@ class BaseView(GenericView):
|
|||
def value(self):
|
||||
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
|
||||
def typeTitle(self):
|
||||
type = IType(self.context)
|
||||
type = self.type
|
||||
return type is not None and type.title or None
|
||||
|
||||
@Lazy
|
||||
def typeUrl(self):
|
||||
type = IType(self.context)
|
||||
if type is not None:
|
||||
provider = type.typeProvider
|
||||
if provider is not None:
|
||||
return zapi.absoluteURL(provider, self.request)
|
||||
provider = self.typeProvider
|
||||
if provider is not None:
|
||||
return zapi.absoluteURL(provider, self.request)
|
||||
return None
|
||||
|
||||
def viewIterator(self, objs):
|
||||
|
@ -161,6 +183,12 @@ class BaseView(GenericView):
|
|||
for t in ITypeManager(self.context).types])
|
||||
+ [('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
|
||||
def uniqueId(self):
|
||||
return zapi.getUtility(IRelationRegistry).getUniqueIdForObject(self.context)
|
||||
|
|
|
@ -324,6 +324,15 @@
|
|||
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 -->
|
||||
|
||||
<!--<editform
|
||||
|
@ -548,6 +557,15 @@
|
|||
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 -->
|
||||
|
||||
<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;
|
||||
}
|
||||
|
||||
/* 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'], ]
|
||||
}
|
||||
}*/
|
||||
|
||||
function submitReplacing(targetId, formId, actionUrl) {
|
||||
dojo.io.updateNode(targetId, {
|
||||
|
@ -27,17 +27,21 @@ function submitReplacing(targetId, formId, actionUrl) {
|
|||
}
|
||||
|
||||
function inlineEdit(id, saveUrl) {
|
||||
var iconNode = dojo.byId("inlineedit_icon");
|
||||
iconNode.style.visibility = "hidden";
|
||||
var editor = dojo.widget.fromScript("Editor",
|
||||
{items: ["save", "|", "formatblock", "|",
|
||||
"insertunorderedlist", "insertorderedlist", "|",
|
||||
"bold", "italic", "|", "createLink", "insertimage"],
|
||||
//dojo.require('dojo.widget.Editor');
|
||||
var iconNode = dojo.byId('inlineedit_icon');
|
||||
iconNode.style.visibility = 'hidden';
|
||||
var editor = dojo.widget.fromScript('Editor',
|
||||
{items: ['save', '|', 'formatblock', '|',
|
||||
'insertunorderedlist', 'insertorderedlist', '|',
|
||||
'bold', 'italic', '|', 'createLink', 'insertimage'],
|
||||
saveUrl: saveUrl,
|
||||
closeOnSave: true,
|
||||
onSave: function(){
|
||||
htmlEditing: true,
|
||||
onSave: function() {
|
||||
this.disableToolbar(true);
|
||||
iconNode.style.visibility = "visible";}
|
||||
iconNode.style.visibility = 'visible';
|
||||
//window.location.reload();
|
||||
}
|
||||
}, dojo.byId(id));
|
||||
return false;
|
||||
}
|
||||
|
@ -50,3 +54,19 @@ function setConceptTypeForComboBox(typeId, cbId) {
|
|||
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$
|
||||
"""
|
||||
|
||||
from zope import component, interface
|
||||
from zope import component, interface, schema
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.app import zapi
|
||||
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.dottedname.resolve import resolve
|
||||
from zope.event import notify
|
||||
from zope.formlib.form import Form, FormFields
|
||||
from zope.formlib.namedtemplate import NamedTemplate
|
||||
from zope.proxy import removeAllProxies
|
||||
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.resource import MediaAsset
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
from loops.browser.common import BaseView
|
||||
from loops.browser.concept import ConceptView
|
||||
|
||||
|
@ -70,16 +72,16 @@ class NodeView(BaseView):
|
|||
resourceName='loops.css', media='all')
|
||||
cm.register('js', 'loops.js', resourceName='loops.js')
|
||||
cm.register('portlet_left', 'navigation', title='Navigation',
|
||||
subMacro=self.template.macros['menu'])
|
||||
subMacro=self.template.macros['menu'])
|
||||
if not IUnauthenticatedPrincipal.providedBy(self.request.principal):
|
||||
cm.register('portlet_right', 'clipboard', title='Clipboard',
|
||||
subMacro=self.template.macros['clipboard'])
|
||||
subMacro=self.template.macros['clipboard'])
|
||||
# this belongs to loops.organize; how to register portlets
|
||||
# from sub- (other) packages?
|
||||
# see controller / configurator: use multiple configurators;
|
||||
# register additional configurators (adapters) from within package.
|
||||
cm.register('portlet_right', 'worklist', title='Worklist',
|
||||
subMacro=self.template.macros['worklist'])
|
||||
cm.register('portlet_right', 'actions', title='Actions',
|
||||
subMacro=self.template.macros['actions'])
|
||||
|
||||
@Lazy
|
||||
def view(self):
|
||||
|
@ -156,6 +158,7 @@ class NodeView(BaseView):
|
|||
|
||||
def renderTarget(self):
|
||||
target = self.target
|
||||
#targetAdapter = target.typeAdapter
|
||||
return target is not None and target.render() or u''
|
||||
|
||||
@Lazy
|
||||
|
@ -164,9 +167,10 @@ class NodeView(BaseView):
|
|||
|
||||
@Lazy
|
||||
def bodyMacro(self):
|
||||
# TODO: replace by: return self.target.macroName
|
||||
# TODO: replace by something like: return self.target.macroName
|
||||
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'
|
||||
if IConcept.providedBy(target):
|
||||
return 'conceptbody'
|
||||
|
@ -295,6 +299,12 @@ class NodeView(BaseView):
|
|||
cm.register('js-execute', jsCall, jsCall=jsCall)
|
||||
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
|
||||
|
||||
|
@ -314,10 +324,43 @@ class InlineEdit(NodeView):
|
|||
|
||||
def save(self):
|
||||
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')))
|
||||
|
||||
|
||||
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
|
||||
|
||||
class SpecialNodeView(NodeView):
|
||||
|
|
|
@ -194,12 +194,20 @@
|
|||
<!-- portlets -->
|
||||
|
||||
<metal:actions define-macro="clipboard">
|
||||
<div class="menu-2">loops Development</div>
|
||||
<div class="menu-2">loops Development</div>
|
||||
</metal:actions>
|
||||
|
||||
|
||||
<metal:actions define-macro="worklist">
|
||||
<div class="menu-2">Create Resource...</div>
|
||||
<metal:actions define-macro="actions">
|
||||
<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>
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ $Id$
|
|||
"""
|
||||
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
from zope.app import zapi
|
||||
from zope.app.catalog.interfaces import ICatalog
|
||||
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.concept import ConceptRelationView, ConceptConfigureView
|
||||
from loops.browser.node import NodeView
|
||||
from loops.interfaces import ITypeConcept
|
||||
|
||||
renderingFactories = {
|
||||
'text/plain': 'zope.source.plaintext',
|
||||
|
@ -60,7 +62,8 @@ class ResourceEditForm(EditForm):
|
|||
fields = FormFields(IBaseResource)
|
||||
typeInterface = self.typeInterface
|
||||
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
|
||||
|
||||
|
||||
|
@ -94,6 +97,20 @@ class ResourceView(BaseView):
|
|||
subMacro=self.template.macros['related'],
|
||||
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):
|
||||
data = self.context.data
|
||||
response = self.request.response
|
||||
|
@ -173,6 +190,9 @@ class DocumentView(ResourceView):
|
|||
def macro(self):
|
||||
return ResourceView.template.macros['render']
|
||||
|
||||
@Lazy
|
||||
def view(self): return self
|
||||
|
||||
def render(self):
|
||||
""" Return the rendered content (data) of the context object.
|
||||
"""
|
||||
|
@ -189,3 +209,16 @@ class DocumentView(ResourceView):
|
|||
return (self.inlineEditingActive
|
||||
and self.context.contentType == 'text/html'
|
||||
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 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">
|
||||
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
||||
<h3 tal:content="item/title">Title</h3>
|
||||
|
|
|
@ -319,6 +319,14 @@
|
|||
set_schema="loops.interfaces.IFile" />
|
||||
</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.external.NodesLoader" />
|
||||
|
|
|
@ -532,7 +532,13 @@ class ITypeConcept(Interface):
|
|||
source="loops.TypeInterfaceSource",
|
||||
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()
|
||||
|
||||
|
||||
|
@ -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
|
||||
edited without necessarily involving a special external application
|
||||
(like e.g. OpenOffice); typical content types are text/html, text/xml,
|
||||
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
|
||||
|
||||
|
|
|
@ -32,8 +32,7 @@ from zope.security.proxy import removeSecurityProxy
|
|||
|
||||
from cybertools.organize.interfaces import IPerson as IBasePerson
|
||||
from loops.organize.util import getPrincipalFolder, authPluginId
|
||||
|
||||
_ = MessageFactory('zope')
|
||||
from loops.util import _
|
||||
|
||||
ANNOTATION_KEY = 'loops.organize.person'
|
||||
|
||||
|
@ -49,7 +48,7 @@ def raiseValidationError(info):
|
|||
|
||||
|
||||
class UserId(schema.TextLine):
|
||||
|
||||
|
||||
def _validate(self, userId):
|
||||
from loops.organize.party import getPersonForUser
|
||||
if not userId:
|
||||
|
|
12
resource.py
12
resource.py
|
@ -45,7 +45,7 @@ from cybertools.relation.interfaces import IRelatable
|
|||
from cybertools.typology.interfaces import ITypeManager
|
||||
|
||||
from interfaces import IBaseResource, IResource
|
||||
from interfaces import IFile
|
||||
from interfaces import IFile, INote
|
||||
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
||||
from interfaces import IMediaAsset, IMediaAssetView
|
||||
from interfaces import IResourceManager, IResourceManagerContained
|
||||
|
@ -196,6 +196,16 @@ class FileAdapter(ResourceAdapterBase):
|
|||
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):
|
||||
|
||||
implements(IWriteFile)
|
||||
|
|
|
@ -63,12 +63,6 @@ class Search(BaseView):
|
|||
self.maxRowNum = 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):
|
||||
self.registerDojo()
|
||||
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 loops.interfaces import ILoopsObject, IConcept, IResource
|
||||
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.resource import Resource, Document, MediaAsset
|
||||
from loops.common import AdapterBase
|
||||
|
@ -43,7 +43,7 @@ class LoopsType(BaseType):
|
|||
|
||||
adapts(ILoopsObject)
|
||||
|
||||
factoryMapping = dict(concept=Concept, resource=Resource)
|
||||
factoryMapping = dict(concept=Concept, resource=Resource, document=Document)
|
||||
containerMapping = dict(concept='concepts', resource='resources')
|
||||
|
||||
@Lazy
|
||||
|
@ -83,6 +83,11 @@ class LoopsType(BaseType):
|
|||
|
||||
@Lazy
|
||||
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)
|
||||
|
||||
@Lazy
|
||||
|
@ -241,7 +246,7 @@ class TypeInterfaceSourceList(object):
|
|||
|
||||
implements(schema.interfaces.IIterableSource)
|
||||
|
||||
typeInterfaces = (ITypeConcept, IFile, ITextDocument)
|
||||
typeInterfaces = (ITypeConcept, IFile, ITextDocument, INote)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
|
Loading…
Add table
Reference in a new issue