Attachment 'SlideSet-1.0.py'
Download 1 # -*- coding: utf-8 -*-
2 """
3 MoinMoin - SlideSet action Version 1.0, 18.10.2014
4 [a modication of SlideShow action]
5
6 Format a wiki page as a series of slides separated by page breaks
7 for printing as handouts.
8
9 For documentation and examples see:
10
11 http://rileylink.net/moin.cgi/MoinMoin_Matters
12
13 History:
14
15 Version 1.0 - 18.10.2014: initial version.
16
17 @copyright: 2014 Ian Riley <ian@riley.asia>
18 @license: GNU GPL, see COPYING for details.
19
20 Based on SlideShow action
21
22 @copyright: 2005 Jim Clark,
23 2005 Nir Soffer,
24 2008 MoinMoin:ThomasWaldmann,
25 2009 MoinMoin:ReimarBauer
26 @license: GNU GPL, see COPYING for details.
27 """
28
29 import re, time
30
31 from MoinMoin import wikiutil, i18n, error
32 from MoinMoin.Page import Page
33
34 Dependencies = ['language']
35
36
37 class Error(error.Error):
38 """ Raised for errors in this module """
39
40 # This could be delivered in a separate plugin, but
41 # it is more convenient to have everything in one module.
42
43 class WikiSlideParser(object):
44 """ Parse slides using wiki format
45
46 Typical usage::
47 for title, start, end in WikiSlideParser().parse(text):
48 slides.append((title, start, end))
49
50 If you want to override this parser, you can add 'slideshow_wiki'
51 parser plugin, that provides a SlideParser class.
52 """
53 _heading_pattern = re.compile(r"""
54 # TODO: check, mhz found bug here
55 (?P<skip>{{{(?:.*\n)+?}}}) |
56 # Match headings level 1
57 (?P<heading>^=\s(?P<text>.*)\s=$\n?)
58 """, re.MULTILINE | re.UNICODE | re.VERBOSE)
59
60 def parse(self, text):
61 """ Parse slide data in text
62
63 Wiki slides are defined by the headings, ignoring the text
64 before the first heading. This parser finds all headings,
65 skipping headings in preformatted code areas.
66
67 Returns an iterator over slide data. For each slide, a tuple
68 (title, bodyStart, bodyEnd) is returned. bodyStart and bodyEnd
69 are indexes into text.
70 """
71 matches = [match for match in self._heading_pattern.finditer(text)
72 if match.start('skip') == -1]
73
74 for i in range(len(matches)):
75 title = matches[i].group('text').strip()
76 bodyStart = matches[i].end('heading')
77 try:
78 bodyEnd = matches[i + 1].start('heading')
79 except IndexError:
80 bodyEnd = len(text)
81 yield title, bodyStart, bodyEnd
82
83
84 class SlidePage(Page):
85 """ A wiki page containing a slideshow
86
87 The slides are parsed according to the page #format xxx processing
88 instruction. This module implements only a wiki format slide parser.
89
90 To support other formats like rst, add a 'slideshow_rst' parser
91 plugin, providing SlideParser class, implementing the SlideParser
92 protocol. See WikiSlideParser for details.
93 """
94 defaultFormat = 'wiki'
95 defaultParser = WikiSlideParser
96
97 def __init__(self, request, name, **keywords):
98 Page.__init__(self, request, name, **keywords)
99 self._slideIndex = None
100 self.counter = ''
101 self.slide_set = ''
102
103 def __len__(self):
104 """ Return the slide count """
105 return len(self.slideIndex())
106
107 def isEmpty(self):
108 return len(self) == 0
109
110 # Slide accessing methods map 1 based slides to 0 based index.
111
112 def titleAt(self, number):
113 """ Return the title of slide number """
114 try:
115 return self.slideIndex()[number - 1][0]
116 except IndexError:
117 return 1
118
119 def bodyAt(self, number):
120 """ Return the body of slide number """
121 try:
122 start, end = self.slideIndex()[number - 1][1:]
123 return self.get_raw_body()[start:end]
124 except IndexError:
125 return self.get_raw_body()
126
127 # Private ----------------------------------------------------------------
128
129 def slideIndex(self):
130 if self._slideIndex is None:
131 self.parseSlides()
132 return self._slideIndex
133
134 def parseSlides(self):
135 body = self.get_raw_body()
136 self._slideIndex = []
137 parser = self.createSlideParser()
138 for title, bodyStart, bodyEnd in parser.parse(body):
139 self._slideIndex.append((title, bodyStart, bodyEnd))
140
141 def createSlideParser(self):
142 """ Import plugin and return parser class
143
144 If plugin is not found, and format is not defaultFormat, raise an error.
145 For defaultFormat, use builtin defaultParser in this module.
146 """
147 format = self.pi['format']
148 plugin = 'slideshow_' + format
149 try:
150 Parser = wikiutil.importPlugin(self.request.cfg, 'parser', plugin, 'SlideParser')
151 except wikiutil.PluginMissingError:
152 if format != self.defaultFormat:
153 raise Error('SlideShow does not support %s format.' % format)
154 Parser = self.defaultParser
155 return Parser()
156
157
158 class SlideshowAction:
159
160 name = 'SlideShow'
161 maxSlideLinks = 15
162
163 def __init__(self, request, pagename, template):
164 self.request = request
165 self.page = SlidePage(self.request, pagename)
166 self.slide_template = slide_template
167 self.set_template = set_template
168
169 # Cache values used many times
170 self.pageURL = self.page.url(request)
171
172 def execute(self):
173 _ = self.request.getText
174 try:
175 #self.setSlideNumber()
176 language = self.page.pi['language']
177 self.request.setContentLanguage(language)
178 for s in range(self.last_slide()):
179 self.slideNumber = s + 1
180 self.page.slide_set += self.slide_template % self
181 self.request.write(self.set_template % self)
182 except Error, err:
183 self.request.theme.add_msg(unicode(err), "error")
184 self.page.send_page()
185
186 # Private ----------------------------------------------------------------
187
188 def createParser(self, format, text):
189 if format == "wiki":
190 format = 'text_moin_wiki'
191 try:
192 Parser = wikiutil.importPlugin(self.request.cfg, 'parser', format,
193 'Parser')
194 except wikiutil.PluginMissingError:
195 from MoinMoin.parser.text import Parser
196 parser = Parser(text, self.request)
197 return parser
198
199 def createFormatter(self, format):
200 try:
201 Formatter = wikiutil.importPlugin(self.request.cfg, 'formatter',
202 format, 'Formatter')
203 except wikiutil.PluginMissingError:
204 from MoinMoin.formatter.text_plain import Formatter
205
206 formatter = Formatter(self.request)
207 self.request.formatter = formatter
208 formatter.page = self.page
209 return formatter
210
211 def languageAttributes(self, lang):
212 return ' lang="%s" dir="%s"' % (lang, i18n.getDirection(lang))
213
214 def last_slide(self):
215 return max(len(self.page), 1)
216
217 # Replacing methods ------------------------------------------------------
218
219 def __getitem__(self, name):
220 item = getattr(self, 'item_' + name)
221 if callable(item):
222 return item()
223 else:
224 return item
225
226 def item_language_attribtues(self):
227 return self.languageAttributes(self.request.content_lang)
228
229 def item_theme_url(self):
230 return '%s/%s' % (self.request.cfg.url_prefix_static, self.request.theme.name)
231
232 item_action_name = name
233
234 def item_logo(self):
235 return wikiutil.escape(self.request.getPragma('logo', defval='[ir].png'))
236
237 def item_title(self):
238 return wikiutil.escape(self.page.page_name)
239
240 def item_slide_title(self):
241 return wikiutil.escape(self.page.titleAt(self.slideNumber))
242
243 def item_slide_body(self):
244 text = self.page.bodyAt(self.slideNumber)
245 format = self.page.pi['format']
246 parser = self.createParser(format, text)
247 formatter = self.createFormatter('text_html')
248 return self.request.redirectedOutput(parser.format, formatter)
249
250 def item_date(self):
251 return wikiutil.escape(self.request.getPragma('date', defval=''))
252
253 def item_author(self):
254 return wikiutil.escape(self.request.getPragma('author', defval=''))
255
256 def item_logo(self):
257 return wikiutil.escape(self.request.getPragma('logo', defval='[ir].png'))
258
259 def item_counter(self):
260 return "%d|%d" % (self.slideNumber, self.last_slide())
261
262 def item_slide_set(self):
263 return self.page.slide_set
264
265 # This is quite stupid template, but it cleans most of the code from
266 # html. With smarter templates, there will be no html in the action code.
267
268 slide_template = """
269 <div id="slide"><h1>%(slide_title)s</h1>
270 <div id="content">%(slide_body)s</div>
271 <div id="slide_footer">
272 <span id="slide_date">%(date)s</span>
273 <span id="slide_author">%(author)s</span>
274 <span id="slide_counter">%(counter)s</span>
275 </div>
276 </div>"""
277
278 set_template = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
279 "http://www.w3.org/TR/html4/strict.dtd">
280 <html%(language_attribtues)s>
281 <head>
282 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
283 <meta name="robots" content="noindex,nofollow">
284 <title>%(title)s</title>
285 <STYLE TYPE="text/css" CHARSET="utf-8" MEDIA="all">
286 <!--
287 @import url(%(theme_url)s/css/%(action_name)s.css);
288 body {
289 margin: 0;
290 padding: 0;
291 }
292 h1:before {content:url(%(theme_url)s/../common/%(logo)s);
293 padding-right:10px; display: inline-block; vertical-align: middle;
294 }
295 -->
296 </STYLE>
297 </head>
298 <body>%(slide_set)s
299 </body>
300 </html>"""
301
302 def execute(pagename, request):
303 """ Glue to current plugin system """
304 SlideshowAction(request, pagename, set_template).execute()
You are not allowed to attach a file to this page.