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