Attachment 'CreatePdfDocument2_1_4.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 __doc__ = """
3 MoinMoin - Generate PDF document using HTMLDOC
4
5 This action script generate PDF documents from a Wiki site using
6 the HTMLDOC (http://www.htmldoc.org) software packages which has
7 to be preinstalled first.
8
9 To use this feature install this script in your's MoinMoin action
10 script plugin directory.
11
12 Thanks goes to Pascal Bauermeister who initiated the implementaion.
13 Lot of things changes since then but the idear using HTMLDOC is the
14 main concept of this implementation.
15
16 @copyright: (C) 2006 Pascal Bauermeister
17 @copyright: (C) 2006-2007 Raphael Bossek
18 @license: GNU GPL, see COPYING for details
19 """
20
21 __version__ = u'2.1.4'
22
23 release_information = """
24 2007-09-21 RaphaelBossek
25 * Release v2.1.4
26 * HTMLDOC supports only HTML 4.1 (http://www.htmldoc.org/documentation.php/Elements.html)
27 * Fix for table borders and cell background.
28 * Added support for code blocks (break on page boundries).
29
30 2007-09-18 RaphaelBossek
31 * Release v2.1.3
32 * Added support for scaling images (--browserwidth).
33
34 2007-08-21 RaphaelBossek
35 * Release v2.1.2
36 * Fixed support for python 2.3.
37
38 2007-08-21 RaphaelBossek
39 * Release v2.1.1
40 * Applied speed improvemtn patch from BrianDickman.
41 * Fixed font size values where x.9 was missing.
42 * Some cosmetic changes in the form.
43
44 2007-08-20 RaphaelBossek
45 * Release v2.1.0
46 * Configuration is seperated by tabbs.
47 * Added support for font style and colors.
48 * Fixed save/load of configuration variables within page (may be empty).
49
50 2007-08-17 RaphaelBossek
51 * Release v2.0.11
52 * Added support for alternative title page and title page logo.
53 * Added support for additional fields for the title page author, docnumber
54 and copyright.
55
56 2006-12-18 RaphaelBossek
57 * Release v2.0.10
58 * Improved support for webpage/book styles if the HTML documents does not.
59
60 2006-12-17 RaphaelBossek
61 * Release v2.0.9
62 * Added AUTH_TYPE for RedirectOutputRequest()
63
64 2006-11-16 RaphaelBossek
65 * Release v2.0.8
66 * Fixed another missing configuration for RedirectOutputRequest()
67
68 2006-11-15 RaphaelBossek
69 * Release v2.0.7
70 * Fixed support for MoinMoin 1.5.3
71 * Fixed SSL support.
72
73 2006-11-14 RaphaelBossek
74 * Release v2.0.6
75 * MoinMoin 1.6 support added.
76 * Fixed Windows(TM) platform support.
77 * Added support for alternative title text.
78
79 2006-09-13 RaphaelBossek
80 * Release v2.0.5
81 * Fixed RedirectOutputRequest class where definition of script_name
82 was missing.
83
84 2006-09-12 RaphaelBossek
85 * Release v2.0.4
86 * Fixed RedirectOutputRequest class where function was redifined
87 to boolean value.
88
89 2006-09-06 RaphaelBossek
90 * Release v2.0.3
91 * Fixed FastCGI support by removing stdout redirect output code. The
92 same functionality will be done by the RedirectOutputRequest class.
93 * Renamed to CreatePdfDocument (for better translation possibilities).
94 * Fixed encoding of title page.
95 * Added charset set option.
96 * Fixed waiting for HTMLDOC.
97
98 2006-09-02 RaphaelBossek
99 * Release v2.0.2
100 * Added createpdfdocument_validoptions and createpdfdocument_defaultvalues
101 configuration parameter support. You are not able to preset available
102 options and which defaults are used in your configuration file.
103
104 2006-08-30 RaphaelBossek
105 * Release v2.0.1
106 * Fixed issue with page revision number forwarding (traceback).
107
108 2006-08-30 RaphaelBossek
109 * Release v2.0.0
110 * Feature enchanced and bug fixed version.
111
112 2006-05-26 PascalBauermeister
113 * Release v1.0.2
114 * Relative image URLs turned absolute was bogus. It is less bogus now.
115
116 2006-05-26 PascalBauermeister
117 * Release v1.0.1
118 * Set env var HTMLDOC_NOCGI to solve CGI issue
119
120 2006-05-24 PascalBauermeister
121 * Initial release v1.0.0
122 """
123
124 import os
125 import sys
126 import stat
127 import re
128 import copy
129 import shutil
130 import StringIO
131 import array
132 from MoinMoin import config
133 from MoinMoin import util
134 from MoinMoin import wikiutil
135 from MoinMoin import packages
136 from MoinMoin import error
137 from MoinMoin.Page import Page
138 from MoinMoin.request import RequestBase
139 from MoinMoin.widget.dialog import Dialog
140 from MoinMoin.version import release as moinmoin_release
141
142 # http://www.barelyfitz.com/projects/tabber/
143 tabber_minimized = '''
144 // Version 1.9 stripped by Creativyst SS & JavaScript Compressor v2.2c (http://www.creativyst.com/Prod/3/)
145 function tabberObj(argsObj)
146 { var arg; this.div = null; this.classMain = "tabber"; this.classMainLive = "tabberlive"; this.classTab = "tabbertab"; this.classTabDefault = "tabbertabdefault"; this.classNav = "tabbernav"; this.classTabHide = "tabbertabhide"; this.classNavActive = "tabberactive"; this.titleElements = ['h2','h3','h4','h5','h6']; this.titleElementsStripHTML = true; this.removeTitle = true; this.addLinkId = false; this.linkIdFormat = '<tabberid>nav<tabnumberone>'; for (arg in argsObj) { this[arg] = argsObj[arg];}
147 this.REclassMain = new RegExp('\\\\b' + this.classMain + '\\\\b', 'gi'); this.REclassMainLive = new RegExp('\\\\b' + this.classMainLive + '\\\\b', 'gi'); this.REclassTab = new RegExp('\\\\b' + this.classTab + '\\\\b', 'gi'); this.REclassTabDefault = new RegExp('\\\\b' + this.classTabDefault + '\\\\b', 'gi'); this.REclassTabHide = new RegExp('\\\\b' + this.classTabHide + '\\\\b', 'gi'); this.tabs = new Array(); if (this.div) { this.init(this.div); this.div = null;}
148 }
149 tabberObj.prototype.init = function(e)
150 { var
151 childNodes, i, i2, t, defaultTab=0, DOM_ul, DOM_li, DOM_a, aId, headingElement; if (!document.getElementsByTagName) { return false;}
152 if (e.id) { this.id = e.id;}
153 this.tabs.length = 0; childNodes = e.childNodes; for(i=0; i < childNodes.length; i++) { if(childNodes[i].className &&
154 childNodes[i].className.match(this.REclassTab)) { t = new Object(); t.div = childNodes[i]; this.tabs[this.tabs.length] = t; if (childNodes[i].className.match(this.REclassTabDefault)) { defaultTab = this.tabs.length-1;}
155 }
156 }
157 DOM_ul = document.createElement("ul"); DOM_ul.className = this.classNav; for (i=0; i < this.tabs.length; i++) { t = this.tabs[i]; t.headingText = t.div.title; if (this.removeTitle) { t.div.title = '';}
158 if (!t.headingText) { for (i2=0; i2<this.titleElements.length; i2++) { headingElement = t.div.getElementsByTagName(this.titleElements[i2])[0]; if (headingElement) { t.headingText = headingElement.innerHTML; if (this.titleElementsStripHTML) { t.headingText.replace(/<br>/gi," "); t.headingText = t.headingText.replace(/<[^>]+>/g,"");}
159 break;}
160 }
161 }
162 if (!t.headingText) { t.headingText = i + 1;}
163 DOM_li = document.createElement("li"); t.li = DOM_li; DOM_a = document.createElement("a"); DOM_a.appendChild(document.createTextNode(t.headingText)); DOM_a.href = "javascript:void(null);"; DOM_a.title = t.headingText; DOM_a.onclick = this.navClick; DOM_a.tabber = this; DOM_a.tabberIndex = i; if (this.addLinkId && this.linkIdFormat) { aId = this.linkIdFormat; aId = aId.replace(/<tabberid>/gi, this.id); aId = aId.replace(/<tabnumberzero>/gi, i); aId = aId.replace(/<tabnumberone>/gi, i+1); aId = aId.replace(/<tabtitle>/gi, t.headingText.replace(/[^a-zA-Z0-9\-]/gi, '')); DOM_a.id = aId;}
164 DOM_li.appendChild(DOM_a); DOM_ul.appendChild(DOM_li);}
165 e.insertBefore(DOM_ul, e.firstChild); e.className = e.className.replace(this.REclassMain, this.classMainLive); this.tabShow(defaultTab); if (typeof this.onLoad == 'function') { this.onLoad({tabber:this});}
166 return this;}; tabberObj.prototype.navClick = function(event)
167 { var
168 rVal, a, self, tabberIndex, onClickArgs; a = this; if (!a.tabber) { return false;}
169 self = a.tabber; tabberIndex = a.tabberIndex; a.blur(); if (typeof self.onClick == 'function') { onClickArgs = {'tabber':self, 'index':tabberIndex, 'event':event}; if (!event) { onClickArgs.event = window.event;}
170 rVal = self.onClick(onClickArgs); if (rVal === false) { return false;}
171 }
172 self.tabShow(tabberIndex); return false;}; tabberObj.prototype.tabHideAll = function()
173 { var i; for (i = 0; i < this.tabs.length; i++) { this.tabHide(i);}
174 }; tabberObj.prototype.tabHide = function(tabberIndex)
175 { var div; if (!this.tabs[tabberIndex]) { return false;}
176 div = this.tabs[tabberIndex].div; if (!div.className.match(this.REclassTabHide)) { div.className += ' ' + this.classTabHide;}
177 this.navClearActive(tabberIndex); return this;}; tabberObj.prototype.tabShow = function(tabberIndex)
178 { var div; if (!this.tabs[tabberIndex]) { return false;}
179 this.tabHideAll(); div = this.tabs[tabberIndex].div; div.className = div.className.replace(this.REclassTabHide, ''); this.navSetActive(tabberIndex); if (typeof this.onTabDisplay == 'function') { this.onTabDisplay({'tabber':this, 'index':tabberIndex});}
180 return this;}; tabberObj.prototype.navSetActive = function(tabberIndex)
181 { this.tabs[tabberIndex].li.className = this.classNavActive; return this;}; tabberObj.prototype.navClearActive = function(tabberIndex)
182 { this.tabs[tabberIndex].li.className = ''; return this;}; function tabberAutomatic(tabberArgs)
183 { var
184 tempObj, divs, i; if (!tabberArgs) { tabberArgs = {};}
185 tempObj = new tabberObj(tabberArgs); divs = document.getElementsByTagName("div"); for (i=0; i < divs.length; i++) { if (divs[i].className &&
186 divs[i].className.match(tempObj.REclassMain)) { tabberArgs.div = divs[i]; divs[i].tabber = new tabberObj(tabberArgs);}
187 }
188 return this;}
189 function tabberAutomaticOnLoad(tabberArgs)
190 { var oldOnLoad; if (!tabberArgs) { tabberArgs = {};}
191 oldOnLoad = window.onload; if (typeof window.onload != 'function') { window.onload = function() { tabberAutomatic(tabberArgs);};} else { window.onload = function() { oldOnLoad(); tabberAutomatic(tabberArgs);};}
192 }
193 if (typeof tabberOptions == 'undefined') { tabberAutomaticOnLoad();} else { if (!tabberOptions['manualStartup']) { tabberAutomaticOnLoad(tabberOptions);}
194 }
195 '''
196
197 tabber_minimized_css = '''
198 <style type="text/css">
199 /*--------------------------------------------------
200 REQUIRED to hide the non-active tab content.
201 But do not hide them in the print stylesheet!
202 --------------------------------------------------*/
203 .tabberlive .tabbertabhide {
204 display:none;
205 }
206
207 /*--------------------------------------------------
208 .tabber = before the tabber interface is set up
209 .tabberlive = after the tabber interface is set up
210 --------------------------------------------------*/
211 .tabber {
212 }
213 .tabberlive {
214 margin-top:1em;
215 }
216
217 /*--------------------------------------------------
218 ul.tabbernav = the tab navigation list
219 li.tabberactive = the active tab
220 --------------------------------------------------*/
221 ul.tabbernav
222 {
223 margin:0;
224 padding: 3px 0;
225 border-bottom: 1px solid #778;
226 font: bold 12px Verdana, sans-serif;
227 }
228
229 ul.tabbernav li
230 {
231 list-style: none;
232 margin: 0;
233 display: inline;
234 }
235
236 ul.tabbernav li a
237 {
238 padding: 3px 0.5em;
239 margin-left: 3px;
240 border: 1px solid #778;
241 border-bottom: none;
242 background: #DDE;
243 text-decoration: none;
244 }
245
246 ul.tabbernav li a:link { color: #448; }
247 ul.tabbernav li a:visited { color: #667; }
248
249 ul.tabbernav li a:hover
250 {
251 color: #000;
252 background: #AAE;
253 border-color: #227;
254 }
255
256 ul.tabbernav li.tabberactive a
257 {
258 background-color: #fff;
259 border-bottom: 1px solid #fff;
260 }
261
262 ul.tabbernav li.tabberactive a:hover
263 {
264 color: #000;
265 background: white;
266 border-bottom: 1px solid white;
267 }
268
269 /*--------------------------------------------------
270 .tabbertab = the tab content
271 Add style only after the tabber interface is set up (.tabberlive)
272 --------------------------------------------------*/
273 .tabberlive .tabbertab {
274 padding:5px;
275 border:1px solid #aaa;
276 border-top:0;
277
278 /* If you don't want the tab size changing whenever a tab is changed
279 you can set a fixed height */
280
281 /* height:200px; */
282
283 /* If you set a fix height set overflow to auto and you will get a
284 scrollbar when necessary */
285
286 /* overflow:auto; */
287 }
288
289 /* If desired, hide the heading since a heading is provided by the tab */
290 .tabberlive .tabbertab h2 {
291 display:none;
292 }
293 .tabberlive .tabbertab h3 {
294 display:none;
295 }
296
297 /* Example of using an ID to set different styles for the tabs on the page */
298 .tabberlive#tab1 {
299 }
300 .tabberlive#tab2 {
301 }
302 .tabberlive#tab2 .tabbertab {
303 height:200px;
304 overflow:auto;
305 }
306 </style>
307 '''
308
309 class RedirectOutputRequest(RequestBase):
310 """Redirect output to string without HTTP headers."""
311 def __init__ (self, req, action='print'):
312 """Prepare a compatible request."""
313 # 1.5,1.6:req.path_info = u'/RaphaelBossek/\xd6nologe' | u'/FrontPage'
314 # after enconde() self.path_info = '/RaphaelBossek/\xd6nologe'
315 self.path_info = req.path_info.encode(config.charset)
316 # 1.5,1.6:query_string = req.query_string = u'action=CreatePdfDocument'
317 self.query_string = 'action=' + action
318 if isinstance(self.query_string, unicode):
319 raise UnicodeError('self.query_string can not be of type UNICODE for python 2.3 compatibility reasons.')
320 # 1.5,1.6:request_uri = req.request_uri = u'/FrontPage?action=CreatePdfDocument'
321 self.request_uri = req.path_info.replace(req.query_string, self.query_string)
322 # 1.5,1.6:url = req.url = u'localhost:8080/FrontPage?action=CreatePdfDocument'
323 self.url = req.url.replace(req.query_string, self.query_string)
324 # 1.5,1.6: Not all kinds of request support SSL.
325 if 'is_ssl' in req.__dict__:
326 self.is_ssl = req.is_ssl
327 else:
328 self.is_ssl = 0
329 # 1.5,1.6: Not all kinds of request set env.
330 self.env = {}
331 if 'env' in req.__dict__:
332 # 1.5,1.6: Do not copy env otherwise UNICODE encoding does not work right.
333 #self._setup_vars_from_std_env(req.env)
334 self.env['AUTH_TYPE'] = req.env.get('AUTH_TYPE', '')
335 self.http_host = req.http_host
336 self.http_user_agent = req.http_user_agent
337 self.request_method = None
338 self.saved_cookie = req.saved_cookie
339 self.remote_addr = req.remote_addr
340 self.script_name = getattr (req, u'script_name', u'')
341
342 self.req = req
343 RequestBase.__init__(self)
344
345 def run(self, rev = None):
346 """Start processing the document."""
347 # 1.6:MoinMoin/request/__init__.py: Initialise action from environment variables not from form.
348 self.action = 'print'
349 if rev:
350 self.form[u'rev'] = [rev]
351 self.output_string = u''
352 self.error_string = u''
353 self.sent_headers = False
354 self.failed = 0
355 RequestBase.run(self)
356 return (self.output_string, self.error_string)
357
358 def http_headers (self, *args, **kw):
359 """Used by MoinMoin 1.5.x instead of emit_http_headers()."""
360 self.sent_headers = True
361
362 def emit_http_headers(self, *args, **kw):
363 """Used by MoinMoin 1.6.x instaed of http_headers()."""
364 self.sent_headers = 1
365
366 def fail (self, err):
367 """Catch if a error occurs and save the message in our string."""
368 RequestBase.fail (self, err)
369 if not self.error_string:
370 self.error_string = str(err)
371
372 def write (self, *data):
373 """Catch the document in our output_string."""
374 if self.sent_headers:
375 if self.failed:
376 self.error_string += data[0]
377 else:
378 self.output_string += data[0]
379
380 def flush(self):
381 pass
382
383
384 def attachment_fsname(attachment, page, request):
385 """Return location of attament on the file system. current_page is the relative location
386 where attachment is used.
387 """
388 from MoinMoin.action import AttachFile
389 pagename, filename = AttachFile.absoluteName(attachment, page.page_name)
390 #self.request.log("attachment_link: url %s pagename %s filename %s" % (url, pagename, filename))
391 fname = wikiutil.taintfilename(filename)
392 return AttachFile.getFilename(request, pagename, fname)
393
394
395 def shell_quote(parameter):
396 o = parameter
397 for c in [u' ', u'(', u')']:
398 o = o.replace(c, u'\\' + c)
399 return o
400
401
402 def getEditorName(request):
403 """Return name of the last editor."""
404 editorname = u''
405 log = request.page._last_edited(request)
406 if log:
407 if request.cfg.show_hosts:
408 title = " @ %s[%s]" % (log.hostname, log.addr)
409 else:
410 title = ""
411 kind, info = log.getInterwikiEditorData(request)
412 if kind in ['interwiki', 'email']:
413 if log._usercache[log.userid].__dict__.get('aliasname', u''):
414 editorname = log._usercache[log.userid].aliasname
415 else:
416 editorname = log._usercache[log.userid].name
417 elif kind == 'ip':
418 try:
419 idx = info.index('.')
420 except ValueError:
421 idx = len(info)
422 editorname = wikiutil.escape(info[:idx])
423 return editorname
424
425
426 def pipeCommand(cmdstr, input=None):
427 child_stdin, child_stdout, child_stderr = os.popen3 (cmdstr, u'b')
428 try:
429 if input:
430 child_stdin.write(input)
431 child_stdin.close()
432 except:
433 pass
434
435 child_output = child_stdout.read()
436 child_stdout.close()
437
438 child_error = child_stderr.read()
439 child_stderr.close()
440
441 if os.name in ['posix', 'mac']:
442 try:
443 # REMARK: Otherwise we get <defunct> processes.
444 os.wait()
445 except OSError, e:
446 # 10: No child processes.
447 if e.errno != 10:
448 raise
449 return (child_output, child_error)
450
451
452 class CreatePdfDocument:
453 """Implementation of the PDF document generator."""
454
455 def __init__(self):
456 self.action_name = self.__class__.__name__
457 self.pagename = None
458 self.request = None
459 self._ = None
460 self.debug = False
461 self.msg = None
462 self.errormsgsent = False
463 self.default_values = {
464 'style': u'webpage',
465 'format': u'pdf13',
466 'titlefileimage': u'',
467 'linkstyle': u'underline',
468 'headerleft': u't',
469 'headermiddle': u'.',
470 'headerright': u'D',
471 'footerleft': u'.',
472 'footermiddle': u'/',
473 'footerright': u'.',
474 'tocheaderleft': u'.',
475 'tocheadermiddle': u't',
476 'tocheaderright': u'.',
477 'tocfooterleft': u'.',
478 'tocfootermiddle': u'.',
479 'tocfooterright': u'i',
480 'bodycolor': u'FFFFFF',
481 'bodyimage': u'',
482 'textcolor': u'000000',
483 'linkcolor': u'0000E0',
484 'size': u'legal',
485 'user-password': u'',
486 'owner-password': u'',
487 'toclevels': u'3',
488 'grayscale': u'unchecked',
489 'title': u'checked',
490 'duplex': u'unchecked',
491 'landscape': u'unchecked',
492 'usersize': u'',
493 'margintop': u'0.50in',
494 'marginbottom': u'0.50in',
495 'marginleft': u'1.00in',
496 'marginright': u'0.50in',
497 'no-toc': u'checked',
498 'no-links': u'checked',
499 'firstpage': u'p1',
500 'jpeg': u'0',
501 'compression': u'0',
502 'pagemode': u'outline',
503 'pagelayout': u'single',
504 'firstpage': u'c1',
505 'numbered': u'checked',
506 'encryption': u'unchecked',
507 'permissioncopy': u'checked',
508 'permissionprint': u'checked',
509 'permissionannotate': u'checked',
510 'permissionmodify': u'checked',
511 'charset': u'iso-8859-1',
512 'debug': u'',
513 'rev': 0,
514 'extra-titledocnumber': u'',
515 'extra-titleauthor': u'',
516 'extra-titlecopyright': u'',
517 'pageinfo': u'unchecked',
518 'bodyfont': u'times',
519 'headingfont': u'helvetica',
520 'headfootfont': u'helvetica',
521 'fontsize': u'11.0',
522 'headfootsize': u'11.0',
523 'fontspacing': u'1.2',
524 'embedfonts': u'checked',
525 'browserwidth': u'680',
526 'extra-dynamiccodeblock': u'checked',
527 }
528 # We have to know which values are checkboxes within the form. If a key does
529 # not exists wihtin the form the corresponding checkbox is not checked.
530 self.form_checkbox = []
531 for key, value in self.default_values.items():
532 if value in [u'checked', u'unchecked']:
533 self.form_checkbox += [key]
534 self.contenttype = u'application/pdf'
535
536 def error_msg(self, msg):
537 """Display error message."""
538 if not self.errormsgsent:
539 # Backward compatiblity with MoinMoin 1.5.
540 if Page.send_page.func_code.co_varnames[1] == 'request':
541 Page(self.request, self.pagename).send_page(self.request, msg=msg)
542 else:
543 Page(self.request, self.pagename).send_page(msg=msg)
544 self.errormsgsent = True
545
546 def fixhtmlstr(self, str):
547 """Convert utf-8 encoded multi-byte sequences into &#XXXX; format."""
548 htmlstr = array.array('c')
549 for c in str:
550 if ord(c) >= 128:
551 htmlstr.fromstring('&#%d;' % ord(c))
552 else:
553 htmlstr.fromstring(c)
554 return htmlstr.tostring()
555
556 def set_page_values(self):
557 """Scan raw page for additional information relating PDF generation."""
558 #pdflines = False
559 for line in self.request.page.get_raw_body().split(u'\n'):
560 if line[:6] == u'##pdf ' and len(line[6:]):
561 line = line[6:]
562 key = line.split()[0]
563 value = line[len(key) + 1:]
564 # Only accept known values/settings.
565 if key in self.default_values:
566 # Check if there are any restrictions for key.
567 if key in self.valid_options:
568 # Set only the value if the restrictions are confirmed.
569 valid_values = self.valid_options[key].keys()
570 if value in valid_values:
571 self.values[key] = value
572 else:
573 # There are no restrictions for value.
574 self.values[key] = value
575 elif not line:
576 break
577
578 def set_page_default_values(self):
579 # We are not able to recognise if this string is part of a verbatim area.
580 matchtoclvl = re.compile(r'^\[\[TableOfContents\(\s*(\d+)\s*\)\]\]')
581 matchtoc = re.compile(r'^\[\[TableOfContents\(*\)*\]\]')
582 toc = False
583 for line in self.request.page.get_raw_body().split(u'\n'):
584 if line[:10] == u'#language ' and not u'language' in self.values:
585 lang = self.make_isolang(line[10:])
586 if lang:
587 self.default_values[u'language'] = lang
588 elif not u'toclevels' in self.values and not toc:
589 result = matchtoclvl.match(line)
590 if result:
591 toclevels = int(result.group(1).strip())
592 if toclevels > 4:
593 toclevels = 4
594 self.default_values[u'toclevels'] = str(toclevels)
595 toc = True
596 elif matchtoc.match(line):
597 toc = True
598 # We assume if table-of-contents is used we intent to generate a book.
599 if toc:
600 # Do not change style if set manually or by configuration.
601 self.default_values[u'style'] = self.default_values.get(u'style', u'book')
602 # Do not generate a table of contents page.
603 if self.default_values[u'style'] != u'book':
604 # Do not change style if set manually or by configuration.
605 self.default_values[u'no-toc'] = self.default_values.get(u'no-toc', u'unchecked')
606
607 def _select (self, name, description=None):
608 """Helper function to create a selection control."""
609 str = u'<select name="%s" size="1">' % (name,)
610 if not description:
611 description = self.valid_options[name]
612 keys = description.keys()
613 keys.sort()
614 for value in keys:
615 if value == self.values[name]:
616 selected = u'selected'
617 else:
618 selected = u''
619 str += u'<option value="%s" %s>%s</option>' % (value, selected, description[value],)
620 str += u'</select>'
621 return str
622
623 def _chooseformat (self, name):
624 """Helper function to create left/middle/right selection controls."""
625 str = u""" <tr>
626 <td class="label"><label>%s</label></td>
627 <td><table>
628 <tr>
629 <td>%s</td>
630 <td>%s</td>
631 </tr>
632 <tr>
633 <td>%s</td>
634 <td>%s</td>
635 </tr>
636 <tr>
637 <td>%s</td>
638 <td>%s</td>
639 </tr>
640 </table>
641 </td>
642 <td>%s</td>
643 </tr>""" % (self.fields[u'label_' + name],
644 self.fields[u'label_left'], self._select(name + u'left', self.valid_options[u'tocformats']),
645 self.fields[u'label_middle'], self._select(name + u'middle', self.valid_options[u'tocformats']),
646 self.fields[u'label_right'], self._select(name + u'right', self.valid_options[u'tocformats']),
647 self.fields[u'help_' + name],)
648 return str
649
650 def makeform (self, errormsg=u''):
651 self.fields = {
652 'error': errormsg,
653 'pagename': wikiutil.escape(self.pagename),
654 'action': self.action_name,
655 'version': __version__,
656 'moinmoin_release': moinmoin_release,
657
658 'label_input': self._(u'Input'),
659 'label_output': self._(u'Output'),
660 'label_page': self._(u'Page'),
661 'label_tableofcontents': self._(u'Contents'),
662 'label_pdf': self._(u'PDF'),
663 'label_security': self._(u'Security'),
664
665 'label_choose_style': self._(u'Choose style'),
666 'help_choose_style': self._(u'book: Create a structured PDF document with headings, chapters, etc.') + u'<br/>' + \
667 self._(u'webpage: Specifies that the HTML sources are unstructured (plain web pages.) A page break is inserted between each file or URL in the output.') + u'<br/>' + \
668 self._(u'continuous: Specifies that the HTML sources are unstructured (plain web pages.) No page breaks are inserted between each file or URL in the output.'),
669
670 'help_titletext': self._(u'Title of the document for the front page.'),
671
672 'label_titlefileimage': self._(u'Title file/image'),
673 'help_titlefileimage': self._(u'The title image or HTML page. These file has to be an attachments!'),
674
675 'label_extra-titledocnumber': self._(u'Version'),
676 'help_extra-titledocnumber': self._(u'Specify document version to be displayed on the title page.'),
677
678 'label_extra-titleauthor': self._(u'Author'),
679 'help_extra-titleauthor': self._(u'Intellectual property owner of this document.'),
680
681 'label_extra-titlecopyright': self._(u'Copyright'),
682 'help_extra-titlecopyright': self._(u'Copyright notice for this document.'),
683
684 'label_pageinfo': self._(u'Apply page information'),
685 'help_pageinfo': self._(u'Information about who and when modified the document are applied at the end.'),
686
687 'label_format': self._(u'Output format'),
688 'help_format': self._(u'Specifies the output format.'),
689
690 'label_outputoptions': self._(u'Output options'),
691 'label_grayscale': self._(u'Grayscale document'),
692 'label_titlepage': self._(u'Title page'),
693 'label_titletext': self._(u'Title'),
694 'label_jpeg': self._(u'JPEG big images'),
695 'label_compression': self._(u'Compression'),
696
697 'label_no-toc': self._(u'Generate a table of contents'),
698 'help_no-toc': self._(u''),
699
700 'label_toclevels': self._(u'Limit the number of levels in the table-of-contents'),
701 'help_toclevels': self._(u'Sets the number of levels in the table-of-contents.') + u' ' + self._(u'Empty for unlimited levels.'),
702
703 'label_numbered': self._(u'Numbered headings'),
704 'help_numbered': self._(u'Check to number all of the headings in the document.'),
705
706 'label_toctitle': self._(u'Table-of-contents title'),
707 'help_toctitle': self._(u'Sets the title for the table-of-contents.') + u' ' + self._(u'Empty for default title.'),
708
709 'label_left': self._(u'Left'),
710 'label_middle': self._(u'Middle'),
711 'label_right': self._(u'Right'),
712
713 'label_tocheader': self._(u'Header of table-of-contantes page'),
714 'help_tocheader': self._(u'Sets the page header to use on table-of-contents pages.'),
715
716 'label_tocfooter': self._(u'Footer of table-of-contantes page'),
717 'help_tocfooter': self._(u'Sets the page footer to use on table-of-contents pages.'),
718
719 'label_header': self._(u'Page header'),
720 'help_header': self._(u'Sets the page header to use on body pages.'),
721
722 'label_footer': self._(u'Page footer'),
723 'help_footer': self._(u'Sets the page footer to use on body pages.'),
724
725 'label_colors': self._(u'Colors'),
726 'label_no-links': self._(u'Create HTTP links'),
727 'help_no-links': self._(u'Enables generation of links in PDF files.'),
728
729 'label_linkstyle': self._(u'Style of HTTP links'),
730 'help_linkstyle': self._(u''),
731
732 'label_linkcolor': self._(u'HTTP links color'),
733 'help_linkcolor': self._(u'Sets the color of links.'),
734
735 'label_bodycolor': self._(u'Body color'),
736 'help_bodycolor': self._(u'Enter the HTML color for the body (background).'),
737
738 'label_bodyimage': self._(u'Body image'),
739 'help_bodyimage': self._(u'Enter the image file for the body (background). These file has to be an attachments!'),
740
741 'label_textcolor': self._(u'Text color'),
742 'help_textcolor': self._(u'Enter the HTML color for the text.'),
743
744 'label_duplex': self._(u'2-Sided'),
745 'help_duplex': self._(u'Specifies that the output should be formatted for double-sided printing.'),
746
747 'label_landscape': self._(u'Landscape'),
748
749 'label_choose_size': self._(u'Choose page size'),
750 'help_choose_size': self._(u'Choose one of the predefined standard sizes or select user defined.'),
751
752 'label_usersize': self._(u'User defined page size'),
753 'help_usersize': self._(u'Specifies the page size using a standard name or in points (no suffix or ##x##pt), inches (##x##in), centimeters (##x##cm), or millimeters (##x##mm).'),
754
755 'label_browserwidth': self._(u'Browser width'),
756 'help_browserwidth': self._(u'Set the target browser width in pixels (400-1200). This determines the page scaling of images.'),
757
758 'label_margin': self._(u'User defined margin'),
759 'label_margintop': self._(u'Top'),
760 'label_marginbottom': self._(u'Bottom'),
761 'label_marginleft': self._(u'Left'),
762 'label_marginright': self._(u'Right'),
763 'help_margin': self._(u'Specifies the margin size using points (no suffix or ##x##pt), inches (##x##in), centimeters (##x##cm), or millimeters (##x##mm).') + u' ' + self._(u'Keep empty for default value.'),
764
765 'label_pagemode': self._(u'Page mode'),
766 'help_pagemode': self._(u'Controls the initial viewing mode for the document.') + u'<br/>' + self._(u'Document: Displays only the docuemnt pages.') + u'<br/>' + self._(u'Outline: Display the table-of-contents outline as well as the document pages.') + u'<br/>' + self._(u'Full-screen: Displays pages on the whole screen; this mode is used primarily for presentations.'),
767
768 'label_pagelayout': self._(u'Page layout'),
769 'help_pagelayout': self._(u'Controls the initial layout of document pages on the screen.') + u'<br/>' + self._(u'Single: Displays a single page at a time.') + u'<br/>' + self._(u'One column: Displays a single column of pages at a time.') + u'<br/>' + self._(u'Two column left/right: Display two columns of pages at a time; the first page is displayed in the left or right column as selected.'),
770
771 'label_firstpage': self._(u'First page'),
772 'help_firstpage': self._(u'Choose the initial page that will be shown.'),
773
774 'label_encryption': self._(u'Encryption'),
775 'help_encryptin': self._(u'Enables encryption and security features for PDF output.'),
776 'label_permissions': self._(u'Permissions'),
777 'help_permissions': self._(u'Specifies the document permissions.'),
778
779 'label_permissionannotate': self._(u'Annotate'),
780 'label_permissionprint': self._(u'Print'),
781 'label_permissionmodify': self._(u'Modify'),
782 'label_permissioncopy': self._(u'Copy'),
783
784 'label_owner-password': self._(u'Owner password'),
785 'help_owner-password': self._(u'Specifies the owner password to control who can change document permissions etc.') + u' ' + self._(u'If this field is left blank, a random 32-character password is generated so that no one can change the document.'),
786
787 'label_user-password': self._(u'User password'),
788 'help_user-password': self._(u'Specifies the user password to restrict viewing permissions on this PDF document.') + u' ' + self._(u'Empty for no encryption.'),
789
790 'label_expert': self._(u'Expert'),
791 'label_language': self._(u'Language translation'),
792 'help_language': self._(u'Specify language to use for date and time format.'),
793
794 'label_extra-dynamiccodeblock': self._(u'Dynamic code block'),
795 'help_extra-dynamiccodeblock': self._(u'Shrink code blocks on page.'),
796
797 'label_fonts': self._(u'Fonts'),
798 'label_fontsize': self._(u'Base font size'),
799 'help_fontsize': self._(u'Set the default size of text.'),
800 'label_fontspacing': self._(u'Line spacing'),
801 'help_fontspacing': self._(u'Set the spacing between lines of text.'),
802 'label_bodyfont': self._(u'Body typeface'),
803 'help_bodyfont': self._(u'Choose the default typeface (font) of text.'),
804 'label_headingfont': self._(u'Heading typeface'),
805 'help_headingfont': self._(u'Choose the default typeface (font) of headings.'),
806 'label_headfootsize': self._(u'Header/Footer size'),
807 'help_headfootsize': self._(u'Set the size of header and footer text.'),
808 'label_headfootfont': self._(u'Header/Footer font'),
809 'help_headfootfont': self._(u'Choose the font for header and footer text.'),
810 'label_charset': self._(u'Charset set'),
811 'help_charset': self._(u'Change the encoding of the text in document.'),
812 'label_embedfonts': self._(u'Embed fonts'),
813 'help_embedfonts': self._(u'Check to embed font in the output file.'),
814
815 'label_about': self._(u'About'),
816 'copyright': u'',
817 'version': self._(u'Version') + u' ' + __version__,
818
819 'button_generate': self._(u'Generate PDF'),
820 'button_remember': self._(u'Remember form'),
821 'button_cancel': self._(u'Cancel'),
822 'button_reset': self._(u'Reset'),
823 }
824
825 self.fields['copyright'] = u"<br/>\n".join(wikiutil.escape(__doc__).split(u"\n"))
826 self.fields.update(self.values)
827
828 # Status of debug.
829 if self.debug:
830 self.fields[u'debug'] = u'1'
831 else:
832 self.fields[u'debug'] = u'0'
833
834 # Go through all format strings.
835 for name in [u'tocheader', u'tocfooter', u'header', u'footer']:
836 self.fields[u'choose_' + name] = self._chooseformat(name)
837
838 self.fields[u'select_style'] = self._select(u'style')
839 self.fields[u'select_format'] = self._select(u'format')
840 self.fields[u'select_linkstyle'] = self._select(u'linkstyle')
841 self.fields[u'select_size'] = self._select(u'size')
842 self.fields[u'select_jpeg'] = self._select(u'jpeg')
843 self.fields[u'select_compression'] = self._select(u'compression')
844 self.fields[u'select_toclevels'] = self._select(u'toclevels')
845 self.fields[u'select_pagemode'] = self._select(u'pagemode')
846 self.fields[u'select_pagelayout'] = self._select(u'pagelayout')
847 self.fields[u'select_firstpage'] = self._select(u'firstpage')
848 self.fields[u'select_charset'] = self._select(u'charset')
849 self.fields[u'select_fontsize'] = self._select(u'fontsize')
850 self.fields[u'select_bodyfont'] = self._select(u'bodyfont')
851 self.fields[u'select_headingfont'] = self._select(u'headingfont')
852 self.fields[u'select_headfootsize'] = self._select(u'headfootsize')
853 self.fields[u'select_headfootfont'] = self._select(u'headfootfont')
854 self.fields[u'select_fontspacing'] = self._select(u'fontspacing')
855
856 # Add tabber implementation.
857 self.request.cfg.html_head += """
858 <script type="text/javascript">
859 <!-- //
860 %s
861 //-->
862 </script>
863
864 %s
865 """ % (tabber_minimized, tabber_minimized_css,)
866
867 form = u''
868 if self.debug:
869 form += u'<p class="warning">Debug mode activated.</p>'
870 if not moinmoin_release[:3] in [u'1.6', u'1.5']:
871 form += u'<p class="warning">This plugin is not designed for MoinMoin %(moinmoin_release)s.</p>'
872 form += """
873 <p class="error">%(error)s</p>
874 <form method="post" action="">
875 <input type="hidden" name="action" value="%(action)s"/>
876 <div class="tabber">
877 <div class="tabbertab">
878 <h3>%(label_input)s</h3>
879 <table>
880 <tr>
881 <td class="label"><label>%(label_choose_style)s</label></td>
882 <td class="content">%(select_style)s</td>
883 <td>%(help_choose_style)s</td>
884 </tr>
885 <tr>
886 <td class="label"><label>%(label_titletext)s</label></td>
887 <td class="content"><input type="text" size="30" name="titletext" value="%(titletext)s" /></td>
888 <td>%(help_titletext)s</td>
889 </tr>
890 <tr>
891 <td class="label"><label>%(label_titlefileimage)s</label></td>
892 <td class="content"><input type="text" size="30" name="titlefileimage" value="%(titlefileimage)s" /></td>
893 <td>%(help_titlefileimage)s</td>
894 </tr>
895 <tr>
896 <td class="label"><label>%(label_extra-titledocnumber)s</label></td>
897 <td class="content"><input type="text" size="30" name="extra-titledocnumber" value="%(extra-titledocnumber)s" /></td>
898 <td>%(help_extra-titledocnumber)s</td>
899 </tr>
900 <tr>
901 <td class="label"><label>%(label_extra-titleauthor)s</label></td>
902 <td class="content"><input type="text" size="30" name="extra-titleauthor" value="%(extra-titleauthor)s" /></td>
903 <td>%(help_extra-titleauthor)s</td>
904 </tr>
905 <tr>
906 <td class="label"><label>%(label_extra-titlecopyright)s</label></td>
907 <td class="content"><input type="text" size="30" name="extra-titlecopyright" value="%(extra-titlecopyright)s" /></td>
908 <td>%(help_extra-titlecopyright)s</td>
909 </tr>
910 <tr>
911 <td class="label"><label>%(label_pageinfo)s</label></td>
912 <td class="checkbox"><input type="checkbox" name="pageinfo" value="checked" %(pageinfo)s /></td>
913 <td>%(help_pageinfo)s</td>
914 </tr>
915 </table>
916 </div>
917 <div class="tabbertab">
918 <h3>%(label_output)s</h3>
919 <table>
920 <tr>
921 <td class="label"><label>%(label_format)s</label></td>
922 <td class="content">%(select_format)s</td>
923 <td>%(help_format)s</td>
924 </tr>
925 <tr>
926 <td class="label"><label>%(label_outputoptions)s</label></td>
927 <td colspan="2"><input type="checkbox" name="grayscale" value="checked" %(grayscale)s />%(label_grayscale)s
928 <input type="checkbox" name="title" value="checked" %(title)s />%(label_titlepage)s<br />
929 %(label_compression)s : %(select_compression)s
930 %(label_jpeg)s %(select_jpeg)s</td>
931 </tr>
932 </table>
933 </div>
934 <div class="tabbertab">
935 <h3>%(label_page)s</h3>
936 <table>
937 <tr>
938 <td class="label"><label>%(label_choose_size)s</label></td>
939 <td>%(select_size)s <br /><nobr>%(label_usersize)s <input type="text" size="15" name="usersize" value="%(usersize)s" /></nobr></td>
940 <td>%(help_choose_size)s<br />%(help_usersize)s</td>
941 </tr>
942 <tr>
943 <td class="label"><label>%(label_browserwidth)s</label></td>
944 <td class="content"><input type="text" size="30" name="browserwidth" value="%(browserwidth)s" /></td>
945 <td>%(help_browserwidth)s</td>
946 </tr>
947 <tr>
948 <td> </td>
949 <td colspan="2"><input type="checkbox" name="duplex" value="checked" %(duplex)s /> %(label_duplex)s
950 <input type="checkbox" name="landscape" value="checked" %(landscape)s /> %(label_landscape)s</td>
951 </tr>
952 <tr>
953 <td class="label"><label>%(label_margin)s</label></td>
954 <td><table><tr><td> </td><td><nobr><label>%(label_margintop)s</label> <input type="text" name="margintop" value="%(margintop)s" size="7" /></nobr></td><td> </td></tr>
955 <tr><td><nobr><label>%(label_marginleft)s</label> <input type="text" name="marginleft" value="%(marginleft)s" size="7" /></nobr></td><td> </td><td><nobr><label>%(label_marginright)s</label> <input type="text" name="marginright" value="%(marginright)s" size="7" /></nobr></td></tr>
956 <tr><td> </td><td><nobr><label>%(label_marginbottom)s</label> <input type="text" name="marginbottom" value="%(marginbottom)s" size="7" /></nobr></td><td> </td></tr></table>
957 <td>%(help_margin)s</td>
958 </tr>
959 %(choose_header)s
960 %(choose_footer)s
961 </table>
962 </div>
963 <div class="tabbertab">
964 <h3>%(label_tableofcontents)s</h3>
965 <table>
966 <tr>
967 <td class="label"><label>%(label_no-toc)s</label></td>
968 <td class="checkbox"><input type="checkbox" name="no-toc" value="checked" %(no-toc)s /></td>
969 <td>%(help_no-toc)s</td>
970 </tr>
971 <tr>
972 <td class="label"><label>%(label_toclevels)s</label></td>
973 <td class="content">%(select_toclevels)s</td>
974 <td>%(help_toclevels)s</td>
975 </tr>
976 <tr>
977 <td> </td>
978 <td><input type="checkbox" name="numbered" value="checked" %(numbered)s /> %(label_numbered)s</td>
979 <td>%(help_numbered)s</td>
980 </tr>
981 <tr>
982 <td class="label"><label>%(label_toctitle)s</label></td>
983 <td class="content"><input type="text" size="30" name="toctitle" value="%(toctitle)s" /></td>
984 <td>%(help_toctitle)s</td>
985 </tr>
986 %(choose_tocheader)s
987 %(choose_tocfooter)s
988 </table>
989 </div>
990 <div class="tabbertab">
991 <h3>%(label_colors)s</h3>
992 <table>
993 <tr>
994 <td class="label"><label>%(label_bodycolor)s</label></td>
995 <td class="content"><input type="text" size="6" name="bodycolor" value="%(bodycolor)s" /></td>
996 <td>%(help_bodycolor)s</td>
997 </tr>
998 <tr>
999 <td class="label"><label>%(label_bodyimage)s</label></td>
1000 <td class="content"><input type="text" size="30" name="bodyimage" value="%(bodyimage)s" /></td>
1001 <td>%(help_bodyimage)s</td>
1002 </tr>
1003 <tr>
1004 <td class="label"><label>%(label_textcolor)s</label></td>
1005 <td class="content"><input type="text" size="6" name="textcolor" value="%(textcolor)s" /></td>
1006 <td>%(help_textcolor)s</td>
1007 </tr>
1008 <tr>
1009 <td class="label"><label>%(label_linkcolor)s</label></td>
1010 <td class="content"><input type="text" size="6" name="linkcolor" value="%(linkcolor)s" /></td>
1011 <td>%(help_linkcolor)s</td>
1012 </tr>
1013 <tr>
1014 <td class="label"><label>%(label_linkstyle)s</label></td>
1015 <td class="content">%(select_linkstyle)s</td>
1016 <td>%(help_linkstyle)s</td>
1017 </tr>
1018 <tr>
1019 <td class="label"><label>%(label_no-links)s</label></td>
1020 <td><input type="checkbox" name="no-links" value="checked" %(no-links)s /></td>
1021 <td>%(help_no-links)s</td>
1022 </tr>
1023 </table>
1024 </div>
1025 <div class="tabbertab">
1026 <h3>%(label_fonts)s</h3>
1027 <table>
1028 <tr>
1029 <td class="label"><label>%(label_fontsize)s</label></td>
1030 <td class="content">%(select_fontsize)s</td>
1031 <td>%(help_fontsize)s</td>
1032 </tr>
1033 <tr>
1034 <td class="label"><label>%(label_fontspacing)s</label></td>
1035 <td class="content">%(select_fontspacing)s</td>
1036 <td>%(help_fontspacing)s</td>
1037 </tr>
1038 <tr>
1039 <td class="label"><label>%(label_bodyfont)s</label></td>
1040 <td class="content">%(select_bodyfont)s</td>
1041 <td>%(help_bodyfont)s</td>
1042 </tr>
1043 <tr>
1044 <td class="label"><label>%(label_headingfont)s</label></td>
1045 <td class="content">%(select_headingfont)s</td>
1046 <td>%(help_headingfont)s</td>
1047 </tr>
1048 <tr>
1049 <td class="label"><label>%(label_headfootsize)s</label></td>
1050 <td class="content">%(select_headfootsize)s</td>
1051 <td>%(help_headfootsize)s</td>
1052 </tr>
1053 <tr>
1054 <td class="label"><label>%(label_headfootfont)s</label></td>
1055 <td class="content">%(select_headfootfont)s</td>
1056 <td>%(help_headfootfont)s</td>
1057 </tr>
1058 <tr>
1059 <td class="label"><label>%(label_charset)s</label></td>
1060 <td class="content">%(select_charset)s</td>
1061 <td>%(help_charset)s</td>
1062 </tr>
1063 <tr>
1064 <td class="label"><label>%(label_embedfonts)s</label></td>
1065 <td class="checkbox"><input type="checkbox" name="embedfonts" value="checked" %(embedfonts)s /></td>
1066 <td>%(help_embedfonts)s</td>
1067 </tr>
1068 </table>
1069 </div>
1070 <div class="tabbertab">
1071 <h3>%(label_pdf)s</h3>
1072 <table>
1073 <tr>
1074 <td class="label"><label>%(label_pagemode)s</label></td>
1075 <td class="content">%(select_pagemode)s</td>
1076 <td>%(help_pagemode)s</td>
1077 </tr>
1078 <tr>
1079 <td class="label"><label>%(label_pagelayout)s</label></td>
1080 <td class="content">%(select_pagelayout)s</td>
1081 <td>%(help_pagelayout)s</td>
1082 </tr>
1083 <tr>
1084 <td class="label"><label>%(label_firstpage)s</label></td>
1085 <td class="content">%(select_firstpage)s</td>
1086 <td>%(help_firstpage)s</td>
1087 </tr>
1088 </table>
1089 </div>
1090 <div class="tabbertab">
1091 <h3>%(label_security)s</h3>
1092 <table>
1093 <tr>
1094 <td class="label"><label>%(label_encryption)s</label></td>
1095 <td><input type="checkbox" name="encryption" value="checked" %(encryption)s /></td>
1096 <td>%(help_numbered)s</td>
1097 </tr>
1098 <tr>
1099 <td class="label"><label>%(label_permissions)s</label></td>
1100 <td><nobr><input type="checkbox" name="permissionprint" value="checked" %(permissionprint)s /> %(label_permissionprint)s</nobr>
1101 <nobr><input type="checkbox" name="permissionmodify" value="checked" %(permissionmodify)s /> %(label_permissionmodify)s</nobr><br />
1102 <nobr><input type="checkbox" name="permissioncopy" value="checked" %(permissioncopy)s /> %(label_permissioncopy)s</nobr>
1103 <nobr><input type="checkbox" name="permissionannotate" value="checked" %(permissionannotate)s /> %(label_permissionannotate)s</nobr></td>
1104 <td>%(help_permissions)s</td>
1105 </tr>
1106 <tr>
1107 <td class="label"><label>%(label_user-password)s</label></td>
1108 <td class="content"><input type="password" size="30" name="user-password" value="%(user-password)s" /></td>
1109 <td>%(help_user-password)s</td>
1110 </tr>
1111 <tr>
1112 <td class="label"><label>%(label_owner-password)s</label></td>
1113 <td class="content"><input type="password" size="30" name="owner-password" value="%(owner-password)s" /></td>
1114 <td>%(help_owner-password)s</td>
1115 </tr>
1116 </table>
1117 </div>
1118 <div class="tabbertab">
1119 <h3>%(label_expert)s</h3>
1120 <table>
1121 <tr>
1122 <td class="label"><label>%(label_language)s</label></td>
1123 <td class="content"><input type="text" size="6" name="language" value="%(language)s" /></td>
1124 <td>%(help_language)s</td>
1125 </tr>
1126 <tr>
1127 <td class="label"><label>%(label_extra-dynamiccodeblock)s</label></td>
1128 <td class="checkbox"><input type="checkbox" name="extra-dynamiccodeblock" value="checked" %(extra-dynamiccodeblock)s /></td>
1129 <td>%(help_extra-dynamiccodeblock)s</td>
1130 </tr>
1131 </table>
1132 </div>
1133 <div class="tabbertab">
1134 <h3>%(label_about)s</h3>
1135 <p>%(version)s (MoinMoin %(moinmoin_release)s)</p>
1136 <p>%(copyright)s</p>
1137 </div>
1138 </div>
1139 <p>
1140 <input type="hidden" name="debug" value="%(debug)s" /><input type="hidden" name="rev" value="%(rev)s" />
1141 <input type="submit" name="generate_from_form" value="%(button_generate)s" />
1142 <input type="submit" name="remember" value="%(button_remember)s" />
1143 <input type="submit" name="cancel" value="%(button_cancel)s" />
1144 </p>
1145 </form>
1146 """ % self.fields
1147 return Dialog(self.request, content=form)
1148
1149 def run(self, pagename, request):
1150 """ Main dispatcher for the action."""
1151 self.pagename = pagename
1152 self.request = request
1153 self._ = self.request.getText
1154 self.form = self.request.form
1155 self.cfg = self.request.cfg
1156
1157 # Canceled by user.
1158 if self.form.has_key(u'cancel'):
1159 # Backward compatiblity with MoinMoin 1.5.
1160 if Page.send_page.func_code.co_varnames[1] == "request":
1161 return self.request.page.send_page(self.request)
1162 else:
1163 return self.request.page.send_page()
1164
1165 # Determine calling parameters.
1166 if self.form.get(u'debug', [u'0']) == [u'1']:
1167 self.debug = True
1168
1169 # This dict contains all possible values.
1170 self.valid_options = {}
1171
1172 self.valid_options[u'tocformats'] = {
1173 u'/': self._(u'1/N,2/N Arabic page numbers'),
1174 u':': self._(u'1/C,2/C Arabic chapter page numbers'),
1175 u'1': self._(u'1,2,3,...'),
1176 u'a': self._(u'a,b,c,...'),
1177 u'A': self._(u'A,B,C,...'),
1178 u'c': self._(u'Chapter title'),
1179 u'C': self._(u'Chapter page number'),
1180 u'd': self._(u'Date'),
1181 u'D': self._(u'Date + Time'),
1182 u'h': self._(u'Heading'),
1183 u'i': self._(u'i,ii,iii,iv,...'),
1184 u'I': self._(u'I,II,III,IV,...'),
1185 u't': self._(u'Title'),
1186 u'T': self._(u'Time'),
1187 u'.': self._(u'Blank'),
1188 # TODO: Not supported yet; u'l': self._(u'Logo image'),
1189 }
1190 self.valid_options[u'style'] = {
1191 u'webpage': self._(u'webpage'),
1192 u'book': self._(u'book'),
1193 u'continuous': self._(u'continuous'),
1194 }
1195 self.valid_options[u'size'] = {
1196 u'legal': self._(u'Legal (8.5x14in)'),
1197 u'a4': self._(u'A4 (210x297mm)'),
1198 u'letter': self._(u'Letter (8.5x11in)'),
1199 u'universal': self._(u'Universal (8.27x11in)'),
1200 u'': self._(u'User defined'),
1201 }
1202 self.valid_options[u'format'] = {
1203 u'pdf11': self._(u'PDF 1.1 (Acrobat 2.0)'),
1204 u'pdf12': self._(u'PDF 1.2 (Acrobat 3.0)'),
1205 u'pdf13': self._(u'PDF 1.3 (Acrobat 4.0)'),
1206 u'pdf14': self._(u'PDF 1.4 (Acrobat 5.0)'),
1207 # TODO: Not supported yet:
1208 #u'ps1': self._(u'PostScript Level 1'),
1209 #u'ps2': self._(u'PostScript Level 2'),
1210 #u'ps3': self._(u'PostScript Level 3'),
1211 }
1212 self.valid_options[u'linkstyle'] = {
1213 u'underline': self._(u'Underline'),
1214 u'plain': self._(u'Plain'),
1215 }
1216 self.valid_options[u'firstpage'] = {
1217 u'c1': self._(u'1st chapter'),
1218 u'p1': self._(u'1st page'),
1219 u'toc': self._(u'Contents'),
1220 }
1221 self.valid_options[u'jpeg'] = {
1222 u'0': self._(u'None'),
1223 u'50': self._(u' 50% (Good)'),
1224 u'55': u'55%', u' 60': u' 60%', u' 65': ' 65%', u' 70': ' 70%', u' 75': ' 75%',
1225 u'80': ' 80%', u' 85': ' 85%', u' 90': ' 90%', u' 95': ' 95%',
1226 u'100': self._(u'100% (Best)'),
1227 }
1228 self.valid_options[u'compression'] = {
1229 u'0': self._(u'None'),
1230 u'1': self._(u'1 (Fast)'),
1231 u'2': u'2', u'3': u'3', u'4': u'4', u'5': u'5', u'6': u'6', u'7': u'7', u'8': u'8',
1232 u'9': self._(u'9 (Best)'),
1233 }
1234 self.valid_options[u'toclevels'] = {
1235 u'0': self._(u'None'),
1236 u'1': u'1', u'2': '2', u'3': '3', u'4': '4'
1237 }
1238 self.valid_options[u'pagemode'] = {
1239 u'outline': self._(u'Outline'),
1240 u'document': self._(u'Document'),
1241 u'fullscreen': self._(u'Full-screen'),
1242 }
1243 self.valid_options[u'pagelayout'] = {
1244 u'single': self._(u'Single'),
1245 u'one': self._(u'One column'),
1246 u'twoleft': self._(u'Two column left'),
1247 u'tworight': self._(u'Two column right'),
1248 }
1249 self.valid_options[u'charset'] = {
1250 u'iso-8859-1': self._(u'ISO 8859-1'),
1251 u'iso-8859-2': self._(u'ISO 8859-2'),
1252 u'iso-8859-3': self._(u'ISO 8859-3'),
1253 u'iso-8859-4': self._(u'ISO 8859-4'),
1254 u'iso-8859-5': self._(u'ISO 8859-5'),
1255 u'iso-8859-6': self._(u'ISO 8859-6'),
1256 u'iso-8859-7': self._(u'ISO 8859-7'),
1257 u'iso-8859-8': self._(u'ISO 8859-8'),
1258 u'iso-8859-9': self._(u'ISO 8859-9'),
1259 u'iso-8859-14': self._(u'ISO 8859-14'),
1260 u'iso-8859-15': self._(u'ISO 8859-15'),
1261 u'cp-874': self._(u'cp-847'),
1262 u'cp-1250': self._(u'cp-1250'),
1263 u'cp-1251': self._(u'cp-1251'),
1264 u'cp-1252': self._(u'cp-1252'),
1265 u'cp-1253': self._(u'cp-1253'),
1266 u'cp-1254': self._(u'cp-1254'),
1267 u'cp-1255': self._(u'cp-1255'),
1268 u'cp-1256': self._(u'cp-1256'),
1269 u'cp-1257': self._(u'cp-1257'),
1270 u'cp-1258': self._(u'cp-1258'),
1271 u'koi-8r': self._(u'koi-8r'),
1272 }
1273 self.valid_options[u'bodyfont'] = {
1274 u'courier': self._(u'Courier'),
1275 u'helvetica': self._(u'Helvetica'),
1276 u'monospace': self._(u'Monospace'),
1277 u'sans': self._(u'Sans'),
1278 u'serif': self._(u'Serif'),
1279 u'times': self._(u'Times'),
1280 }
1281 self.valid_options[u'headingfont'] = self.valid_options[u'bodyfont']
1282 self.valid_options[u'headfootfont'] = self.valid_options[u'bodyfont']
1283 # Go through all font types and create fontname{-bold,-oblique,-boldoblique} entries.
1284 for fontname in self.valid_options[u'bodyfont'].keys():
1285 for fontstyle in [u'bold', u'oblique', u'boldoblique']:
1286 self.valid_options[u'headfootfont'][fontname + u'-' + fontstyle] = u'%s (%s)' % (self.valid_options[u'headfootfont'][fontname], self._(fontstyle),)
1287 # Set possible font sizes.
1288 self._set_fontsize(u'headfootsize', 6, 24, 5)
1289 self._set_fontsize(u'fontsize', 4, 24, 5)
1290 self._set_fontsize(u'fontspacing', 1, 3, 1)
1291
1292 # Set translated name of table of contents as default.
1293 self.default_values[u'toctitle'] = self._(u'Contents')
1294
1295 self.default_values[u'titletext'] = self.pagename
1296 self.default_values[u'extra-titledocnumber'] = u'%d' % self.request.page.get_rev()[1]
1297 page_editor = self.request.page.lastEditInfo().get(u'editor', u'')
1298 self.default_values[u'extra-titleauthor'] = wikiutil.escape(getEditorName(self.request))
1299
1300 # Make sure we create date and time strings in right format.
1301 if self.request.current_lang:
1302 self.default_values[u'language'] = self.request.current_lang
1303 elif self.request.page.language:
1304 self.default_values[u'language'] = self.request.page.language
1305 else:
1306 #self.cfg.language_default or "en"
1307 self.default_values[u'language'] = self.make_isolang(self.cfg.__dict__.get(u'default_language', u'en'))
1308
1309 self.values = {}
1310
1311 # If the configuration variable 'createpdfdocument_validoptions' exists we update our
1312 # self.valid_options dict with these values.
1313 if getattr (self.request.cfg, u'createpdfdocument_validoptions', None):
1314 self.valid_options.update (self.request.cfg.createpdfdocument_validoptions)
1315
1316 # If the configuration variable 'createpdfdocument_defaultvalues' exists we update our
1317 # self.default_values dict with these values.
1318 if getattr (self.request.cfg, u'createpdfdocument_defaultvalues', None):
1319 for key, value in self.request.cfg.createpdfdocument_defaultvalues.items():
1320 self.default_values[key] = value
1321
1322 # Scan page to extract default values.
1323 self.set_page_default_values()
1324
1325 # Create a PDF document direct without any user iteraction from default and page settings.
1326 if self.form.has_key(u'generate'):
1327 self.set_page_values()
1328 self.update_values(useform=False)
1329 return self.do_generate()
1330
1331 # Create a PDF document from form settings.
1332 if self.form.has_key(u'generate_from_form'):
1333 self.update_values()
1334 return self.do_generate()
1335
1336 if self.form.has_key(u'remember'):
1337 self.update_values()
1338 return self.do_remember()
1339
1340 self.set_page_values()
1341 self.update_values(useform=False)
1342 # Backward compatiblity with MoinMoin 1.5.
1343 if Page.send_page.func_code.co_varnames[1] == 'request':
1344 return self.request.page.send_page(self.request, msg=self.makeform())
1345 else:
1346 return self.request.page.send_page(msg=self.makeform())
1347
1348 def update_values (self, useform=True):
1349 """Preset values with they form values or defaults."""
1350 for key, default in self.default_values.items():
1351 # Modify value only if not already set.
1352 if not key in self.values:
1353 # If the form does not contain the value (e.g. for checkboxes) set the
1354 # default value (e.g. for checkboxes unset by default).
1355 if not key in self.form:
1356 # Special processing for checkboxes in forms. If the key does not exists
1357 # within the form it is not checked.
1358 if key in self.form_checkbox and useform:
1359 self.values[key] = u'unchecked'
1360 elif useform:
1361 # Edit fields are missing if they are empty.
1362 self.values[key] = u''
1363 else:
1364 self.values[key] = default
1365 else:
1366 self.values[key] = self.form[key][0]
1367 # Check if revision is an integer value.
1368 try:
1369 self.values[u'rev'] = int(self.values.get(u'rev', self.request.page.rev))
1370 except:
1371 self.values[u'rev'] = self.request.page.rev
1372 # Check if page revision exists.
1373 (pagefname, realrev, exists) = self.request.page.get_rev(rev=self.values[u'rev'])
1374 if exists:
1375 self.values[u'rev'] = realrev
1376 else:
1377 # Determine latest revision number.
1378 (pagefname, self.values[u'rev'], exists) = self.request.page.get_rev()
1379 # Check valid value range.
1380 try:
1381 self.values[u'browserwidth'] = int(self.values[u'browserwidth'])
1382 if self.values[u'browserwidth'] < 400 or self.values[u'browserwidth'] > 1200:
1383 self.values[u'browserwidth'] = self.default_values[u'browserwidth']
1384 except:
1385 self.values[u'browserwidth'] = self.default_values[u'browserwidth']
1386 # We need a string.
1387 self.values[u'browserwidth'] = u'%s' % self.values[u'browserwidth']
1388
1389 def do_generate (self):
1390 """Create PDF document."""
1391 # Generate the HTML page using MoinMoin wiki engine.
1392 html = self.get_html()
1393 if html:
1394 pdfdata = self.html2pdf(html)
1395 if pdfdata:
1396 # Send as application/pdf the generated file by HTMLDOC
1397 self.send_pdf(pdfdata)
1398
1399 # MoinMoin1.6: send_closing_html() has to be called explicit.
1400 # MoinMoin1.5: raise MoinMoinNoFooter exception to forbit creation of HTML footer.
1401 if moinmoin_release[:3] == u'1.5':
1402 from MoinMoin.util import MoinMoinNoFooter
1403 raise MoinMoinNoFooter
1404
1405 def do_remember(self):
1406 """Create a message containing information about how to save the form values for future reuse."""
1407 save = u''
1408 for key, value in self.values.items():
1409 if key in [u'user-password', u'owner-password', u'rev', u'debug']:
1410 continue
1411 if key in self.default_values and value == self.default_values[key]:
1412 continue
1413 save += u'##pdf %s %s' % (key, value,)
1414 if self.debug:
1415 if key in self.default_values:
1416 save += u' <-- default value is "%s" (without quotes)' % self.default_values[key]
1417 else:
1418 save += u' <-- keyword missing in defaults'
1419 save += u'\n'
1420 if save:
1421 msg = self._(u'Add follwing lines at the beginning of your page:') + u'<br/><pre>' + save + u'</pre>'
1422 else:
1423 msg = self._(u'All values correspond to they default. Nothing have to be saved.')
1424 # Backward compatiblity with MoinMoin 1.5.
1425 if Page.send_page.func_code.co_varnames[1] == "request":
1426 return self.request.page.send_page(self.request, msg)
1427 else:
1428 return self.request.page.send_page(msg)
1429
1430 def send_pdf (self, data):
1431 """Send PDF file to HTTP server."""
1432 filename = self.pagename.replace (u'/', u'-') + u'-v' + str(self.values[u'rev']) + u'.pdf'
1433
1434 # Send HTTP header.
1435 self.request.http_headers([
1436 'Content-Type: %s' % self.contenttype,
1437 'Content-Length: %d' % len(data),
1438 # TODO: fix the encoding here, plain 8 bit is not allowed
1439 # according to the RFCs There is no solution that is
1440 # compatible to IE except stripping non-ascii chars
1441 'Content-Disposition: inline; filename="%s"' % filename.encode(config.charset),
1442 ])
1443
1444 # Send binary data.
1445 sio = StringIO.StringIO(data)
1446 shutil.copyfileobj(sio, self.request, 8192)
1447
1448 def get_html (self):
1449 """Generate the HTML body of this page."""
1450 # Save page as HTML.
1451 newreq = RedirectOutputRequest(self.request)
1452 # Do not add edit information.
1453 # Add extra meta tags.
1454 orig_html_head = self.request.cfg.html_head
1455 self.request.cfg.html_head = self.request.cfg.html_head + u"""
1456 <meta name="docnumber" content="%s">
1457 <meta name="author" content="%s">
1458 <meta name="copyright" content="%s">
1459 """ % (wikiutil.escape(self.values['extra-titledocnumber']), wikiutil.escape(self.values['extra-titleauthor']), wikiutil.escape(self.values['extra-titlecopyright']),)
1460 (html, errmsg) = newreq.run(rev = self.values.get(u'rev', None))
1461 # Restore original HTML head configuration.
1462 self.request.cfg.html_head = orig_html_head
1463 if html:
1464 html = self.fixhtmlstr(html)
1465 # Make URLs absolute.
1466 # FIXME: Until MoinMoin is not XHTML compilant we can not use a XML parser
1467 # (e.g. expat) to transform the HTML document. In the meantime we try to
1468 # achive the same with regular expressions subtitution.
1469 base = self.request.getQualifiedURL()
1470 for htmlref in [u'src', u'href']:
1471 reurlref = r'(%s=[\'"])(/[^\'"]*)[\'"]' % (htmlref,)
1472 urlref = re.compile (reurlref, re.I)
1473 for match in urlref.finditer(html):
1474 foundref = match.groups()
1475 html = html.replace (foundref[0] + foundref[1], foundref[0] + base + foundref[1])
1476
1477 # Rename title of the document.
1478 titletext_html = self.fixhtmlstr(wikiutil.escape(self.values['titletext']))
1479 html = re.compile(r'<title>[^<]+</title>').sub(u'<title>%s</title>' % titletext_html, html)
1480
1481 if self.values[u'pageinfo'] == u'unchecked':
1482 # Remove pageinfo by regex. There is no standard way to do that yet.
1483 # Read the comment in ThemeBase.shouldShowPageinfo().
1484 html = re.compile(r'<p[^>]+id="pageinfo".*</p>').sub(u'', html)
1485
1486 # HTMLDOC workarround: Add borders to tables. HTMLDOC assume border="0" if not defined.
1487 html = re.compile(r'<table>').sub(u'<table border="1">', html)
1488
1489 # HTMLDOC workarround: There is no CSS support in HTMLDOC.
1490 tablecolor = re.compile(r'<td.*?background-color: (#......).*?>')
1491 for match in tablecolor.finditer(html):
1492 html = html.replace (match.group(0), u'<td bgcolor="%s">' % match.group(1), 1)
1493
1494 # HTMLDOC workarround: Handle <pre> sections over page boundries.
1495 if self.values[u'extra-dynamiccodeblock'] == u'checked':
1496 multiplespaces = re.compile(r'( {2,})')
1497 spanmatch = re.compile(u'<span.*?</span>')
1498 presections = re.compile (r'(<pre>)(.*?)(</pre>)', re.IGNORECASE | re.DOTALL)
1499 for match in presections.finditer(html):
1500 foundref = match.groups()
1501 # <span> elemens disturb our analysis. We remove them.
1502 presection = spanmatch.sub(u'', foundref[1])
1503 # Search for multiple spaces and replace them by · except the last space.
1504 for spaces in multiplespaces.finditer(presection):
1505 newspaces = u'·' * (len(spaces.group(1)) - 1) + u' '
1506 presection = presection.replace (spaces.group(1), newspaces, 1)
1507 # Go through lines and add a ¶ sign at the end of eatch line.
1508 newprelines = []
1509 for preline in presection.split(u"\n"):
1510 preline = preline + u'¶<br />'
1511 newprelines.append(preline)
1512 # Create a table arround an multi-line block.
1513 if newprelines:
1514 tablestart = u'<table border="1" bgcolor="#F3F5F7" padding="5"><tr><td>'
1515 tableend = u'</td></tr></table>'
1516 else:
1517 newprelines.append(preline)
1518 tablestart = u''
1519 tableend = u''
1520 # Replace the <pre> block with new dynamic text.
1521 html = html.replace (u''.join(foundref), u'%s<font face="Courier,Monospace">%s</font>%s' % (tablestart, u"\n".join(newprelines), tableend,), 1)
1522 else:
1523 self.error_msg(self._(u'Could not redirect HTML output for further processing:') + errmsg)
1524 return html
1525
1526 def make_isolang (self, language):
1527 return language + u'_' + language.upper()
1528
1529 def html2pdf (self, html):
1530 """Create a PDF document based on the current parameters."""
1531 # Not all os support environment variable definition in one line with the calling application.
1532 if os.name in ['posix', 'mac']:
1533 htmldocopts = [u'LANG=' + self.values[u'language'], u'HTMLDOC_NOCGI=1']
1534 else:
1535 htmldocopts = []
1536 # Determine UID to access ACL protected sites too (mandatory to download attached images).
1537 htmldocopts += [u'htmldoc', "--cookies", "MOIN_ID=" + self.request.user.id, u'--no-duplex']
1538
1539 for key in [u'header', u'footer', u'tocheader', u'tocfooter']:
1540 self.values[key] = self.values.get(key + u'left', u'.') + self.values.get(key + u'middle', u'.') + self.values.get(key + u'right', u'.')
1541
1542 permissions = []
1543 for opt, value in self.values.items():
1544 # Skip alle non-HTMLDOC configuration parameters.
1545 if opt in [u'language', u'debug', u'rev', u'titletext', u'pageinfo'] or opt[:6] == u'extra-':
1546 continue
1547
1548 # Skip options without values.
1549 value = value.strip()
1550 if not value:
1551 continue
1552
1553 # Skip options for header/footer configuration which differenciate between position (e.g. footerright or tocheadermiddle)
1554 if opt[:6] in [u'header', u'footer'] and opt[6:] or opt[:9] in [u'tocheader', u'tocfooter'] and opt[9:]:
1555 continue
1556
1557 if opt == u'titlefileimage':
1558 # Check if we have a --titlefile or --titleimage option.
1559 lower_value = value.lower()
1560 dotpos = lower_value.rfind(u'.')
1561 if lower_value[dotpos:] in [u'.bmp', u'.gif', u'.jpg', u'.jpeg', u'.png']:
1562 opt = u'titleimage'
1563 else:
1564 opt = u'titlefile'
1565 value = attachment_fsname(value, self.request.page, self.request)
1566 elif opt == u'bodyimage':
1567 value = attachment_fsname(value, self.request.page, self.request)
1568
1569 if opt in [u'style']:
1570 htmldocopts += [u'--' + value]
1571 elif opt in self.form_checkbox:
1572 if value == u'checked':
1573 if opt[:10] == u'permission':
1574 permissions += [opt[10:]]
1575 # Reverse meaning of 'no-' options.
1576 elif opt[:3] != u'no-':
1577 htmldocopts += [u'--' + opt]
1578 elif opt[:3] == u'no-':
1579 htmldocopts += [u'--' + opt]
1580 elif opt[:6] == u'margin':
1581 htmldocopts += [u'--' + opt[6:], value]
1582 else:
1583 htmldocopts += [u'--' + opt, value]
1584 if permissions:
1585 htmldocopts += [u'--permission', u','.join (permissions)]
1586 htmldocopts += [u'-']
1587 # Do not forget to escape all spaces!
1588 eschtmldocopts = [shell_quote(arg) for arg in htmldocopts]
1589 cmdstr = u' '.join(eschtmldocopts)
1590 errmsg = None
1591
1592 pdf = None
1593 if self.debug:
1594 self.request.http_headers()
1595 errmsg = self._(u'HTMLDOC command:') + u'<pre>' + wikiutil.escape(cmdstr) + u'</pre>'
1596 (htmldoc_help, htmldoc_err) = pipeCommand(u'HTMLDOC_NOCGI=1 htmldoc --help')
1597 errmsg += u'<p><pre>%s</pre></p>' % wikiutil.escape(htmldoc_help)
1598 if 'env' in self.request.__dict__:
1599 reqenv = u'%s' % wikiutil.escape(self.request.env)
1600 else:
1601 reqenv = u'None'
1602 errmsg += u'<p>MoinMoin release %s<br/>self.request = %s<br/>self.request.env = %s</p>' % (wikiutil.escape(moinmoin_release), wikiutil.escape(type(self.request)), reqenv,)
1603 errmsg += u'<hr/><hr/><hr/>'
1604 else:
1605 (pdf, htmldocmsg) = pipeCommand(cmdstr, html)
1606
1607 # Check for error message on STDOUT.
1608 if pdf[:8] == u'HTMLDOC ':
1609 htmldocmsg += pdf
1610 pdf = None
1611
1612 if htmldocmsg:
1613 errmsg = self._(u'Command:') + u'<pre>' + wikiutil.escape(cmdstr) + u'</pre>' + self._('returned:') + u'<pre>' + \
1614 wikiutil.escape(htmldocmsg).replace(u'\n', u'<br/>') + u'</pre>'
1615
1616 # As it is difficult to get the htmldoc return code, we check for
1617 # error by checking the produced pdf length
1618 if not pdf and errmsg:
1619 if self.debug:
1620 self.request.write(u'<html><body>%s</body></hftml>' % errmsg)
1621 self.request.write(html)
1622 else:
1623 self.error_msg(errmsg)
1624 elif pdf[:4] != '%PDF':
1625 self.error_msg(self._(u'Invalid PDF document generated') + wikiutil.escape(pdf[:80]))
1626 pdf = None
1627
1628 return pdf
1629
1630 def _set_fontsize(self, key, min, max, smallstep):
1631 self.valid_options[key] = {}
1632 for fontsize_big in range(min, max):
1633 for fontsize_step in range(0, 10, smallstep):
1634 fontsize = u'%d.%d' % (fontsize_big, fontsize_step,)
1635 self.valid_options[key][fontsize] = self._(fontsize)
1636 self.valid_options[key][u'%d.0' % max] = self._(u'%d.0' % max)
1637
1638
1639 def execute (pagename, request):
1640 try:
1641 CreatePdfDocument().run (pagename = pagename, request = request)
1642 except:
1643 raise
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.