[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>