[Zope3-checkins] CVS: zopeproducts/zwiki - __init__.py:1.1 __init__.pyc:1.1 add.pt:1.1 browser.py:1.1 browser.pyc:1.1 configure.zcml:1.1 interfaces.py:1.1 interfaces.pyc:1.1 view_page.pt:1.1 zwiki.py:1.1 zwiki.pyc:1.1
Stephan Richter
srichter@cbu.edu
Sat, 5 Apr 2003 15:50:04 -0500
Update of /cvs-repository/zopeproducts/zwiki
In directory cvs.zope.org:/tmp/cvs-serv19546/zwiki
Added Files:
__init__.py __init__.pyc add.pt browser.py browser.pyc
configure.zcml interfaces.py interfaces.pyc view_page.pt
zwiki.py zwiki.pyc
Log Message:
Initial ZWiki for Zope 3 checkin. Much thanks goes to Simon Michael who
helped me out getting this first piece of rendering right.
Features so far:
- Wiki object. Container of all Wiki pages.
- WikiPage content object, holding the data, which turned out to be tiny.
- Beginnings of the PageHierarchyAdapter...no view and not tested.
- Rendered code recognizes Wiki names, the escaping '!' and the '[]' for
all lower case Wiki names.
- Generated Links bring you either to another Wiki page or to an add page.
Immediate to dos:
- Get tests running.
- Add tests for the rendering.
- Implement PageHierarchy support (maybe write own traverser).
- Implement stx and/or rest support.
I hope that Simon will really get into the project and contribute all of
his know-how on Wikis. :-)
I find that the Developer experience has drastically improved since I last
tried to develop a product (bug collector) for Zope 3. There are still
some rough edges, but that's okay - at least I do not feel like missing
features left and right.
=== Added File zopeproducts/zwiki/__init__.py ===
=== Added File zopeproducts/zwiki/__init__.pyc ===
<Binary-ish file>
=== Added File zopeproducts/zwiki/add.pt ===
<html metal:use-macro="views/standard_macros/dialog">
<body>
<div metal:fill-slot="body">
<form action="action.html" method="POST">
<table class="TypeListing" cellpadding="3">
<caption>Add Content</caption>
<tbody tal:repeat="info view/addingInfo">
<tr>
<td class="Selector">
<input type="radio" name="type_name"
tal:attributes="value info/action; id info/action" />
</td>
<td class="TypeName">
<label style="font-weight: bold;"
tal:attributes="for info/action">
<span tal:replace="info/title" >Folder</span>
</label>
<div class="TypeDescription" tal:content="info/description">
Folders are generic containers for content, including other
folders.
</div>
</td>
</tr>
</tbody>
<tbody tal:condition="nothing">
<tr>
<td class="Selector">
<input type="radio" name="type_name" value="" />
</td>
<td class="TypeName">
<img alt="Folder" src="../../ZMI/www/document_icon.gif" />
Document
</td>
</tr>
<tr>
<td class="Selector"><br /></td>
<td class="TypeDescription">
Documents are simple textual content.
</td>
</tr>
</tbody>
<tr>
<td><br/></td>
<td>
<input type="text" name="id"
tal:condition="view/namesAccepted"
tal:attributes="value request/id | nothing"
/>
<input type="submit" value=" Add " />
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
=== Added File zopeproducts/zwiki/browser.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Browser View Components for Wikis
$Id: browser.py,v 1.1 2003/04/05 20:50:02 srichter Exp $
"""
import re
from urllib import quote, unquote
from zope.app.browser.container.adding import Adding
from zope.app.traversing import getParent, getPath, objectName
urlchars = r'[A-Za-z0-9/:@_%~#=&\.\-\?\+\$,]+'
urlendchar = r'[A-Za-z0-9/]'
url = r'["=]?((about|gopher|http|https|ftp|mailto|file):%s)' %urlchars
bracketedexpr = r'\[([^\n\]]+)\]'
protectedLine = r'(?m)^!(.*)$'
U = 'A-Z\xc0-\xdf'
L = 'a-z\xe0-\xff'
b = '(?<![%s0-9])' % (U+L)
wikiname1 = r'(?L)%s[%s]+[%s]+[%s][%s]*[0-9]*' % (b,U,L,U,U+L)
wikiname2 = r'(?L)%s[%s][%s]+[%s][%s]*[0-9]*' % (b,U,U,L,U+L)
wikilink = r'!?(%s|%s|%s|%s)' % (wikiname1,wikiname2,bracketedexpr,url)
localwikilink = r'!?(%s|%s|%s)' % (wikiname1, wikiname2, bracketedexpr)
interwikilink = r'!?((?P<local>%s):(?P<remote>%s))' % \
(localwikilink, urlchars+urlendchar)
class WikiAdding(Adding):
"""Custom adding view for NewsSite objects."""
menu_id = "add_wiki"
class ViewWikiPage:
"""A rendered View of the wiki page."""
def path(self):
"""Get the path of this page."""
return "%s/%s" %(objectName(getParent(self.context)),
objectName(self.context))
def renderWikiLinks(self, source):
"""Add Wiki Links to the source"""
html = str(source)
html = re.sub(protectedLine, self._protectLine, html)
# html = re.sub(interwikilink, self._interwikilinkReplace, html)
html = re.sub(wikilink, self._wikilinkReplace, html)
return html
def render(self):
"""Render the wiki page source."""
html = self.renderWikiLinks(self.context.source)
html = html.replace('\n', '<br/>\n')
return html
def _protectLine(self, match):
return re.sub(wikilink, r'!\1', match.group(1))
def _wikilinkReplace(self, match, allowed=0, state=None, text=''):
# tasty spaghetti regexps! better suggestions welcome ?
"""
Replace an occurrence of the wikilink regexp or one of the
special [] constructs with a suitable hyperlink
To be used as a re.sub repl function *and* get a proper value
for literal context, 'allowed', etc, enclose this function
with the value using 'thunk_substituter'.
"""
# In a literal?
if state is not None:
if within_literal(match.start(1), match.end(1)-1, state, text):
return match.group(1)
# matches beginning with ! should be left alone
if re.match('^!', match.group(0)):
return match.group(1)
m = morig = match.group(1)
wiki = getParent(self.context)
# if it's a bracketed expression,
if re.match(bracketedexpr, m):
# strip the enclosing []'s
m = re.sub(bracketedexpr, r'\1', m)
# extract a (non-url) path if there is one
pathmatch = re.match(r'(([^/]*/)+)([^/]+)', m)
if pathmatch:
path, id = pathmatch.group(1), pathmatch.group(3)
else:
path, id = '', m
# or if there was a path assume it's to some non-wiki
# object and skip the usual existence checking for
# simplicity. Could also attempt to navigate the path in
# zodb to learn more about the destination
if path:
return '<a href="%s%s">%s%s</a>' % (path, id, path, id)
# otherwise fall through to normal link processing
# if it's an ordinary url, link to it
if re.match(url,m):
# except, if preceded by " or = it should probably be left alone
if re.match('^["=]', m): # "
return m
else:
return '<a href="%s">%s</a>' % (m, m)
# it might be a structured text footnote ?
elif re.search(r'(?si)<a name="%s"' % (m),text):
return '<a href="#%s">[%s]</a>' % (m,m)
# a wikiname - if a page (or something) of this name exists, link to it
elif m in wiki:
return '<a href="%s/%s">%s</a>' % (getPath(wiki), quote(m), m)
# otherwise, provide a "?" creation link
else:
return '%s<a href="%s/+/AddWikiPage=%s">?</a>' %(
morig, getPath(wiki), quote(m))
def _interwikilinkReplace(self, match, allowed=0, state=None, text=''):
"""Replace an occurrence of interwikilink with a suitable hyperlink.
To be used as a re.sub repl function *and* get a proper value
for literal context, 'allowed', etc.
"""
# matches beginning with ! should be left alone This is a bit naughty,
# but: since we know this text will likely be scanned with
# _wikilink_replace right after this pass, leave the ! in place for it
# to find. Otherwise the localname will get wiki-linked.
if re.match('^!', match.group(0)):
return match.group(0)
localname = match.group('local')
remotename = match.group('remote') # named groups come in handy here!
# NB localname could be [bracketed]
if re.match(bracketedexpr,localname):
localname = re.sub(bracketedexpr, r'\1', localname)
# look for a RemoteWikiURL definition
if hasattr(self.aq_parent, localname):
localpage = getattr(self.aq_parent,localname)
# local page found - search for "RemoteWikiUrl: url"
m = re.search(remotewikiurl, str(localpage))
if m is not None:
# NB: pages are stored html-quoted XXX eh ? they are ?
# something's not right somewhere.. I have lost my grip on this
# whole quoting issue.
remoteurl = html_unquote(m.group(1))
# we have a valid inter-wiki link
link = '<a href="%s%s">%s:%s</a>' % \
(remoteurl, remotename, localname, remotename)
# protect it from any later wiki-izing passes
return re.sub(wikilink, r'!\1', link)
# otherwise, leave alone
return match.group(0)
=== Added File zopeproducts/zwiki/browser.pyc ===
<Binary-ish file>
=== Added File zopeproducts/zwiki/configure.zcml ===
<zopeConfigure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<content class=".zwiki.Wiki">
<implements interface="zope.app.interfaces.container.IContentContainer" />
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
<factory
id="Wiki"
permission="zope.ManageContent"
title="Wiki"
description="Minimal Wiki Page Container implementation " />
<allow
interface="zope.app.interfaces.services.service.Read"
/>
<require
permission="zope.ManageServices"
interface="zope.app.interfaces.services.service.Write"
/>
<require
permission="zope.View"
interface="zope.app.interfaces.container.IReadContainer"/>
<require
permission="zope.ManageContent"
interface="zope.app.interfaces.container.IWriteContainer"/>
</content>
<content class=".zwiki.WikiPage">
<factory
id="WikiPage"
permission="zope.ManageContent"
title="Wiki Page"
description="A Wiki Page" />
<!-- XXX: This security needs to be improved. -->
<require
permission="zope.View"
interface=".interfaces.IWikiPage"
set_schema=".interfaces.IWikiPage" />
<implements
interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
/>
</content>
<adapter
factory=".zwiki.WikiPageHierarchyAdapter"
provides=".interfaces.IWikiPageHierarchy"
for="zope.app.interfaces.annotation.IAnnotatable" />
<!-- Browser-specific configuration -->
<browser:menu
id="add_wiki"
title="Menu of objects to be added to wikis."/>
<!-- Custom adding view. -->
<browser:view
for=".interfaces.IWiki"
name="+"
class=".browser.WikiAdding"
permission="zope.ManageContent"
allowed_attributes="addingInfo"
menu="zmi_actions"
title="Add"
>
<browser:page name="index.html" template="add.pt" />
<browser:page name="action.html" attribute="action" />
</browser:view>
<browser:menuItem menu="add_content"
for="zope.app.interfaces.container.IAdding"
title="Wiki"
action="Wiki"
description="A simple Wiki."/>
<browser:addform
name="AddWikiPage"
schema=".interfaces.IWikiPage"
label="Add Wiki Page"
content_factory=".zwiki.WikiPage"
permission="zope.ManageContent"
fields="source type"
menu="add_wiki"
title="Wiki Page"/>
<browser:editform
schema=".interfaces.IWikiPage"
label="Change Wiki Page"
name="edit.html"
for=".interfaces.IWikiPage"
permission="zope.ManageContent"
menu="zmi_views"
title="Edit"
fields="source type"/>
<browser:page
name="view.html"
for=".interfaces.IWikiPage"
class=".browser.ViewWikiPage"
template="view_page.pt"
permission="zope.View"
menu="zmi_views"
title="View"/>
<browser:defaultView
name="view.html"
for=".interfaces.IWikiPage"/>
</zopeConfigure>
=== Added File zopeproducts/zwiki/interfaces.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""ZWiki Interface Declarations
This module defines the ZWiki relevant interfaces.
$Id: interfaces.py,v 1.1 2003/04/05 20:50:02 srichter Exp $
"""
from zope.interface import Interface
from zope.schema import Text, TextLine, List
from zope.app.interfaces.container import IContentContainer
class IWiki(IContentContainer):
"""A simple Wiki Page container.
A simple marker interface, so that we can define special views on
Wikis."""
class IWikiPage(Interface):
"""A single Wiki Page content object.
The Wiki page is a simple content object that stores the content
(source) and the source type of the wiki page."""
source = Text(
title=u"Source Text",
description=u"Renderable source text of the Wiki Page.",
default=u"",
required=True)
type = TextLine(
title=u"Source Type",
description=u"Type of the source text, e.g. structured text",
default=u"plain text",
required=True)
def append(source):
"""Append some text to the existing source text."""
def comment(source, user):
"""Comment on the current Wiki; add comment to source."""
class IWikiPageHierarchy(Interface):
"""This interface supports the virtual hierarchical structure of the Wiki
Pages."""
parents = List(
title=u"Wiki Page Parents",
description=u"Parents of a a Wiki",
value_types=(TextLine(title=u"Parent Name",
description=u"Name of the parent wiki page."),),
required=False)
def reparent(parents):
"""Reset the parents the Wiki page belongs to.
The parents attribute is a list of unicode strings that contain the
names of the parent wiki pages.
"""
=== Added File zopeproducts/zwiki/interfaces.pyc ===
<Binary-ish file>
=== Added File zopeproducts/zwiki/view_page.pt ===
<html metal:use-macro="views/standard_macros/page">
<head>
<style metal:fill-slot="style_slot">
</style>
</head>
<body>
<div metal:fill-slot="body">
<h1 tal:content="view/path">Wikis/WikiPage</h1><br/>
<p tal:replace="structure view/render">This is the rendered Wiki</p>
</div>
</body>
</html>
=== Added File zopeproducts/zwiki/zwiki.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Wiki implementation
$Id: zwiki.py,v 1.1 2003/04/05 20:50:02 srichter Exp $
"""
from zope.app.content.folder import Folder
from zope.app.interfaces.annotation import IAnnotations, IAnnotatable
from zopeproducts.zwiki.interfaces import IWiki, IWikiPage, IWikiPageHierarchy
HierarchyKey = 'http://www.zope.org/zwiki#1.0/PageHierarchy/parents'
class Wiki(Folder):
__doc__ = IWiki.__doc__
__implements__ = (IWiki, Folder.__implements__)
class WikiPage:
__doc__ = IWikiPage.__doc__
__implements__ = IWikiPage
# See zopeproducts.zwiki.interfaces.IWikiPage
source = u''
# See zopeproducts.zwiki.interfaces.IWikiPage
type = u'plain text'
def append(self, source):
"See zopeproducts.zwiki.interfaces.IWikiPage"
self.source += source
def comment(self, source, user):
"See zopeproducts.zwiki.interfaces.IWikiPage"
self.append(comment_template %(1, user, source))
class WikiPageHierarchyAdapter:
__doc__ = IWikiPageHierarchy.__doc__
__implements__ = IWikiPageHierarchy
__used_for__ = IAnnotatable
def __init__(self, context):
self.annotations = getAdapter(context, IAnnotations)
data = self.annotations.get(HierarchyKey)
if not data:
self.annotations[HierarchyKey] = []
def reparent(self, parents):
"See zopeproducts.zwiki.interfaces.IWikiPageHierarchy"
self.parents = parents
def setParents(self, parents):
self.annotations[HierarchyKey] = parents
def getParents(self):
return self.annotations[HierarchyKey]
parents = property(getParents, setParents)
comment_template = '''
Comment #%i by %s
%s'''
=== Added File zopeproducts/zwiki/zwiki.pyc ===
<Binary-ish file>