What about WikiWords?

Our wiki doesn’t yet have a way to link pages.

A “WikiWord” is a word that starts with an uppercase letter, has a collection of lowercase letters and numbers followed by another uppercase letter and more letters and numbers (sometimes described as WordsSmashedTogether). A typical wiki will automatically create links for WikiWords when it finds them. This sounds like a job for a regular expression.

Here’s the new version of root.py, which will be explained afterwards:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
"""Main Controller"""
from wiki20.lib.base import BaseController
from tg import expose, flash, require, url, request, redirect
from pylons.i18n import ugettext as _, lazy_ugettext as l_
from tg import redirect, validate
from wiki20.model import DBSession, metadata
from wiki20.controllers.error import ErrorController
from wiki20.model.page import Page
import re
from docutils.core import publish_parts

wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")

class RootController(BaseController):
    error = ErrorController()

    @expose('wiki20.templates.page')
    def default(self, pagename="FrontPage"):
        page = DBSession.query(Page).filter_by(pagename=pagename).one()
        content = publish_parts(page.data, writer_name="html")["html_body"]
        root = url('/')
        content = wikiwords.sub(r'<a href="%s\1">\1</a>' % root, content)
        return dict(content=content, wikipage=page)

    @expose(template="wiki20.templates.edit")
    def edit(self, pagename):
        page = DBSession.query(Page).filter_by(pagename=pagename).one()
        return dict(wikipage=page)

    @expose('wiki20.templates.about')
    def about(self):
        return dict(page='about')


    @expose()
    def save(self, pagename, data, submit):
        page = DBSession.query(Page).filter_by(pagename=pagename).one()
        page.data = data
        redirect("/" + pagename)

9-10: we include two more imports: re for regular expressions and a method called publish_parts from docutils.

12: the wikiwords regular expression describes a WikiWord.

19: In default, the new material begins here with the use of publish_parts, a utility that takes string input and returns a dictionary of document parts after performing conversions; here converting the data field of the FrontPage record from Restructured Text to HTML (specified by writer_name="html"). Selecting the fragment part produces the document without the document title, subtitle, docinfo, header, or footer.

21: You can configure TurboGears so that it doesn’t live at the root of a site. That way you can combine multiple TurboGears apps on a single server. We use tg.url() to create relative links so that they will continue to work regardless of how many apps you’re running.

22: rewrites the string content by finding any WikiWords and substituting hyperlinks for those WikiWords. That way when you click on a WikiWord, it will take you to that page. The r'string' means ‘raw string’, one that turns off escaping, which is mostly used in regular expression strings to prevent you from having to double escape slashes. The substitution may look a bit weird, but is more understandable if you recognize that the %s gets substituted with root, then each occurrence of the \1 is replaced with the string matching the regex.

23: Note that default() is now returning a dict containing an additional key-value pair: content=content. This will not break wiki20.templates.page because that page is only looking for page in the dictionary, however if we want to do something interesting with the new key-value pair we’ll need to edit wiki20.templates.page:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!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"
    xmlns:py="http://genshi.edgewall.org/"
    xmlns:xi="http://www.w3.org/2001/XInclude">

    <xi:include href="master.html" />

    <head>
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
        <title>${wikipage.pagename} - The TurboGears 2 Wiki</title>
    </head>

    <body>
        <div class="main_content">
            <div style="float:right; width: 10em;"> Viewing
                <span py:replace="wikipage.pagename">Page Name Goes Here</span>
                <br/>
                You can return to the <a href="/">FrontPage</a>.
            </div>
            <div py:replace="XML(content)">Formatted content goes here.</div>
            <a href="/edit/${wikipage.pagename}">Edit this page</a>
        </div>
    </body>
</html>

21: Genshi defaults to XML: since content comes through as XML, we strip it off using the XML() function to produce plain text (try removing the function call to see what happens).

To test the new version of the system, edit the data in your front page to include a WikiWord. When the page is displayed, you’ll see that it’s now a link. You probably won’t be surprised to find that clicking that link produces an error.

Previous topic

Editing pages

Next topic

Hey, where’s the page?

This Page