[Zope3-checkins] CVS: zopeproducts/zwiki/browser - __init__.py:1.1 add.pt:1.1 comment_page.pt:1.1 configure.zcml:1.1 parents_page.pt:1.1 view_page.pt:1.1 wiki.py:1.1 wiki_icon.gif:1.1 wiki_toc.pt:1.1 wikipage.py:1.1 wikipage_icon.gif:1.1

Stephan Richter srichter@cbu.edu
Wed, 9 Apr 2003 17:47:18 -0400


Update of /cvs-repository/zopeproducts/zwiki/browser
In directory cvs.zope.org:/tmp/cvs-serv14209/browser

Added Files:
	__init__.py add.pt comment_page.pt configure.zcml 
	parents_page.pt view_page.pt wiki.py wiki_icon.gif wiki_toc.pt 
	wikipage.py wikipage_icon.gif 
Log Message:
Whee, this is a big structural change. I am making this the last location
chnage for Wiki and WikiPage, so that people can start using zwiki for 
Zope 3 for their sites. Before the next structural change, I will provide
tools to import and export the data in XML without loss of information.

Here are the changes:

- Created browser directory and moved everything browser-related in there.

- Moved Wiki and WikiPage broswer code into separate files. 

- Added 'wiki' skin.

- Moved Wiki and WikiPage content objects into their own files.

- Adjusted tests and configuration to reflect this change.


Okay, back to working on the stylesheet stuff. :))



=== Added File zopeproducts/zwiki/browser/__init__.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 Views for the zwiki for Zope 3 Product

$Id: __init__.py,v 1.1 2003/04/09 21:47:16 srichter Exp $
"""


=== Added File zopeproducts/zwiki/browser/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/comment_page.pt ===
<html metal:use-macro="views/standard_macros/page">
  <head>
    <style metal:fill-slot="style_slot">
    </style>
  </head>
  <body i18n:domain="wiki">
    <div metal:fill-slot="body">

      <form action="addComment.html" method="post">

        <table cellspacing="0" cellpadding="2" border="0">
          <tr>
            <td i18n:translate="">Comment</td>
            <td>
	      <textarea name="comment" cols="60" rows="10" />
            </td>
          </tr>
        </table>
        <input type="submit" name="submit" value="Submit" 
	       i18n:attributes="value submit-button" />

      </form>

    </div>
  </body>
</html>


=== Added File zopeproducts/zwiki/browser/configure.zcml ===
<zopeConfigure
   xmlns="http://namespaces.zope.org/zope"
   xmlns:browser="http://namespaces.zope.org/browser">

<include package=".skin" />

  <!-- Browser-specific configuration -->

  <browser:menu
       id="add_wiki"
       title="Menu of objects to be added to wikis."/>

  <!-- Custom adding view.  -->
  <browser:view
      for="zopeproducts.zwiki.interfaces.IWiki"
      name="+"
      class=".wiki.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:page
      name="toc.html"
      for="zopeproducts.zwiki.interfaces.IWiki"
      class=".wiki.TableOfContents"
      template="wiki_toc.pt"
      permission="zopeproducts.zwiki.ViewWikiPage"
      menu="zmi_views"
      title="TOC"/>


  <browser:menuItem menu="add_content"
      for="zope.app.interfaces.container.IAdding"
      title="Wiki"
      action="Wiki"
      description="A simple Wiki."/>

  <browser:icon
      name="zmi_icon"
      for="zopeproducts.zwiki.interfaces.IWiki"
      file="wiki_icon.gif"
      />

  <!-- WikiPage browser configuration -->

  <browser:addform
      label="Add Wiki Page"
      name="AddWikiPage"
      schema="zopeproducts.zwiki.interfaces.IWikiPage"
      content_factory="zopeproducts.zwiki.wiki.WikiPage"
      permission="zopeproducts.zwiki.AddWikiPage"
      fields="source type"
      class=".wikipage.EditWikiPage"
      menu="add_wiki"
      title="Wiki Page"/>

  <browser:editform
      schema="zopeproducts.zwiki.interfaces.IWikiPage"
      for="zopeproducts.zwiki.interfaces.IWikiPage"
      label="Change Wiki Page"
      name="edit.html"
      permission="zopeproducts.zwiki.EditWikiPage"
      fields="source type"
      class=".wikipage.EditWikiPage"
      menu="zmi_views" title="Edit" />

  <browser:pages
      for="zopeproducts.zwiki.interfaces.IWikiPage"
      class=".wikipage.ViewWikiPage"
      permission="zopeproducts.zwiki.ViewWikiPage">
      <browser:page name="view.html" template="view_page.pt"
          menu="zmi_views" title="View" />
      <browser:page name="jumpto.html" attribute="jumpTo" />
  </browser:pages>

  <browser:pages
      for="zopeproducts.zwiki.interfaces.IWikiPage"
      class=".wikipage.EditWikiParents"
      permission="zopeproducts.zwiki.ReparentWikiPage">
      <browser:page name="parents.html" template="parents_page.pt"
          menu="zmi_views" title="Parents" />
      <browser:page name="setParents.html" attribute="setParents" />
  </browser:pages>

  <browser:pages
      for="zopeproducts.zwiki.interfaces.IWikiPage"
      class=".wikipage.WikiPageComment"
      permission="zopeproducts.zwiki.CommentWikiPage">
      <browser:page name="commentForm.html" template="comment_page.pt"
          menu="zmi_views" title="Add Comment" />
      <browser:page name="addComment.html" attribute="comment" />
  </browser:pages>

  <browser:defaultView
      name="view.html"
      for="zopeproducts.zwiki.interfaces.IWikiPage"/>

  <browser:icon
      name="zmi_icon"
      for="zopeproducts.zwiki.interfaces.IWikiPage"
      file="wikipage_icon.gif"
      />

<browser:page
    name="_traverse" 
    for="zopeproducts.zwiki.interfaces.IWikiPage"
    class="zopeproducts.zwiki.traversal.WikiPageTraverser" 
    permission="zope.Public" />

</zopeConfigure>


=== Added File zopeproducts/zwiki/browser/parents_page.pt ===
<html metal:use-macro="views/standard_macros/page">
  <head>
    <style metal:fill-slot="style_slot">
    </style>
  </head>
  <body i18n:domain="wiki">
    <div metal:fill-slot="body">

      <form action="setParents.html" method="post">

        <table cellspacing="0" cellpadding="2" border="0">
          <tr>
            <td i18n:translate="">Parents</td>
            <td>
	      <select name="parents:list" multiple="">
                  <div tal:repeat="parent view/availableWikis" tal:omit-tag="">
                <option tal:content="parent" selected=""
                        tal:condition="python: parent in view.parents()">
                  Wiki1
                </option>
                <option tal:content="parent"
                        tal:condition="python: parent not in view.parents()">
                  Wiki1
                </option>
                </div>
              </select>
            </td>
          </tr>
        </table>
        <input type="submit" name="submit" value="Reparent" 
               i18n:attributes="value reparent-button" />

      </form>

      <h3 i18n:translate="">Branch</h3>

      <p tal:replace="structure view/branch" />

    </div>
  </body>
</html>


=== Added File zopeproducts/zwiki/browser/view_page.pt ===
<html metal:use-macro="views/standard_macros/page">
  <head>
    <style metal:fill-slot="style_slot">
    </style>
  </head>
  <body i18n:domain="wiki">
    <div metal:fill-slot="body">


      <div id="wikipage_header">
        <div id="wikipage_path" 
           tal:content="structure view/breadcrumbs">Wikis/WikiPage
        </div>
        <div id="wikipage_info">Last modified by 
          <b tal:content="view/author">srichter</b> on
          <span tal:replace="view/modified">March 4, 2002.</span>
        </div>
      </div>

      <div tal:replace="structure view/render">
        This is the rendered Wiki
      </div>

      <form action="jumpto.html">
      <div class="box" id="jumpto">
        <div class="body">
          <span i18n:translate="">Jump to:</span><input
            type="text" name="jumpto"/>
        </div>
      </div>
      </form>

    </div>
  </body>
</html>


=== Added File zopeproducts/zwiki/browser/wiki.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: wiki.py,v 1.1 2003/04/09 21:47:16 srichter Exp $
"""
from zope.component import getAdapter
from zope.proxy.context import ContextWrapper
from zope.app.traversing import objectName
from zope.app.browser.container.adding import Adding


class WikiAdding(Adding):
    """Custom adding view for NewsSite objects."""
    menu_id = "add_wiki"


class TableOfContents:
    """Table of contents for a Wiki"""

    def toc(self):
        """Generate a table of contents."""
        children = []

        for name, page in self.context.items():
            wrapped = ContextWrapper(page, self.context, name=name)
            hier = getAdapter(wrapped, IWikiPageHierarchy)
            if hier.getParents() == ():
                children.append((wrapped, hier.findChildren())) 
        return self._branchHTML(children)

    def _branchHTML(self, children):
        html = '<ul>\n'
        for child, subs in children:
            html += ' <li><a href="%s">%s</a></li>\n' %(objectName(child),
                                                        objectName(child))
            if subs:
                html += self._branchHTML(subs)
        html += '</ul>\n'
        return html


=== Added File zopeproducts/zwiki/browser/wiki_icon.gif ===
  <Binary-ish file>

=== Added File zopeproducts/zwiki/browser/wiki_toc.pt ===
<html metal:use-macro="views/standard_macros/page">
  <head>
    <style metal:fill-slot="style_slot">
    </style>
  </head>
  <body i18n:domain="wiki">
    <div metal:fill-slot="body">

      <h1 i18n:translate="">Wiki Table of Contents</h1>

      <p tal:replace="structure view/toc">This is a table of contents.</p>

    </div>
  </body>
</html>


=== Added File zopeproducts/zwiki/browser/wikipage.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 WikiPages

$Id: wikipage.py,v 1.1 2003/04/09 21:47:16 srichter Exp $
"""
import re
from urllib import quote, unquote

from zope.app.interfaces.dublincore import ICMFDublinCore

from zope.component import getAdapter, getView, getService, createObject
from zope.proxy.context import ContextWrapper
from zope.app.browser.form.widget import ListWidget
from zope.app.form.widget import CustomWidget
from zope.app.traversing import getParent, getPath, objectName

from zopeproducts.zwiki.interfaces import IWikiPageHierarchy

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 SourceTypeWidget(ListWidget):

    size = 1

    def renderItems(self, value):
        name = self.name
        # get items
        types = getService(self.context, "WikiSourceTypeRegistry")
        items = types.getAllTitles()

        # check if we want to select first item
        if (not value and getattr(self.context, 'firstItem', False)
            and len(items) > 0):
            value = items[0]

        cssClass = self.getValue('cssClass')

        rendered_items = []
        count = 0
        for item_value in items:
            item_text = self.textForValue(item_value)

            if item_value == value:
                rendered_item = self.renderSelectedItem(
                    count, item_text, item_value, name, cssClass)
            else:
                rendered_item = self.renderItem(
                    count, item_text, item_value, name, cssClass)

            rendered_items.append(rendered_item)
            count += 1

        return rendered_items


class EditWikiPage(object):

    type = CustomWidget(SourceTypeWidget)


class ViewWikiPage:
    """A rendered View of the wiki page."""

    def breadcrumbs(self):
        """Get the path of this page."""
        hier = getAdapter(self.context, IWikiPageHierarchy)
        path = hier.path()
        html = []
        for page in path:
            html.append('<a href="%s">%s</a>' %(getPath(page),
                                                objectName(page)))
        return ' / '.join(html)

    def author(self):
        """Get user who last modified the Wiki Page."""
        creators = getAdapter(self.context, ICMFDublinCore).creators
        if not creators:
            return 'unknown'
        return creators[0]

    def modified(self):
        """Get last modification date."""
        date = getAdapter(self.context, ICMFDublinCore).modified
        if date is None:
            date = getAdapter(self.context, ICMFDublinCore).created
        formatter = self.request.locale.getDateTimeFormatter('medium')
        return formatter.format(date)

    def jumpTo(self, jumpto):
        """Try to get quickly to another Wiki page"""
        wiki = getParent(self.context)
        if jumpto in wiki:
            return self.request.response.redirect(getPath(wiki)+'/'+jumpto)
        else:
            return self.request.response.redirect('.')

    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."""
        types = getService(self.context, "WikiSourceTypeRegistry")
        source = types.createObject(self.context.type,
                                    self.context.source)
        view = getView(source, None, self.request)
        html = view.render(self.context)
        html = self.renderWikiLinks(html)
        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)


class EditWikiParents:

    def parents(self):
        hier = getAdapter(self.context, IWikiPageHierarchy)
        return hier.parents

    def availableWikis(self):
        wiki = getParent(self.context)
        return wiki.keys()

    def setParents(self, parents):
        hier = getAdapter(self.context, IWikiPageHierarchy)
        hier.reparent(parents)
        return self.request.response.redirect('./@@parents.html')

    def _branchHTML(self, children):
        html = '<ul>\n'
        for child, subs in children:
            html += ' <li><a href="../%s">%s</a></li>\n' %(objectName(child),
                                                           objectName(child))
            if subs:
                html += self._branchHTML(subs)
        html += '</ul>\n'
        return html

    def branch(self):
        hier = getAdapter(self.context, IWikiPageHierarchy)
        children = hier.findChildren()
        return self._branchHTML(children)


class WikiPageComment:

    def comment(self, comment):
        types = getService(self.context, "WikiSourceTypeRegistry")
        source = types.createObject(self.context.type, self.context.source)
        view = getView(source, None, self.request)
        comment = view.createComment(comment, self.context.getCommentCounter())
        self.context.comment(comment)
        return self.request.response.redirect('.')




=== Added File zopeproducts/zwiki/browser/wikipage_icon.gif ===
  <Binary-ish file>