delete docs/html.

svn path=/plone.app.discussion/trunk/; revision=36997
This commit is contained in:
Timo Stollenwerk 2010-06-04 11:14:35 +00:00
parent bca29657b5
commit adbe6c7db7
24 changed files with 0 additions and 3220 deletions

View File

@ -1,4 +0,0 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: ad04f153429ceaff21b3a3a4a57a98f6
tags: fbb0d17656682115ca4d033fb2f83ba1

View File

@ -1,25 +0,0 @@
API/Interfaces
--------------
The conversation and replies adapters.
The conversation is responsible for storing all comments. It provides a
dict-like API for accessing comments, where keys are integers and values
are IComment objects. It also provides features for finding comments quickly.
The IReplies adapter provides an API for finding and manipulating the comments
directly in reply to a particular comment (implemented by the CommentReplies
adpater) or at the top level of the conversation (implemented by the
ConversationReplies adapter).
.. autointerface:: plone.app.discussion.interfaces.IConversation
:members:
.. autointerface:: plone.app.discussion.interfaces.IReplies
:members:
.. autointerface:: plone.app.discussion.interfaces.IComment
:members:

View File

@ -1,59 +0,0 @@
========================
Architectural Principles
========================
This document outlines architectural principles used in the design of
plone.app.discussion.
**Discussion items have a portal_type**
This makes it easier to search for them and manage them using existing
CMF and Plone UI constructs.
**Discussion items are cataloged**
It is possible to search for discussion items like any other type of
content.
**Discussion items are subject to workflow and permission**
Moderation, anonymous commenting, and auto approve/reject should be
handled using workflow states, automatic and manual transitions, and
permissions.
**Discussion items are light weight objects**
Discussion item objects are as light weight as possible. Ideally, a
discussion item should be as lightweight as a catalog brain. This may mean
that we forego convenience base classes and re-implement certain interfaces.
Comments should not provide the full set of dublin core metadata, though
custom indexers can be used to provide values for standard catalog indexes.
**Optimise for retrival speed**
HTML filtering and other processing should happen on save, not on render,
to make rendering quick.
**Settings are stored using plone.registry**
Any global setting should be stored in plone.registry records.
**Forms are constructed using extensible z3c.form forms**
This allows plugins (such as spam protection algorithms) to provide
additional validation. It also allows integrators to write add-ons that add
new fields to the comment form.
**Discussion items are stored in a BTree container**
This allows faster lookup and manipulation.
**Discussion items are accessed using a dict-like interface**
This makes iteration and manipulation more natural. Even if comments are
not stored threaded, the dict interface should act as if they are, i.e.
calling items() on a comment should return the replies to that comment
(in order).
**Discussion items are retrieved in reverse creation date order**
Discussion items do not need to support explicit ordering. They should
always be retrieved in reverse creation date order (most recent for).
They can be stored with keys so that this is always true.
**Discussion items do not need readable ids**
Ids can be based on the creation date.
**Discussion items send events**
The usual zope.lifecycleevent and zope.container events are fired when
discussion items are added, removed, or modified.

View File

@ -1,30 +0,0 @@
===========================
Captcha Plugin Architecture
===========================
This document contains design notes for the plone.app.discussion Captcha plugin
architecture. It also explains how to write your own Captcha plugin (???).
Currently there are two plugins that work with plone.app.discussion:
1) plone.formwidget.captcha
2) plone.formwidget.recaptcha
1) Captcha plugin must provide the feature "plone.app.discussion-captcha":
Add this to your configure.zcml::
<configure ...
xmlns:meta="http://namespaces.zope.org/meta">
<!-- Declare that plone.formwidget.captcha provides a Captcha field that
can be used by plone.app.discussion to add a Captcha field to comment
forms. -->
<meta:provides feature="plone.app.discussion-captcha" />
...
</configure>
For examples have a look at plone.formwidget.captcha
https://svn.plone.org/svn/plone/plone.formwidget.captcha/trunk/plone/formwidget/captcha/configure.zcml

View File

@ -1,167 +0,0 @@
============
Design Notes
============
This document contains design notes for plone.app.discussion.
Storage and traversal
---------------------
For each content item, there is a Conversation object stored in annotations.
This can be traversed to via the ++conversation++ namespace, but also fetched
via an adapter lookup to IConversation.
The conversation stores all comments related to a content object. Each
comment has an integer id (also representable as a string, to act as an OFS
id and allow traversal). Hence, traversing to obj/++conversation++/123 retrieves
the comment with id 123.
Comments ids are assigned in order, so a comment with id N was posted before
a comment with id N + 1. However, it is not guaranteed that ids will be
incremental. Ids must be positive integers - 0 or negative numbers are not
allowed.
Threading information is stored in the conversation: we keep track of the
set of children and the parent if any comment. Top-level comments have a
parent id of 0. This information is managed by the conversation class when
comments are manipulated using a dict-like API.
Note that the __parent__/acquisition parent of an IComment is the
IConversation, and the __parent__/acquisition parent of an IConversation is
the content object.
Events
------
Manipulating the IConversation object should fire the usual IObjectAddedEvent
and IObjectRemovedEvent events. The UI may further fire IObjectCreatedEvent
and IObjectModifiedEvent for comments.
Factories
---------
Comments should always be created via the 'Discussion Item' IFactory utility.
Conversations should always be obtained via the IConversation adapter (even
the ++conversation++ namespace should use this). This makes it possible to
replace conversations and comments transparently.
The Comment class
-----------------
The inheritance tree for DiscussionItem is shown below. Classes we want to
mix in and interface we want to implement in the Comment class are marked
with [x].
[ ] DiscussionItem
[ ] Document
[ ] PortalContent = [ ] IContentish
[ ] DynamicType = [ ] IDynamicType
[ ] CMFCatalogAware = [ ] <no interface>
[ ] SimpleItem = [ ] ISimpleItem
[ ] Item [ ]
[?] Base = [ ] <no interface>
[ ] Resource = [ ] <no interface>
[ ] CopySource = [ ] ICopySource
[ ] Tabs = [ ] <no interface>
[x] Traversable = [ ] ITraversable
[ ] Element = [ ] <no interface>
[x] Owned = [ ] IOwned
[ ] UndoSupport = [ ] IUndoSupport
[ ] Persistent [ ]
[ ] Implicit [ ]
[x] RoleManager = [ ] IRoleManager
[ ] RoleManager = [ ] IPermissionMappingSupport
[ ] DefaultDublinCoreImpl = [ ] IDublinCore
[ ] ICatalogableDublinCore
[ ] IMutableDublinCore
[ ] PropertyManager = [ ] IPropertyManager
Thus, we want:
* Traversable, to get absolute_url() and friends
- this requires a good acquisition chain at all times
* Acquisition.Explicit, to support acquisition
- we do not want implicit acquisition
* Owned, to be able to track ownership
* RoleManager, to support permissions and local roles
We also want to use a number of custom indexers for most of the standard
metadata such as creator, effective date etc.
Finally, we'll need event handlers to perform the actual indexing.
Discussion settings
-------------------
Discussion can be enabled per-type and per-instance, via values in the FTI
(allow_discussion) and on the object. These will remain unchanged. The
IConversation object's 'enabled' property should consult these.
Global settings should be managed using plone.registry. A control panel
can be generated from this as well, using the helper class in
plone.app.registry.
Note that some settings, notably those to do with permissions and workflow,
will need to be wired up as custom form fields with custom data mangers
or similar.
Workflow and permissions
------------------------
Where possible, we should use existing permissions:
* View
* Reply to Item
* Modify Portal Content
* Request Review
In addition, we'll need a 'Moderator' role and a moderation permission,
* Moderate comment
* Bypass moderation
To control whether Anonymous can post comments, we manage the 'Reply to Item'
permission. To control whether moderation is required for various roles, we
could manage the 'Bypass moderation' permission.
These could work in a workflow like this:
* --> [posted] -- {publish} --> [published]--> *
| ^
| |
+----- {auto-publish} -----+
| |
+----- {auto-moderate} ----+
The 'posted' state is the initial state. 'published' is the state where the
comment is visible to non-reviewers.
The 'publish' transition would be protected by the 'Moderate comment'
permission. We could have states and transition for 'rejected', etc, but it
is probably just as good to delete comments that are rejected.
The 'auto-publish' transition would be an automatic transition protected by
the 'Bypass moderation' permission.
The 'auto-moderate' transition would be another automatic transition protected
by an expression (e.g. calling a view) that returns True if the user is on
an auto-moderation 'white-list', e.g. by email address or username.
Forms and UI
------------
The basic commenting display/reply form is placed in a viewlet.
The reply form is dynamically created right under the comment when the user hits
the reply button. To do so, we copy the standard comment form with a jQuery
function. This function sets the form's hidden in_reply_to field to the id of
the comment the user wants to reply to. This also makes is possible to use
z3c.form validation for the reply forms, because we can uniquely identify the
a reply form request and return the reply form with validation errors.
Since we rely on JavaScript for the reply form creation, the reply button is
removed for nonJavaScript enabled browsers.
The comment form uses z3c.form and plone.z3cform's ExtensibleForm support. This
makes it possible to plug in additional fields declaratively, e.g. to include
SPAM protection.

View File

@ -1,29 +0,0 @@
.. plone.app.discussion documentation master file, created by
sphinx-quickstart on Thu Mar 18 10:17:15 2010.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to plone.app.discussion's documentation!
================================================
.. module:`plone.app.discussion`
Contents:
.. toctree::
:maxdepth: 2
architecture.txt
design.txt
api.txt
.. include:: ../../CHANGES.txt
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,417 +0,0 @@
/**
* Sphinx stylesheet -- basic theme
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
img {
border: 0;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
/* -- general body styles --------------------------------------------------- */
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 0;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
/* -- other body styles ----------------------------------------------------- */
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlight {
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.refcount {
color: #060;
}
.optional {
font-size: 1.3em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
tt.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
tt.descclassname {
background-color: transparent;
}
tt.xref, a tt {
background-color: transparent;
font-weight: bold;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
background-color: transparent;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

View File

@ -1,218 +0,0 @@
/**
* Sphinx stylesheet -- default theme
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: sans-serif;
font-size: 100%;
background-color: #11303d;
color: #000;
margin: 0;
padding: 0;
}
div.document {
background-color: #1c4e63;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
div.body {
background-color: #ffffff;
color: #000000;
padding: 0 20px 30px 20px;
}
div.footer {
color: #ffffff;
width: 100%;
padding: 9px 0 9px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #ffffff;
text-decoration: underline;
}
div.related {
background-color: #133f52;
line-height: 30px;
color: #ffffff;
}
div.related a {
color: #ffffff;
}
div.sphinxsidebar {
}
div.sphinxsidebar h3 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.4em;
font-weight: normal;
margin: 0;
padding: 0;
}
div.sphinxsidebar h3 a {
color: #ffffff;
}
div.sphinxsidebar h4 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.3em;
font-weight: normal;
margin: 5px 0 0 0;
padding: 0;
}
div.sphinxsidebar p {
color: #ffffff;
}
div.sphinxsidebar p.topless {
margin: 5px 10px 10px 10px;
}
div.sphinxsidebar ul {
margin: 10px;
padding: 0;
color: #ffffff;
}
div.sphinxsidebar a {
color: #98dbcc;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
/* -- body styles ----------------------------------------------------------- */
a {
color: #355f7c;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
div.body p, div.body dd, div.body li {
text-align: justify;
line-height: 130%;
}
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: 'Trebuchet MS', sans-serif;
background-color: #f2f2f2;
font-weight: normal;
color: #20435c;
border-bottom: 1px solid #ccc;
margin: 20px -20px 10px -20px;
padding: 3px 0 3px 10px;
}
div.body h1 { margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 160%; }
div.body h3 { font-size: 140%; }
div.body h4 { font-size: 120%; }
div.body h5 { font-size: 110%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li {
text-align: justify;
line-height: 130%;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 5px;
background-color: #eeffcc;
color: #333333;
line-height: 120%;
border: 1px solid #ac9;
border-left: none;
border-right: none;
}
tt {
background-color: #ecf0f3;
padding: 0 1px 0 1px;
font-size: 0.95em;
}
.warning tt {
background: #efc2c2;
}
.note tt {
background: #d6d6d6;
}

View File

@ -1,232 +0,0 @@
/// XXX: make it cross browser
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
*/
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
"group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {}
}
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
}
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
}
/**
* small function to check if an array contains
* a given item.
*/
jQuery.contains = function(arr, item) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == item)
return true;
}
return false;
}
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery.className.has(node.parentNode, className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this)
});
}
}
return this.each(function() {
highlight(this);
});
}
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initModIndex();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can savely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated == 'undefined')
return string;
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlight');
});
}, 10);
$('<li class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
.appendTo($('.sidebar .this-page-menu'));
}
},
/**
* init the modindex toggle buttons
*/
initModIndex : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
console.log($('tr.cg-' + idnum).toggle());
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
$('span.highlight').removeClass('highlight');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

View File

@ -1,61 +0,0 @@
.hll { background-color: #ffffcc }
.c { color: #408090; font-style: italic } /* Comment */
.err { border: 1px solid #FF0000 } /* Error */
.k { color: #007020; font-weight: bold } /* Keyword */
.o { color: #666666 } /* Operator */
.cm { color: #408090; font-style: italic } /* Comment.Multiline */
.cp { color: #007020 } /* Comment.Preproc */
.c1 { color: #408090; font-style: italic } /* Comment.Single */
.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.gd { color: #A00000 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gr { color: #FF0000 } /* Generic.Error */
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi { color: #00A000 } /* Generic.Inserted */
.go { color: #303030 } /* Generic.Output */
.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.gt { color: #0040D0 } /* Generic.Traceback */
.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.kp { color: #007020 } /* Keyword.Pseudo */
.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.kt { color: #902000 } /* Keyword.Type */
.m { color: #208050 } /* Literal.Number */
.s { color: #4070a0 } /* Literal.String */
.na { color: #4070a0 } /* Name.Attribute */
.nb { color: #007020 } /* Name.Builtin */
.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.no { color: #60add5 } /* Name.Constant */
.nd { color: #555555; font-weight: bold } /* Name.Decorator */
.ni { color: #d55537; font-weight: bold } /* Name.Entity */
.ne { color: #007020 } /* Name.Exception */
.nf { color: #06287e } /* Name.Function */
.nl { color: #002070; font-weight: bold } /* Name.Label */
.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.nt { color: #062873; font-weight: bold } /* Name.Tag */
.nv { color: #bb60d5 } /* Name.Variable */
.ow { color: #007020; font-weight: bold } /* Operator.Word */
.w { color: #bbbbbb } /* Text.Whitespace */
.mf { color: #208050 } /* Literal.Number.Float */
.mh { color: #208050 } /* Literal.Number.Hex */
.mi { color: #208050 } /* Literal.Number.Integer */
.mo { color: #208050 } /* Literal.Number.Oct */
.sb { color: #4070a0 } /* Literal.String.Backtick */
.sc { color: #4070a0 } /* Literal.String.Char */
.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.s2 { color: #4070a0 } /* Literal.String.Double */
.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.sh { color: #4070a0 } /* Literal.String.Heredoc */
.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.sx { color: #c65d09 } /* Literal.String.Other */
.sr { color: #235388 } /* Literal.String.Regex */
.s1 { color: #4070a0 } /* Literal.String.Single */
.ss { color: #517918 } /* Literal.String.Symbol */
.bp { color: #007020 } /* Name.Builtin.Pseudo */
.vc { color: #bb60d5 } /* Name.Variable.Class */
.vg { color: #bb60d5 } /* Name.Variable.Global */
.vi { color: #bb60d5 } /* Name.Variable.Instance */
.il { color: #208050 } /* Literal.Number.Integer.Long */

View File

@ -1,467 +0,0 @@
/**
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurance, the
* latter for highlighting it.
*/
jQuery.makeSearchSummary = function(text, keywords, hlwords) {
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
});
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') +
$.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlight');
});
return rv;
}
/**
* Porter Stemmer
*/
var PorterStemmer = function() {
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
/**
* Search Module
*/
var Search = {
_index : null,
_queued_query : null,
_pulse_status : -1,
init : function() {
var params = $.getQueryParameters();
if (params.q) {
var query = params.q[0];
$('input[name="q"]')[0].value = query;
this.performSearch(query);
}
},
/**
* Sets the index
*/
setIndex : function(index) {
var q;
this._index = index;
if ((q = this._queued_query) !== null) {
this._queued_query = null;
Search.query(q);
}
},
hasIndex : function() {
return this._index !== null;
},
deferQuery : function(query) {
this._queued_query = query;
},
stopPulse : function() {
this._pulse_status = 0;
},
startPulse : function() {
if (this._pulse_status >= 0)
return;
function pulse() {
Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = '';
for (var i = 0; i < Search._pulse_status; i++)
dotString += '.';
Search.dots.text(dotString);
if (Search._pulse_status > -1)
window.setTimeout(pulse, 500);
};
pulse();
},
/**
* perform a search for something
*/
performSearch : function(query) {
// create the required interface elements
this.out = $('#search-results');
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
this.dots = $('<span></span>').appendTo(this.title);
this.status = $('<p style="display: none"></p>').appendTo(this.out);
this.output = $('<ul class="search"/>').appendTo(this.out);
$('#search-progress').text(_('Preparing search...'));
this.startPulse();
// index already loaded, the browser was quick!
if (this.hasIndex())
this.query(query);
else
this.deferQuery(query);
},
query : function(query) {
// stem the searchterms and add them to the
// correct list
var stemmer = new PorterStemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = query.split(/\s+/);
var object = (tmp.length == 1) ? tmp[0].toLowerCase() : null;
for (var i = 0; i < tmp.length; i++) {
// stem the word
var word = stemmer.stemWord(tmp[i]).toLowerCase();
// select the correct list
if (word[0] == '-') {
var toAppend = excluded;
word = word.substr(1);
}
else {
var toAppend = searchterms;
hlterms.push(tmp[i].toLowerCase());
}
// only add if not already in the list
if (!$.contains(toAppend, word))
toAppend.push(word);
};
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
console.debug('SEARCH: searching for:');
console.info('required: ', searchterms);
console.info('excluded: ', excluded);
// prepare search
var filenames = this._index.filenames;
var titles = this._index.titles;
var terms = this._index.terms;
var descrefs = this._index.descrefs;
var modules = this._index.modules;
var desctypes = this._index.desctypes;
var fileMap = {};
var files = null;
var objectResults = [];
var regularResults = [];
$('#search-progress').empty();
// lookup as object
if (object != null) {
for (var module in modules) {
if (module.indexOf(object) > -1) {
fn = modules[module];
descr = _('module, in ') + titles[fn];
objectResults.push([filenames[fn], module, '#module-'+module, descr]);
}
}
for (var prefix in descrefs) {
for (var name in descrefs[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
match = descrefs[prefix][name];
descr = desctypes[match[1]] + _(', in ') + titles[match[0]];
objectResults.push([filenames[match[0]], fullname, '#'+fullname, descr]);
}
}
}
}
// sort results descending
objectResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
// perform the search on the required terms
for (var i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
// no match but word was a required one
if ((files = terms[word]) == null)
break;
if (files.length == undefined) {
files = [files];
}
// create the mapping
for (var j = 0; j < files.length; j++) {
var file = files[j];
if (file in fileMap)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
}
// now check if the files don't contain excluded terms
for (var file in fileMap) {
var valid = true;
// check if all requirements are matched
if (fileMap[file].length != searchterms.length)
continue;
// ensure that none of the excluded terms is in the
// search result.
for (var i = 0; i < excluded.length; i++) {
if (terms[excluded[i]] == file ||
$.contains(terms[excluded[i]] || [], file)) {
valid = false;
break;
}
}
// if we have still a valid result we can add it
// to the result list
if (valid)
regularResults.push([filenames[file], titles[file], '', null]);
}
// delete unused variables in order to not waste
// memory until list is retrieved completely
delete filenames, titles, terms;
// now sort the regular results descending by title
regularResults.sort(function(a, b) {
var left = a[1].toLowerCase();
var right = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0);
});
// combine both
var results = regularResults.concat(objectResults);
// print the results
var resultCount = results.length;
function displayNextItem() {
// results left, load the summary and display it
if (results.length) {
var item = results.pop();
var listItem = $('<li style="display:none"></li>');
listItem.append($('<a/>').attr(
'href',
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
highlightstring + item[2]).html(item[1]));
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
$.get('_sources/' + item[0] + '.txt', function(data) {
listItem.append($.makeSearchSummary(data, searchterms, hlterms));
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
});
} else {
// no source available, just display title
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
}
}
// search finished, update title and status message
else {
Search.stopPulse();
Search.title.text(_('Search Results'));
if (!resultCount)
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
else
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
Search.status.fadeIn(500);
}
}
displayNextItem();
}
}
$(document).ready(function() {
Search.init();
});

View File

@ -1,306 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>API/Interfaces &mdash; plone.app.discussion v1.0b4 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '#',
VERSION: '1.0b4',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="plone.app.discussion v1.0b4 documentation" href="index.html" />
<link rel="prev" title="Design Notes" href="design.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="design.html" title="Design Notes"
accesskey="P">previous</a> |</li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="api-interfaces">
<h1>API/Interfaces<a class="headerlink" href="#api-interfaces" title="Permalink to this headline"></a></h1>
<p>The conversation and replies adapters.</p>
<p>The conversation is responsible for storing all comments. It provides a
dict-like API for accessing comments, where keys are integers and values
are IComment objects. It also provides features for finding comments quickly.</p>
<p>The IReplies adapter provides an API for finding and manipulating the comments
directly in reply to a particular comment (implemented by the CommentReplies
adpater) or at the top level of the conversation (implemented by the
ConversationReplies adapter).</p>
<dl class="interface">
<dt id="plone.app.discussion.interfaces.IConversation">
<em class="property">interface </em><tt class="descclassname">plone.app.discussion.interfaces.</tt><tt class="descname">IConversation</tt><a class="headerlink" href="#plone.app.discussion.interfaces.IConversation" title="Permalink to this definition"></a></dt>
<dd><p>Extends: <tt class="xref docutils literal"><span class="pre">zope.interface.common.mapping.IIterableMapping</span></tt></p>
<p>A conversation about a content object.</p>
<p>This is a persistent object in its own right and manages all comments.</p>
<p>The dict interface allows access to all comments. They are stored by
long integer key, in the order they were added.</p>
<p>Note that __setitem__() is not supported - use addComment() instead.
However, comments can be deleted using __delitem__().</p>
<p>To get replies at the top level, adapt the conversation to IReplies.</p>
<p>The conversation can be traversed to via the ++comments++ namespace.
For example, path/to/object/++comments++/123 retrieves comment 123.</p>
<p>The __parent__ of the conversation (and the acquisition parent during
traversal) is the content object. The conversation is the __parent__
(and acquisition parent) for all comments, regardless of threading.</p>
<dl class="method">
<dt id="IConversation.__delitem__">
<tt class="descname">__delitem__</tt><big>(</big><em>key</em><big>)</big><a class="headerlink" href="#IConversation.__delitem__" title="Permalink to this definition"></a></dt>
<dd>Delete the comment with the given key. The key is a long id.</dd></dl>
<dl class="attribute">
<dt id="IConversation.last_comment_date">
<tt class="descname">last_comment_date</tt><a class="headerlink" href="#IConversation.last_comment_date" title="Permalink to this definition"></a></dt>
<dd>Date of the most recent comment</dd></dl>
<dl class="attribute">
<dt id="IConversation.total_comments">
<tt class="descname">total_comments</tt><a class="headerlink" href="#IConversation.total_comments" title="Permalink to this definition"></a></dt>
<dd>Total number of comments on this item</dd></dl>
<dl class="method">
<dt id="IConversation.getComments">
<tt class="descname">getComments</tt><big>(</big><em>start=0</em>, <em>size=None</em><big>)</big><a class="headerlink" href="#IConversation.getComments" title="Permalink to this definition"></a></dt>
<dd><p>Return an iterator of comment objects for rendering.</p>
<p>The &#8216;start&#8217; parameter is the id of the comment from which to start the
batch. If no such comment exists, the next higher id will be used.
This means that you can use max key from a previous batch + 1 safely.</p>
<p>The &#8216;size&#8217; parameter is the number of comments to return in the
batch.</p>
<p>The comments are returned in creation date order, in the exact batch
size specified.</p>
</dd></dl>
<dl class="method">
<dt id="IConversation.enabled">
<tt class="descname">enabled</tt><big>(</big><big>)</big><a class="headerlink" href="#IConversation.enabled" title="Permalink to this definition"></a></dt>
<dd><p>Returns True if discussion is enabled for this conversation.</p>
<p>This method checks five different settings in order to figure out if
discussion is enable on a specific content object:</p>
<ol class="arabic simple">
<li>Check if discussion is enabled globally in the plone.app.discussion
registry/control panel.</li>
<li>If the current content object is a folder, always return False, since
we don&#8217;t allow comments on a folder. This setting is used to allow/
disallow comments for all content objects inside a folder, not for
the folder itself.</li>
<li>Check if the allow_discussion boolean flag on the content object is
set. If it is set to True or False, return the value. If it set to
None, try further.</li>
<li>Traverse to a folder with allow_discussion set to either True or
False. If allow_discussion is not set (None), traverse further until
we reach the PloneSiteRoot.</li>
<li>Check if discussion is allowed for the content type.</li>
</ol>
</dd></dl>
<dl class="method">
<dt id="IConversation.getThreads">
<tt class="descname">getThreads</tt><big>(</big><em>start=0</em>, <em>size=None</em>, <em>root=0</em>, <em>depth=None</em><big>)</big><a class="headerlink" href="#IConversation.getThreads" title="Permalink to this definition"></a></dt>
<dd><p>Return a batch of comment objects for rendering.</p>
<p>The &#8216;start&#8217; parameter is the id of the comment from which to start
the batch. If no such comment exists, the next higher id will be used.
This means that you can use max key from a previous batch + 1 safely.
This should be a root level comment.</p>
<p>The &#8216;size&#8217; parameter is the number of threads to return in the
batch. Full threads are always returned (although you can stop
consuming the iterator if you want to abort).</p>
<p>&#8216;root&#8217;, if given, is the id of the comment to which reply
threads will be found. &#8216;root&#8217; itself is not included. If not given,
all threads are returned.</p>
<p>If &#8216;depth&#8217; is given, it can be used to limit the depth of threads
returned. For example, depth=1 will return only direct replies.</p>
<p>Comments are returned as an iterator of dicts with keys &#8216;comment&#8217;,
the comment, &#8216;id&#8217;, the comment id, and &#8216;depth&#8217;, which is 0 for
top-level comments, 1 for their replies, and so on. The list is
returned in depth-first order.</p>
</dd></dl>
<dl class="method">
<dt id="IConversation.addComment">
<tt class="descname">addComment</tt><big>(</big><em>comment</em><big>)</big><a class="headerlink" href="#IConversation.addComment" title="Permalink to this definition"></a></dt>
<dd>Adds a new comment to the list of comments, and returns the
comment id that was assigned. The comment_id property on the comment
will be set accordingly.</dd></dl>
<dl class="attribute">
<dt id="IConversation.commentators">
<tt class="descname">commentators</tt><a class="headerlink" href="#IConversation.commentators" title="Permalink to this definition"></a></dt>
<dd>The set of unique commentators (usernames)</dd></dl>
</dd></dl>
<dl class="interface">
<dt id="plone.app.discussion.interfaces.IReplies">
<em class="property">interface </em><tt class="descclassname">plone.app.discussion.interfaces.</tt><tt class="descname">IReplies</tt><a class="headerlink" href="#plone.app.discussion.interfaces.IReplies" title="Permalink to this definition"></a></dt>
<dd><p>Extends: <tt class="xref docutils literal"><span class="pre">zope.interface.common.mapping.IIterableMapping</span></tt></p>
<p>A set of related comments in reply to a given content object or
another comment.</p>
<p>Adapt a conversation or another comment to this interface to obtain the
direct replies.</p>
<dl class="method">
<dt id="IReplies.__delitem__">
<tt class="descname">__delitem__</tt><big>(</big><em>key</em><big>)</big><a class="headerlink" href="#IReplies.__delitem__" title="Permalink to this definition"></a></dt>
<dd>Delete the comment with the given key. The key is a long id.</dd></dl>
<dl class="method">
<dt id="IReplies.addComment">
<tt class="descname">addComment</tt><big>(</big><em>comment</em><big>)</big><a class="headerlink" href="#IReplies.addComment" title="Permalink to this definition"></a></dt>
<dd>Adds a new comment as a child of this comment, and returns the
comment id that was assigned. The comment_id property on the comment
will be set accordingly.</dd></dl>
</dd></dl>
<dl class="interface">
<dt id="plone.app.discussion.interfaces.IComment">
<em class="property">interface </em><tt class="descclassname">plone.app.discussion.interfaces.</tt><tt class="descname">IComment</tt><a class="headerlink" href="#plone.app.discussion.interfaces.IComment" title="Permalink to this definition"></a></dt>
<dd><p>A comment.</p>
<p>Comments are indexed in the catalog and subject to workflow and security.</p>
<dl class="attribute">
<dt id="IComment.author_username">
<tt class="descname">author_username</tt><a class="headerlink" href="#IComment.author_username" title="Permalink to this definition"></a></dt>
<dd>Name</dd></dl>
<dl class="attribute">
<dt id="IComment.modification_date">
<tt class="descname">modification_date</tt><a class="headerlink" href="#IComment.modification_date" title="Permalink to this definition"></a></dt>
<dd>Modification date</dd></dl>
<dl class="attribute">
<dt id="IComment.title">
<tt class="descname">title</tt><a class="headerlink" href="#IComment.title" title="Permalink to this definition"></a></dt>
<dd>Subject</dd></dl>
<dl class="attribute">
<dt id="IComment.author_email">
<tt class="descname">author_email</tt><a class="headerlink" href="#IComment.author_email" title="Permalink to this definition"></a></dt>
<dd>Email</dd></dl>
<dl class="attribute">
<dt id="IComment.text">
<tt class="descname">text</tt><a class="headerlink" href="#IComment.text" title="Permalink to this definition"></a></dt>
<dd>Comment</dd></dl>
<dl class="attribute">
<dt id="IComment.portal_type">
<tt class="descname">portal_type</tt><a class="headerlink" href="#IComment.portal_type" title="Permalink to this definition"></a></dt>
<dd>Portal type</dd></dl>
<dl class="attribute">
<dt id="IComment.comment_id">
<tt class="descname">comment_id</tt><a class="headerlink" href="#IComment.comment_id" title="Permalink to this definition"></a></dt>
<dd>A comment id unique to this conversation</dd></dl>
<dl class="attribute">
<dt id="IComment.author_name">
<tt class="descname">author_name</tt><a class="headerlink" href="#IComment.author_name" title="Permalink to this definition"></a></dt>
<dd>Name</dd></dl>
<dl class="attribute">
<dt id="IComment.creation_date">
<tt class="descname">creation_date</tt><a class="headerlink" href="#IComment.creation_date" title="Permalink to this definition"></a></dt>
<dd>Creation date</dd></dl>
<dl class="attribute">
<dt id="IComment.mime_type">
<tt class="descname">mime_type</tt><a class="headerlink" href="#IComment.mime_type" title="Permalink to this definition"></a></dt>
<dd>MIME type</dd></dl>
<dl class="attribute">
<dt id="IComment.__name__">
<tt class="descname">__name__</tt><a class="headerlink" href="#IComment.__name__" title="Permalink to this definition"></a></dt>
<dd>Name</dd></dl>
<dl class="attribute">
<dt id="IComment.in_reply_to">
<tt class="descname">in_reply_to</tt><a class="headerlink" href="#IComment.in_reply_to" title="Permalink to this definition"></a></dt>
<dd>Id of comment this comment is in reply to</dd></dl>
<dl class="attribute">
<dt id="IComment.creator">
<tt class="descname">creator</tt><a class="headerlink" href="#IComment.creator" title="Permalink to this definition"></a></dt>
<dd>Author name (for display)</dd></dl>
<dl class="attribute">
<dt id="IComment.__parent__">
<tt class="descname">__parent__</tt><a class="headerlink" href="#IComment.__parent__" title="Permalink to this definition"></a></dt>
<dd>Conversation</dd></dl>
</dd></dl>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h4>Previous topic</h4>
<p class="topless"><a href="design.html"
title="previous chapter">Design Notes</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/api.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="design.html" title="Design Notes"
>previous</a> |</li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2010, Timo Stollenwerk.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
</div>
</body>
</html>

View File

@ -1,153 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Architectural Principles &mdash; plone.app.discussion v1.0b4 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '#',
VERSION: '1.0b4',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="plone.app.discussion v1.0b4 documentation" href="index.html" />
<link rel="next" title="Design Notes" href="design.html" />
<link rel="prev" title="Welcome to plone.app.discussions documentation!" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="design.html" title="Design Notes"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="index.html" title="Welcome to plone.app.discussions documentation!"
accesskey="P">previous</a> |</li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="architectural-principles">
<h1>Architectural Principles<a class="headerlink" href="#architectural-principles" title="Permalink to this headline"></a></h1>
<p>This document outlines architectural principles used in the design of
plone.app.discussion.</p>
<blockquote>
<dl class="docutils">
<dt><strong>Discussion items have a portal_type</strong></dt>
<dd>This makes it easier to search for them and manage them using existing
CMF and Plone UI constructs.</dd>
<dt><strong>Discussion items are cataloged</strong></dt>
<dd>It is possible to search for discussion items like any other type of
content.</dd>
<dt><strong>Discussion items are subject to workflow and permission</strong></dt>
<dd>Moderation, anonymous commenting, and auto approve/reject should be
handled using workflow states, automatic and manual transitions, and
permissions.</dd>
<dt><strong>Discussion items are light weight objects</strong></dt>
<dd>Discussion item objects are as light weight as possible. Ideally, a
discussion item should be as lightweight as a catalog brain. This may mean
that we forego convenience base classes and re-implement certain interfaces.
Comments should not provide the full set of dublin core metadata, though
custom indexers can be used to provide values for standard catalog indexes.</dd>
<dt><strong>Optimise for retrival speed</strong></dt>
<dd>HTML filtering and other processing should happen on save, not on render,
to make rendering quick.</dd>
<dt><strong>Settings are stored using plone.registry</strong></dt>
<dd>Any global setting should be stored in plone.registry records.</dd>
<dt><strong>Forms are constructed using extensible z3c.form forms</strong></dt>
<dd>This allows plugins (such as spam protection algorithms) to provide
additional validation. It also allows integrators to write add-ons that add
new fields to the comment form.</dd>
<dt><strong>Discussion items are stored in a BTree container</strong></dt>
<dd>This allows faster lookup and manipulation.</dd>
<dt><strong>Discussion items are accessed using a dict-like interface</strong></dt>
<dd>This makes iteration and manipulation more natural. Even if comments are
not stored threaded, the dict interface should act as if they are, i.e.
calling items() on a comment should return the replies to that comment
(in order).</dd>
<dt><strong>Discussion items are retrieved in reverse creation date order</strong></dt>
<dd>Discussion items do not need to support explicit ordering. They should
always be retrieved in reverse creation date order (most recent for).
They can be stored with keys so that this is always true.</dd>
<dt><strong>Discussion items do not need readable ids</strong></dt>
<dd>Ids can be based on the creation date.</dd>
<dt><strong>Discussion items send events</strong></dt>
<dd>The usual zope.lifecycleevent and zope.container events are fired when
discussion items are added, removed, or modified.</dd>
</dl>
</blockquote>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h4>Previous topic</h4>
<p class="topless"><a href="index.html"
title="previous chapter">Welcome to plone.app.discussion&#8217;s documentation!</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="design.html"
title="next chapter">Design Notes</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/architecture.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="design.html" title="Design Notes"
>next</a> |</li>
<li class="right" >
<a href="index.html" title="Welcome to plone.app.discussions documentation!"
>previous</a> |</li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2010, Timo Stollenwerk.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
</div>
</body>
</html>

View File

@ -1,111 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Captcha Plugin Architecture &mdash; plone.app.discussion v1.0b4 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '#',
VERSION: '1.0b4',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="plone.app.discussion v1.0b4 documentation" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="captcha-plugin-architecture">
<h1>Captcha Plugin Architecture<a class="headerlink" href="#captcha-plugin-architecture" title="Permalink to this headline"></a></h1>
<p>This document contains design notes for the plone.app.discussion Captcha plugin
architecture. It also explains how to write your own Captcha plugin (???).</p>
<p>Currently there are two plugins that work with plone.app.discussion:</p>
<blockquote>
<ol class="arabic simple">
<li>plone.formwidget.captcha</li>
<li>plone.formwidget.recaptcha</li>
</ol>
</blockquote>
<ol class="arabic simple">
<li>Captcha plugin must provide the feature &#8220;plone.app.discussion-captcha&#8221;:</li>
</ol>
<p>Add this to your configure.zcml:</p>
<div class="highlight-python"><pre>&lt;configure ...
xmlns:meta="http://namespaces.zope.org/meta"&gt;
&lt;!-- Declare that plone.formwidget.captcha provides a Captcha field that
can be used by plone.app.discussion to add a Captcha field to comment
forms. --&gt;
&lt;meta:provides feature="plone.app.discussion-captcha" /&gt;
...
&lt;/configure&gt;</pre>
</div>
<p>For examples have a look at plone.formwidget.captcha</p>
<p><a class="reference external" href="https://svn.plone.org/svn/plone/plone.formwidget.captcha/trunk/plone/formwidget/captcha/configure.zcml">https://svn.plone.org/svn/plone/plone.formwidget.captcha/trunk/plone/formwidget/captcha/configure.zcml</a></p>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/captcha.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2010, Timo Stollenwerk.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
</div>
</body>
</html>

View File

@ -1,306 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Design Notes &mdash; plone.app.discussion v1.0b4 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '#',
VERSION: '1.0b4',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="plone.app.discussion v1.0b4 documentation" href="index.html" />
<link rel="next" title="API/Interfaces" href="api.html" />
<link rel="prev" title="Architectural Principles" href="architecture.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="api.html" title="API/Interfaces"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="architecture.html" title="Architectural Principles"
accesskey="P">previous</a> |</li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="design-notes">
<h1>Design Notes<a class="headerlink" href="#design-notes" title="Permalink to this headline"></a></h1>
<p>This document contains design notes for plone.app.discussion.</p>
<div class="section" id="storage-and-traversal">
<h2>Storage and traversal<a class="headerlink" href="#storage-and-traversal" title="Permalink to this headline"></a></h2>
<p>For each content item, there is a Conversation object stored in annotations.
This can be traversed to via the ++conversation++ namespace, but also fetched
via an adapter lookup to IConversation.</p>
<p>The conversation stores all comments related to a content object. Each
comment has an integer id (also representable as a string, to act as an OFS
id and allow traversal). Hence, traversing to obj/++conversation++/123 retrieves
the comment with id 123.</p>
<p>Comments ids are assigned in order, so a comment with id N was posted before
a comment with id N + 1. However, it is not guaranteed that ids will be
incremental. Ids must be positive integers - 0 or negative numbers are not
allowed.</p>
<p>Threading information is stored in the conversation: we keep track of the
set of children and the parent if any comment. Top-level comments have a
parent id of 0. This information is managed by the conversation class when
comments are manipulated using a dict-like API.</p>
<p>Note that the __parent__/acquisition parent of an IComment is the
IConversation, and the __parent__/acquisition parent of an IConversation is
the content object.</p>
</div>
<div class="section" id="events">
<h2>Events<a class="headerlink" href="#events" title="Permalink to this headline"></a></h2>
<p>Manipulating the IConversation object should fire the usual IObjectAddedEvent
and IObjectRemovedEvent events. The UI may further fire IObjectCreatedEvent
and IObjectModifiedEvent for comments.</p>
</div>
<div class="section" id="factories">
<h2>Factories<a class="headerlink" href="#factories" title="Permalink to this headline"></a></h2>
<p>Comments should always be created via the &#8216;Discussion Item&#8217; IFactory utility.
Conversations should always be obtained via the IConversation adapter (even
the ++conversation++ namespace should use this). This makes it possible to
replace conversations and comments transparently.</p>
</div>
<div class="section" id="the-comment-class">
<h2>The Comment class<a class="headerlink" href="#the-comment-class" title="Permalink to this headline"></a></h2>
<p>The inheritance tree for DiscussionItem is shown below. Classes we want to
mix in and interface we want to implement in the Comment class are marked
with [x].</p>
<blockquote>
<dl class="docutils">
<dt>[ ] DiscussionItem</dt>
<dd><dl class="first last docutils">
<dt>[ ] Document</dt>
<dd><dl class="first last docutils">
<dt>[ ] PortalContent = [ ] IContentish</dt>
<dd><p class="first">[ ] DynamicType = [ ] IDynamicType
[ ] CMFCatalogAware = [ ] &lt;no interface&gt;
[ ] SimpleItem = [ ] ISimpleItem</p>
<blockquote class="last">
<dl class="docutils">
<dt>[ ] Item [ ]</dt>
<dd>[?] Base = [ ] &lt;no interface&gt;
[ ] Resource = [ ] &lt;no interface&gt;
[ ] CopySource = [ ] ICopySource
[ ] Tabs = [ ] &lt;no interface&gt;
[x] Traversable = [ ] ITraversable
[ ] Element = [ ] &lt;no interface&gt;
[x] Owned = [ ] IOwned
[ ] UndoSupport = [ ] IUndoSupport</dd>
</dl>
<p>[ ] Persistent [ ]
[ ] Implicit [ ]
[x] RoleManager = [ ] IRoleManager</p>
<blockquote>
[ ] RoleManager = [ ] IPermissionMappingSupport</blockquote>
</blockquote>
</dd>
<dt>[ ] DefaultDublinCoreImpl = [ ] IDublinCore</dt>
<dd><blockquote class="first">
[ ] ICatalogableDublinCore
[ ] IMutableDublinCore</blockquote>
<p class="last">[ ] PropertyManager = [ ] IPropertyManager</p>
</dd>
</dl>
</dd>
</dl>
</dd>
</dl>
</blockquote>
<p>Thus, we want:</p>
<blockquote>
<ul>
<li><dl class="first docutils">
<dt>Traversable, to get absolute_url() and friends</dt>
<dd><ul class="first last simple">
<li>this requires a good acquisition chain at all times</li>
</ul>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>Acquisition.Explicit, to support acquisition</dt>
<dd><ul class="first last simple">
<li>we do not want implicit acquisition</li>
</ul>
</dd>
</dl>
</li>
<li><p class="first">Owned, to be able to track ownership</p>
</li>
<li><p class="first">RoleManager, to support permissions and local roles</p>
</li>
</ul>
</blockquote>
<p>We also want to use a number of custom indexers for most of the standard
metadata such as creator, effective date etc.</p>
<p>Finally, we&#8217;ll need event handlers to perform the actual indexing.</p>
</div>
<div class="section" id="discussion-settings">
<h2>Discussion settings<a class="headerlink" href="#discussion-settings" title="Permalink to this headline"></a></h2>
<p>Discussion can be enabled per-type and per-instance, via values in the FTI
(allow_discussion) and on the object. These will remain unchanged. The
IConversation object&#8217;s &#8216;enabled&#8217; property should consult these.</p>
<p>Global settings should be managed using plone.registry. A control panel
can be generated from this as well, using the helper class in
plone.app.registry.</p>
<p>Note that some settings, notably those to do with permissions and workflow,
will need to be wired up as custom form fields with custom data mangers
or similar.</p>
</div>
<div class="section" id="workflow-and-permissions">
<h2>Workflow and permissions<a class="headerlink" href="#workflow-and-permissions" title="Permalink to this headline"></a></h2>
<p>Where possible, we should use existing permissions:</p>
<blockquote>
<ul class="simple">
<li>View</li>
<li>Reply to Item</li>
<li>Modify Portal Content</li>
<li>Request Review</li>
</ul>
</blockquote>
<p>In addition, we&#8217;ll need a &#8216;Moderator&#8217; role and a moderation permission,</p>
<blockquote>
<ul class="simple">
<li>Moderate comment</li>
<li>Bypass moderation</li>
</ul>
</blockquote>
<p>To control whether Anonymous can post comments, we manage the &#8216;Reply to Item&#8217;
permission. To control whether moderation is required for various roles, we
could manage the &#8216;Bypass moderation&#8217; permission.</p>
<p>These could work in a workflow like this:</p>
<blockquote>
<ul>
<li><dl class="first docutils">
<dt>&#8211;&gt; [posted] &#8211; {publish} &#8211;&gt; [published]&#8211;&gt; *</dt>
<dd><div class="first line-block">
<div class="line">^</div>
<div class="line"><a href="#id1"><span class="problematic" id="id2">|</span></a></div>
</div>
<p class="last">+&#8212;&#8211; {auto-publish} &#8212;&#8211;+
| |
+&#8212;&#8211; {auto-moderate} &#8212;-+</p>
</dd>
</dl>
</li>
</ul>
</blockquote>
<p>The &#8216;posted&#8217; state is the initial state. &#8216;published&#8217; is the state where the
comment is visible to non-reviewers.</p>
<p>The &#8216;publish&#8217; transition would be protected by the &#8216;Moderate comment&#8217;
permission. We could have states and transition for &#8216;rejected&#8217;, etc, but it
is probably just as good to delete comments that are rejected.</p>
<p>The &#8216;auto-publish&#8217; transition would be an automatic transition protected by
the &#8216;Bypass moderation&#8217; permission.</p>
<p>The &#8216;auto-moderate&#8217; transition would be another automatic transition protected
by an expression (e.g. calling a view) that returns True if the user is on
an auto-moderation &#8216;white-list&#8217;, e.g. by email address or username.</p>
</div>
<div class="section" id="forms-and-ui">
<h2>Forms and UI<a class="headerlink" href="#forms-and-ui" title="Permalink to this headline"></a></h2>
<p>The basic commenting display/reply form is placed in a viewlet.</p>
<p>The reply form is dynamically created right under the comment when the user hits
the reply button. To do so, we copy the standard comment form with a jQuery
function. This function sets the form&#8217;s hidden in_reply_to field to the id of
the comment the user wants to reply to. This also makes is possible to use
z3c.form validation for the reply forms, because we can uniquely identify the
a reply form request and return the reply form with validation errors.</p>
<p>Since we rely on JavaScript for the reply form creation, the reply button is
removed for nonJavaScript enabled browsers.</p>
<p>The comment form uses z3c.form and plone.z3cform&#8217;s ExtensibleForm support. This
makes it possible to plug in additional fields declaratively, e.g. to include
SPAM protection.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference external" href="#">Design Notes</a><ul>
<li><a class="reference external" href="#storage-and-traversal">Storage and traversal</a></li>
<li><a class="reference external" href="#events">Events</a></li>
<li><a class="reference external" href="#factories">Factories</a></li>
<li><a class="reference external" href="#the-comment-class">The Comment class</a></li>
<li><a class="reference external" href="#discussion-settings">Discussion settings</a></li>
<li><a class="reference external" href="#workflow-and-permissions">Workflow and permissions</a></li>
<li><a class="reference external" href="#forms-and-ui">Forms and UI</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="architecture.html"
title="previous chapter">Architectural Principles</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="api.html"
title="next chapter">API/Interfaces</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/design.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="api.html" title="API/Interfaces"
>next</a> |</li>
<li class="right" >
<a href="architecture.html" title="Architectural Principles"
>previous</a> |</li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2010, Timo Stollenwerk.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
</div>
</body>
</html>

View File

@ -1,180 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Index &mdash; plone.app.discussion v1.0b4 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '#',
VERSION: '1.0b4',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="plone.app.discussion v1.0b4 documentation" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="#" title="General Index"
accesskey="I">index</a></li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<h1 id="index">Index</h1>
<a href="#_"><strong>_</strong></a> | <a href="#A"><strong>A</strong></a> | <a href="#C"><strong>C</strong></a> | <a href="#E"><strong>E</strong></a> | <a href="#G"><strong>G</strong></a> | <a href="#I"><strong>I</strong></a> | <a href="#L"><strong>L</strong></a> | <a href="#M"><strong>M</strong></a> | <a href="#P"><strong>P</strong></a> | <a href="#T"><strong>T</strong></a>
<hr />
<h2 id="_">_</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IConversation.__delitem__">__delitem__() (IConversation method)</a></dt>
<dd><dl>
<dt><a href="api.html#IReplies.__delitem__">(IReplies method)</a></dt>
</dl></dd>
<dt><a href="api.html#IComment.__name__">__name__ (IComment attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
<dt><a href="api.html#IComment.__parent__">__parent__ (IComment attribute)</a></dt>
</dl></td></tr></table>
<h2 id="A">A</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IConversation.addComment">addComment() (IConversation method)</a></dt>
<dd><dl>
<dt><a href="api.html#IReplies.addComment">(IReplies method)</a></dt>
</dl></dd>
<dt><a href="api.html#IComment.author_email">author_email (IComment attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
<dt><a href="api.html#IComment.author_name">author_name (IComment attribute)</a></dt>
<dt><a href="api.html#IComment.author_username">author_username (IComment attribute)</a></dt>
</dl></td></tr></table>
<h2 id="C">C</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IComment.comment_id">comment_id (IComment attribute)</a></dt>
<dt><a href="api.html#IConversation.commentators">commentators (IConversation attribute)</a></dt>
<dt><a href="api.html#IComment.creation_date">creation_date (IComment attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
<dt><a href="api.html#IComment.creator">creator (IComment attribute)</a></dt>
</dl></td></tr></table>
<h2 id="E">E</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IConversation.enabled">enabled() (IConversation method)</a></dt></dl></td><td width="33%" valign="top"><dl>
</dl></td></tr></table>
<h2 id="G">G</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IConversation.getComments">getComments() (IConversation method)</a></dt>
<dt><a href="api.html#IConversation.getThreads">getThreads() (IConversation method)</a></dt></dl></td><td width="33%" valign="top"><dl>
</dl></td></tr></table>
<h2 id="I">I</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#plone.app.discussion.interfaces.IComment">IComment (interface in plone.app.discussion.interfaces)</a></dt>
<dt><a href="api.html#plone.app.discussion.interfaces.IConversation">IConversation (interface in plone.app.discussion.interfaces)</a></dt>
<dt><a href="api.html#IComment.in_reply_to">in_reply_to (IComment attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
<dt><a href="api.html#plone.app.discussion.interfaces.IReplies">IReplies (interface in plone.app.discussion.interfaces)</a></dt>
</dl></td></tr></table>
<h2 id="L">L</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IConversation.last_comment_date">last_comment_date (IConversation attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
</dl></td></tr></table>
<h2 id="M">M</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IComment.mime_type">mime_type (IComment attribute)</a></dt>
<dt><a href="api.html#IComment.modification_date">modification_date (IComment attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
</dl></td></tr></table>
<h2 id="P">P</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IComment.portal_type">portal_type (IComment attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
</dl></td></tr></table>
<h2 id="T">T</h2>
<table width="100%" class="indextable"><tr><td width="33%" valign="top">
<dl>
<dt><a href="api.html#IComment.text">text (IComment attribute)</a></dt>
<dt><a href="api.html#IComment.title">title (IComment attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
<dt><a href="api.html#IConversation.total_comments">total_comments (IConversation attribute)</a></dt>
</dl></td></tr></table>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="#" title="General Index"
>index</a></li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2010, Timo Stollenwerk.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
</div>
</body>
</html>

View File

@ -1,301 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Welcome to plone.app.discussions documentation! &mdash; plone.app.discussion v1.0b4 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '#',
VERSION: '1.0b4',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="plone.app.discussion v1.0b4 documentation" href="#" />
<link rel="next" title="Architectural Principles" href="architecture.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="architecture.html" title="Architectural Principles"
accesskey="N">next</a> |</li>
<li><a href="#">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="welcome-to-plone-app-discussion-s-documentation">
<h1>Welcome to plone.app.discussion&#8217;s documentation!<a class="headerlink" href="#welcome-to-plone-app-discussion-s-documentation" title="Permalink to this headline"></a></h1>
<p>Contents:</p>
<ul>
<li class="toctree-l1"><a class="reference external" href="architecture.html">Architectural Principles</a></li>
<li class="toctree-l1"><a class="reference external" href="design.html">Design Notes</a><ul>
<li class="toctree-l2"><a class="reference external" href="design.html#storage-and-traversal">Storage and traversal</a></li>
<li class="toctree-l2"><a class="reference external" href="design.html#events">Events</a></li>
<li class="toctree-l2"><a class="reference external" href="design.html#factories">Factories</a></li>
<li class="toctree-l2"><a class="reference external" href="design.html#the-comment-class">The Comment class</a></li>
<li class="toctree-l2"><a class="reference external" href="design.html#discussion-settings">Discussion settings</a></li>
<li class="toctree-l2"><a class="reference external" href="design.html#workflow-and-permissions">Workflow and permissions</a></li>
<li class="toctree-l2"><a class="reference external" href="design.html#forms-and-ui">Forms and UI</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference external" href="api.html">API/Interfaces</a></li>
</ul>
</div>
<div class="section" id="changelog">
<h1>Changelog<a class="headerlink" href="#changelog" title="Permalink to this headline"></a></h1>
<div class="section" id="b5-unreleased">
<h2>1.0b5 (unreleased)<a class="headerlink" href="#b5-unreleased" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>Fix encoding error in migration procedure, otherwise migration procedure
breaks on joining output list in case we have there any non-ascii characters.
[piv]</li>
<li>plone.z3cform 0.6.0 compatibility (fix maximum recursion depth error which
appears with plone.z3cform higher than 0.5.10).
[piv]</li>
<li>Removed moderation.js from js registry and include it only in moderation.pt as
that is the only place where it is used.
[ggozad]</li>
</ul>
</div>
<div class="section" id="b4-2010-04-04">
<h2>1.0b4 (2010-04-04)<a class="headerlink" href="#b4-2010-04-04" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>New feature: As a moderator, I am notified when new comments require my
attention.
[timo]</li>
<li>Sphinx-based developer documentation added. See
<a class="reference external" href="http://packages.python.org/plone.app.discussion">http://packages.python.org/plone.app.discussion</a>.
[timo]</li>
<li>Rename &#8220;Single State Workflow&#8221; to &#8220;Comment Single State Workflow&#8221;.
[timo]</li>
<li>Rename &#8216;publish comment&#8217; to &#8216;approve comment&#8217;. This fixes #1608470.
[timo]</li>
<li>Show a warning in the moderation view if the moderation workflow is disabled.
[timo]</li>
<li>Move &#8216;Moderate comments&#8217; link from site actions to user actions.
[timo]</li>
<li>Fix #662654: As an administrator, I can configure a Collection to show recent
comments. Comment.Type() now correctly returns the FTI title (&#8216;Comment&#8217;)
[chaoflow]</li>
<li>German translation updated.
[juh]</li>
<li>Fix #2419342: Fix untranslated published/deleted status messages.
[timo]</li>
<li>Remove fixed width of the actions column of the moderation view. The
translated button titles can differ in size from the English titles.
[timo]</li>
<li>Fix #2494228: Remove comments as well when a content object is deleted.
[timo]</li>
<li>Fix unicode error when non-ASCII characters are typed into the name field of a
comment by anonymous users.
[regebro]</li>
<li>Make p.a.d. work with the recent version of plone.z3cform (0.5.10)
[timo]</li>
<li>Make p.a.d. styles less generic. This fixes #10253.
[timo]</li>
<li>Added greek translation.
[ggozad]</li>
<li>A bug in the moderator panel meant you couldn&#8217;t delete items in a virtual
host, if your portal was named &#8220;plone&#8221;.
[regebro]</li>
</ul>
</div>
<div class="section" id="b3-2010-01-28">
<h2>1.0b3 (2010-01-28)<a class="headerlink" href="#b3-2010-01-28" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>Added an i18n directory for messages in the plone domain and updated scripts
to rebuild and sync it.
[hannosch]</li>
<li>Added an optional conversationCanonicalAdapterFactory showing how to share
comments across all translations with LinguaPlone, by storing and retrieving
the conversation from the canonical object.
[hannosch]</li>
<li>Play by the Plone 3.3+ rules and use the INavigationRoot as a base for the
moderation view.
[hannosch]</li>
<li>Added a commentTitle CSS class to the comment titles.
[hannosch]</li>
<li>Update message ids to match their real text.
[hannosch]</li>
<li>Set CSS classes for the comment form in the updateActions method.
[timo]</li>
<li>Respect the allow_comments field on an object and avoid calculations if no
comments should be shown.
[hannosch]</li>
<li>Automatically load the ZCML files of the captcha widgets if they are
installed.
[hannosch]</li>
<li>Fixed i18n domain in GenericSetup profiles to be <tt class="docutils literal"><span class="pre">plone</span></tt>. Other values
aren&#8217;t supported for GS profiles.
[hannosch]</li>
<li>Provide our own copy of the default one state workflow. Not all Plone sites
have this workflow installed.
[hannosch]</li>
<li>Register the event subscribers for the correct interfaces in Plone 3.
[hannosch]</li>
<li>Factored out subscriber declarations into its own ZCML file.
[hannosch]</li>
<li>Bugfix for #2281226: Moderation View: Comments disappear when hitting the
&#8216;Apply&#8217; button without choosing a bulk action.
[timo]</li>
<li>Allow to show the full text of a comment in the moderation view.
[timo]</li>
<li>German translation added.
[timo]</li>
<li>Italian translation added.
[keul]</li>
</ul>
</div>
<div class="section" id="b2-2010-01-22">
<h2>1.0b2 (2010-01-22)<a class="headerlink" href="#b2-2010-01-22" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>Bugfix for #2010181: The name of a commenter who commented while not logged in
should not appear as a link.
[timo]</li>
<li>Bugfix for #2010078: Comments that await moderation are visually distinguished
from published comments.
[timo]</li>
<li>Bugfix for #2010085: Use object_provides instead of portal_type to query the
catalog for comment.
[timo]</li>
<li>Bugfix for #2010071: p.a.d. works with plone.z3cform 0.5.7 and
plone.app.z3cform 0.4.9 now.
[timo]</li>
<li>Bugfix for #1513398: Show &#8220;anonymous&#8221; when name field is empty in comment
form.
[timo]</li>
<li>Migration view: Dry run option added, abort transaction when something goes
wrong during migration, be more verbose about errors.
[timo]</li>
</ul>
</div>
<div class="section" id="b1-2009-12-08">
<h2>1.0b1 (2009-12-08)<a class="headerlink" href="#b1-2009-12-08" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>Fix redirect after a adding a comment
[timo]</li>
<li>Replace yes/no widgets with check boxes in the discussion control panel
[timo]</li>
<li>Make comments viewlet show up in Plone 4
[timo]</li>
<li>Apply Plone 4 styles to comment form
[timo]</li>
<li>Simplify moderation view by removing the filters
[timo]</li>
</ul>
</div>
<div class="section" id="a2-2009-10-18">
<h2>1.0a2 (2009-10-18)<a class="headerlink" href="#a2-2009-10-18" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>Plone 4 / Zope 2.12 support
[timo]</li>
<li>Comment migration script added
[timo]</li>
<li>Pluggable plone.z3cform comment forms
[timo]</li>
<li>Captcha and ReCaptcha support added
[timo]</li>
</ul>
</div>
<div class="section" id="a1-2009-06-07">
<h2>1.0a1 (2009-06-07)<a class="headerlink" href="#a1-2009-06-07" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li>Basic commenting functionality and batch moderation.
[timo]</li>
</ul>
</div>
</div>
<div class="section" id="indices-and-tables">
<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><a class="reference external" href="genindex.html"><em>Index</em></a></li>
<li><a class="reference external" href="modindex.html"><em>Module Index</em></a></li>
<li><a class="reference external" href="search.html"><em>Search Page</em></a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="#">Table Of Contents</a></h3>
<ul>
<li><a class="reference external" href="#">Welcome to plone.app.discussion&#8217;s documentation!</a><ul>
</ul>
</li>
<li><a class="reference external" href="#changelog">Changelog</a><ul>
<li><a class="reference external" href="#b5-unreleased">1.0b5 (unreleased)</a></li>
<li><a class="reference external" href="#b4-2010-04-04">1.0b4 (2010-04-04)</a></li>
<li><a class="reference external" href="#b3-2010-01-28">1.0b3 (2010-01-28)</a></li>
<li><a class="reference external" href="#b2-2010-01-22">1.0b2 (2010-01-22)</a></li>
<li><a class="reference external" href="#b1-2009-12-08">1.0b1 (2009-12-08)</a></li>
<li><a class="reference external" href="#a2-2009-10-18">1.0a2 (2009-10-18)</a></li>
<li><a class="reference external" href="#a1-2009-06-07">1.0a1 (2009-06-07)</a></li>
</ul>
</li>
<li><a class="reference external" href="#indices-and-tables">Indices and tables</a></li>
</ul>
<h4>Next topic</h4>
<p class="topless"><a href="architecture.html"
title="next chapter">Architectural Principles</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/index.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" size="18" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="architecture.html" title="Architectural Principles"
>next</a> |</li>
<li><a href="#">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2010, Timo Stollenwerk.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
</div>
</body>
</html>

View File

@ -1,30 +0,0 @@
# Sphinx inventory version 1
# Project: plone.app.discussion
# Version: 1.0b4
IConversation.getComments method api.html
IComment.title attribute api.html
IComment.modification_date attribute api.html
IConversation.getThreads method api.html
IComment.comment_id attribute api.html
plone.app.discussion.interfaces.IReplies interface api.html
IConversation.enabled method api.html
plone.app.discussion.interfaces.IComment interface api.html
IComment.creator attribute api.html
IComment.author_email attribute api.html
IComment.author_name attribute api.html
IConversation.__delitem__ method api.html
IComment.creation_date attribute api.html
IConversation.total_comments attribute api.html
IComment.__parent__ attribute api.html
IComment.in_reply_to attribute api.html
IComment.__name__ attribute api.html
IComment.text attribute api.html
plone.app.discussion.interfaces.IConversation interface api.html
IComment.author_username attribute api.html
IConversation.last_comment_date attribute api.html
IComment.portal_type attribute api.html
IComment.mime_type attribute api.html
IReplies.addComment method api.html
IConversation.commentators attribute api.html
IConversation.addComment method api.html
IReplies.__delitem__ method api.html

View File

@ -1,91 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &mdash; plone.app.discussion v1.0b4 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '#',
VERSION: '1.0b4',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="top" title="plone.app.discussion v1.0b4 documentation" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<h1 id="search-documentation">Search</h1>
<div id="fallback" class="admonition warning">
<script type="text/javascript">$('#fallback').hide();</script>
<p>
Please activate JavaScript to enable the search
functionality.
</p>
</div>
<p>
From here you can search these documents. Enter your search
words into the box below and click "search". Note that the search
function will automatically search for all of the words. Pages
containing fewer words won't appear in the result list.
</p>
<form action="" method="get">
<input type="text" name="q" value="" />
<input type="submit" value="search" />
<span id="search-progress" style="padding-left: 10px"></span>
</form>
<div id="search-results">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li><a href="index.html">plone.app.discussion v1.0b4 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2010, Timo Stollenwerk.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
</div>
<script type="text/javascript" src="searchindex.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long