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