diff --git a/browser/common.py b/browser/common.py
index 5b94498..46dc3c5 100644
--- a/browser/common.py
+++ b/browser/common.py
@@ -561,6 +561,11 @@ class BaseView(GenericView, I18NView):
jsCall = 'dojo.require("dijit.form.ValidationTextBox");'
self.controller.macros.register('js-execute', jsCall, jsCall=jsCall)
+ def registerDojoTextarea(self):
+ self.registerDojo()
+ jsCall = 'dojo.require("dijit.form.SimpleTextarea");'
+ self.controller.macros.register('js-execute', jsCall, jsCall=jsCall)
+
def registerDojoEditor(self):
self.registerDojo()
jsCall = 'dojo.require("dijit.Editor");'
@@ -574,6 +579,7 @@ class BaseView(GenericView, I18NView):
jsCall = ('dojo.require("dijit.form.Form"); '
'dojo.require("dijit.form.DateTextBox"); '
'dojo.require("dijit.form.TimeTextBox"); '
+ 'dojo.require("dijit.form.SimpleTextarea"); '
'dojo.require("dijit.form.FilteringSelect"); '
'dojo.require("dojox.grid.DataGrid"); '
'dojo.require("dojo.data.ItemFileWriteStore"); '
diff --git a/browser/loops.css b/browser/loops.css
index 12aa8a9..593549d 100644
--- a/browser/loops.css
+++ b/browser/loops.css
@@ -40,6 +40,22 @@ blockquote ul {
margin-bottom: 0.3em;
}
+.dialog div.heading {
+ font-weight: bold;
+ font-size: 140%;
+ margin: 0.5em 0 0.3em 0;
+}
+
+.dialog label {
+ display: block;
+ font-weight: bold;
+ margin-top: 0.5em;
+}
+
+.dialog div.buttons {
+ margin-top: 0.5em;
+}
+
table.listing td {
white-space: normal;
vertical-align: middle;
diff --git a/browser/node.py b/browser/node.py
index 6246b24..139d942 100644
--- a/browser/node.py
+++ b/browser/node.py
@@ -60,7 +60,6 @@ from loops import util
from loops.util import _
from loops.browser.common import BaseView
from loops.browser.concept import ConceptView
-from loops.organize.comment.browser import comment_macros
from loops.organize.tracking import access
from loops.versioning.util import getVersion
@@ -485,19 +484,16 @@ class NodeView(BaseView):
# comments
+
@Lazy
def comment_macros(self):
+ from loops.organize.comment.browser import comment_macros
return comment_macros.macros
- # better: provide a ``comments`` view on the target object.
-
@Lazy
- def commentsAllowed(self):
- return False
- return True
-
- def addCommentUrlFor(self, target):
- return '#'
+ def comments(self):
+ return component.getMultiAdapter((self.context, self.request),
+ name='comments.html')
# inner HTML views
diff --git a/browser/resource_macros.pt b/browser/resource_macros.pt
index 40b69cb..66eac2e 100644
--- a/browser/resource_macros.pt
+++ b/browser/resource_macros.pt
@@ -15,6 +15,7 @@
The body
+
@@ -33,6 +34,7 @@
tal:define="linkText item/adapted/linkText|nothing"
tal:content="python: linkText or 'more...'">more...
+
@@ -45,6 +47,7 @@
tal:attributes="src
string:${view/url}/.target${view/targetId}/view?version=this" />
Description
+
@@ -80,8 +83,9 @@
tal:attributes="href string:$url/external_edit?version=this">
Open for editing
-
-
+
+
+
diff --git a/organize/comment/README.txt b/organize/comment/README.txt
new file mode 100644
index 0000000..4ba1f39
--- /dev/null
+++ b/organize/comment/README.txt
@@ -0,0 +1,80 @@
+===============================================================
+loops - Linked Objects for Organization and Processing Services
+===============================================================
+
+ ($Id$)
+
+Let's do some basic setup
+
+ >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
+ >>> site = placefulSetUp(True)
+ >>> from zope import component, interface
+
+and set up a simple loops site with a concept manager and some concepts
+(with all the type machinery, what in real life is done via standard
+ZCML setup):
+
+ >>> from loops.organize.setup import SetupManager
+ >>> component.provideAdapter(SetupManager, name='organize')
+
+ >>> from loops.tests.setup import TestSite
+ >>> t = TestSite(site)
+ >>> concepts, resources, views = t.setup()
+
+
+Comments - Managed by a Tracking Storage
+========================================
+
+ >>> loopsRoot = concepts.getLoopsRoot()
+ >>> records = loopsRoot.getRecordManager()
+
+More setup
+----------
+
+In order to be able to login and store favorites and other personal data
+we have to prepare our environment. We need some basic adapter registrations,
+and a pluggable authentication utility with a principal folder.
+
+ >>> from loops.organize.tests import setupObjectsForTesting
+ >>> setupData = setupObjectsForTesting(site, concepts)
+ >>> johnC = setupData.johnC
+
+We also assign a document as a target to the home node so that we are able
+to assign comments to this document.
+
+ >>> home = views['home']
+ >>> home.target = resources['d001.txt']
+
+Creating comments
+-----------------
+
+ >>> from loops.browser.node import NodeView
+ >>> from loops.tests.auth import TestRequest
+ >>> view = NodeView(home, TestRequest())
+
+ >>> from loops.organize.comment.browser import CreateComment
+
+ >>> input = dict(subject='My comment', text='Comment text')
+ >>> fc = CreateComment(view, TestRequest(form=input))
+ >>> fc.update()
+ False
+
+
+Viewing comments
+----------------
+
+ >>> from loops.organize.comment.browser import CommentsView, CommentView
+ >>> comments = CommentsView(home, TestRequest())
+
+ >>> items = list(comments.allItems())
+ >>> items
+ []
+ >>> item = items[0]
+ >>> item.subject, item.timeStamp, item.userTitle
+ ('My comment', '... ...', u'john')
+
+
+Fin de partie
+=============
+
+ >>> placefulTearDown()
diff --git a/organize/comment/base.py b/organize/comment/base.py
new file mode 100644
index 0000000..3ad956e
--- /dev/null
+++ b/organize/comment/base.py
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+"""
+Base classes for comments/discussions.
+
+$Id$
+"""
+
+from zope.component import adapts
+from zope.interface import implements
+
+from cybertools.tracking.btree import Track
+from cybertools.tracking.interfaces import ITrackingStorage
+from cybertools.tracking.comment.interfaces import IComment
+from loops import util
+
+
+class Comment(Track):
+
+ implements(IComment)
+
+ typeName = 'Comment'
+
+ contentType = 'text/restructured'
+
diff --git a/organize/comment/browser.py b/organize/comment/browser.py
index eb23523..8d8daa5 100644
--- a/organize/comment/browser.py
+++ b/organize/comment/browser.py
@@ -27,24 +27,104 @@ from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
from cybertools.browser.action import actions
+from cybertools.tracking.btree import TrackingStorage
from loops.browser.action import DialogAction
from loops.browser.common import BaseView
+from loops.browser.form import ObjectForm, EditObject
+from loops.browser.node import NodeView
+from loops.organize.comment.base import Comment
+from loops.organize.party import getPersonForUser
+from loops.organize.tracking.browser import BaseTrackView
+from loops.setup import addObject
+from loops import util
from loops.util import _
comment_macros = ViewPageTemplateFile('comment_macros.pt')
-actions.register('addComment', 'button', DialogAction,
- title=_(u'Add Comment'),
- description=_(u'Add a comment to this object.'),
- viewName='create_comment.html',
- dialogName='createComment',
- innerForm='inner_comment_form.html',
- #prerequisites=['registerDojoDateWidget'],
-)
+
+class CommentsView(NodeView):
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ @Lazy
+ def allowed(self):
+ return False
+ return True
+
+ @Lazy
+ def addUrl(self):
+ return '%s/create_comment.html' % self.nodeView.getUrlForTarget(self.context)
+
+ @Lazy
+ def addOnClick(self):
+ self.registerDojoFormAll()
+ return "objectDialog('createComment', '%s'); return false;" % self.addUrl
+
+ def allItems(self):
+ result = []
+ rm = self.loopsRoot.getRecordManager()
+ ts = rm.get('comments')
+ target = self.virtualTargetObject
+ if None in (ts, target):
+ return result
+ for tr in reversed(list(ts.query(taskId=util.getUidForObject(target)))):
+ view = CommentView(tr, self.request)
+ view.parent = self
+ result.append(view)
+ return result
-class CommentsView(BaseView):
+class CommentView(BaseTrackView):
- pass
+ @Lazy
+ def subject(self):
+ return self.context.data['subject']
+ @Lazy
+ def text(self):
+ return self.parent.renderText(self.context.data['text'],
+ self.context.contentType)
+
+
+class CreateCommentForm(ObjectForm):
+
+ template = comment_macros
+
+ @Lazy
+ def macro(self):
+ return self.template.macros['create_comment']
+
+
+class CreateComment(EditObject):
+
+ @Lazy
+ def personId(self):
+ p = getPersonForUser(self.context, self.request)
+ if p is not None:
+ return util.getUidForObject(p)
+ return self.request.principal.id
+
+ @Lazy
+ def object(self):
+ return self.view.virtualTargetObject
+
+ def update(self):
+ form = self.request.form
+ subject = form.get('subject')
+ text = form.get('text')
+ if not subject or not text or self.personId is None or self.object is None:
+ return True
+ #contentType = form.get('contentType') or 'text/restructured'
+ rm = self.view.loopsRoot.getRecordManager()
+ ts = rm.get('comments')
+ if ts is None:
+ ts = addObject(rm, TrackingStorage, 'comments', trackFactory=Comment)
+ uid = util.getUidForObject(self.object)
+ ts.saveUserTrack(uid, 0, self.personId, dict(
+ subject=subject, text=text))
+ url = self.view.virtualTargetUrl + '?version=this'
+ self.request.response.redirect(url)
+ return False
diff --git a/organize/comment/comment_macros.pt b/organize/comment/comment_macros.pt
index 240e870..ceceae4 100644
--- a/organize/comment/comment_macros.pt
+++ b/organize/comment/comment_macros.pt
@@ -3,32 +3,67 @@
+ tal:define="comments nocall:view/comments"
+ tal:condition="comments/allowed">
Comments
-
-
-
+
+
-
+
+
-
Resource Title