2 The Wiki module primarily exports the `WikiPage` class:
6 from docutils
import core
, io
7 from docutils
import readers
9 __all__
= ['WikiPage', 'allPages', 'recentPages',
10 'searchTitles', 'search', 'css']
12 ## All the Wiki pages will be kept in this directory:
13 pageDir
= '/usr/home/ianb/w/pypaper/pages/'
15 class WikiPage(object):
17 WikiPage is a class to represent one page in a WikiWikiWeb [#]_.
18 The page may or may not yet exist -- that is, it may not yet
21 .. [#] http://c2.com/cgi-bin/wiki
23 It has the following properties and methods:
26 A read-only property giving the HTML for the page.
27 If the page does not yet have content the text
28 ``"This page has not yet been created"`` is returned.
30 The text for the page. To save new text, simply
31 assign to this property.
33 The title of the page.
35 The name of the page -- a canonical identifier.
36 Related to the title, but not necessarily the
45 def __init__(self
, pageName
):
47 Each page has a name, which is a unique identifier, for example
48 ``"FrontPage"``, which identifies the page in the URL and
56 Returns the base path (sans extension) for this page
58 return _basePath(self
.name
)
60 basePath
= property(basePath
)
63 """Does this page have content yet?"""
64 return _exists(self
.name
)
67 """Returns text of HTML for page (HTML fragment only)"""
69 html
= open(self
.basePath
+ ".html").read()
70 html
= self
._subWikiLinks
(html
)
73 return 'This page has not yet been created.'
77 def preview(self
, text
):
78 """Returns an HTML preview of the text"""
79 return self
._subWikiLinks
(self
._convertText
(text
))
81 _wikiLinkRE
= re
.compile(r
'(<a [^>]* href=")!(.*?)("[^>]*>)(.*?)(</a>)',
84 def _subWikiLinks(self
, text
):
85 return self
._wikiLinkRE
.sub(self
._subLink
, ' %s ' % text
)
87 def _subLink(self
, match
):
88 if _exists(match
.group(2)):
89 return match
.group(1) + match
.group(2) + match
.group(3) + match
.group(4) + match
.group(5)
91 return '<span class="nowiki">%s%s%s%s?%s</span>' \
92 % (match
.group(4), match
.group(1), match
.group(2),
93 match
.group(3), match
.group(5))
97 The text of the page. ReStructuredText is used, though the
98 parsing is internal to the module. You can assign to this
99 property to save new text for the page.
102 return open(self
.basePath
+ ".txt").read()
106 def setText(self
, text
):
107 """Sets the text for the page (and updates cached HTML at the
109 f
= open(self
.basePath
+ ".txt", 'w')
112 f
= open(self
.basePath
+ ".html", 'w')
113 f
.write(self
._convertText
(text
))
116 def _convertText(self
, text
):
117 return self
._cleanHTML
(core
.publish_string(
120 parser_name
='restructuredtext',
123 def _cleanHTML(self
, html
):
124 return html
[html
.find('<body>'):html
.find('</body>')]
126 text
= property(text
, setText
)
128 def searchMatches(self
, text
):
132 return self
.searchTitleMatches(text
) \
133 or self
.text().lower().find(text
.lower()) != -1
135 def searchTitleMatches(self
, text
):
139 return self
.title().lower().find(text
.lower()) != -1
141 def modifiedDate(self
):
142 """Date modified (integer timestamp)"""
143 return os
.stat(self
.basePath
+ ".txt").st_mtime
145 modifiedDate
= property(modifiedDate
)
147 def modifiedDateText(self
):
148 """Text representation of modified date"""
149 return time
.strftime("%a %m/%d/%y", time
.gmtime(self
.modifiedDate()))
151 modifiedDateText
= property(modifiedDateText
)
157 title
= property(title
)
160 Methods for searching the wiki pages:
164 """All pages with content in the system"""
165 return [WikiPage(page
[:-4])
166 for page
in os
.listdir(pageDir
)
167 if page
.endswith('.txt')]
170 """All pages, sorted by date modified, most recent first"""
172 pages
.sort(lambda a
, b
: cmp(b
.modifiedDate(), a
.modifiedDate()))
175 def searchTitles(text
):
176 """Search page titles for ``text``, returning list of pages"""
177 return [page
for page
in allPages()
178 if page
.searchTitleMatches(text
)]
181 """Search titles and bodies of pages for ``text``, returning list
183 return [page
for page
in allPages()
184 if page
.searchMatches(text
)]
188 return os
.path
.join(pageDir
, name
)
191 return os
.path
.exists(_basePath(name
) + ".html")
194 There is one module global to be printed at the top of
198 The HTML to put the proper CSS at the top of the page. This
199 should be put in the ``<head>`` section of the page.
203 f
= open('default.css')
207 css
= '<style type="text/css">\n%s</style>\n' % f
.read()
210 ########################################
211 ## reST-specific stuff
212 ########################################
215 from docutils
import nodes
216 from docutils
.readers
import standalone
217 from docutils
.transforms
import Transform
219 class WikiLinkResolver(nodes
.SparseNodeVisitor
):
222 def visit_reference(self
, node
):
223 if node
.resolved
or not node
.hasattr('refname'):
225 refname
= node
['refname']
227 node
['class'] = 'wiki'
228 # I put a ! here to distinguish Wiki links from other
229 # links -- Wiki links have to be fixed up at view time,
230 # to distinguish between dangling and resolved Wiki
232 node
['refuri'] = '!' + refname
235 class WikiLink(Transform
):
238 default_priority
= 800
241 visitor
= WikiLinkResolver(self
.document
)
242 self
.document
.walk(visitor
)
244 class Reader(standalone
.Reader
):
247 supported
= standalone
.Reader
.supported
+ ('wiki',)
249 def get_transforms(self
):
250 return standalone
.Reader
.get_transforms(self
) + [WikiLink
]