trac-wikiprint-4.0.0+svn18614/0000755000175500017550000000000014611213476015427 5ustar debacledebacletrac-wikiprint-4.0.0+svn18614/COPYING0000644000175500017550000000254614050534752016471 0ustar debacledebacleCopyright (c) 2021 Cinc All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.trac-wikiprint-4.0.0+svn18614/tracpdf/0000755000175500017550000000000014546107647017063 5ustar debacledebacletrac-wikiprint-4.0.0+svn18614/tracpdf/util.py0000644000175500017550000000507614546106315020411 0ustar debacledebacle# -*- coding: utf-8 -*- # Copyright (c) 2021 Cinc # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import io import os from imp import find_module try: FileNotFoundError except NameError: # py2.X FileNotFoundError = (IOError, OSError) def get_trac_css(env, css_file): """Get the contents of the given CSS file from the trac installation. :param env: Trac Environment object. Will be used when using local env styles. :param css_file: name of one of Trac CSS files, e.g. 'trac.css' :return content of the file as a string Note that the file is not taken from the current environment for now. """ mod = find_module('trac') # TODO: check for environment CSS files first to account for local # styles. path = os.path.join(mod[1], 'htdocs', 'css', css_file) try: with io.open(path, encoding='utf-8', errors='replace') as f: return f.read() except FileNotFoundError: return u'' def writeResponse(req, data, httperror=200, content_type='text/plain; charset=utf-8'): data = data.encode('utf-8') req.send_response(httperror) req.send_header('Content-Type', content_type) req.send_header('Content-Length', len(data)) req.end_headers() req.write(data) trac-wikiprint-4.0.0+svn18614/tracpdf/htdocs/0000755000175500017550000000000014051376115020334 5ustar debacledebacletrac-wikiprint-4.0.0+svn18614/tracpdf/htdocs/css/0000755000175500017550000000000014051376115021124 5ustar debacledebacletrac-wikiprint-4.0.0+svn18614/tracpdf/htdocs/css/wikiprint.css0000644000175500017550000000004214051376115023652 0ustar debacledebacle.pdf-parameters { width: 40em; }trac-wikiprint-4.0.0+svn18614/tracpdf/__init__.py0000644000175500017550000000310614051376115021161 0ustar debacledebacle# -*- coding: utf-8 -*- # Copyright (c) 2021 Cinc # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import pkg_resources pkg_resources.require('Trac >= 1.4') del pkg_resources from .admin import * from .pdfbook import PdfBook from .wikiprint import * trac-wikiprint-4.0.0+svn18614/tracpdf/pdfbook.py0000644000175500017550000001126714051376115021055 0ustar debacledebacle# -*- coding: utf-8 -*- # Copyright (c) 2021 Cinc # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. try: from ConfigParser import ConfigParser PY2 = True except ImportError: from configparser import ConfigParser PY2 = False from io import StringIO from trac.util.html import tag from trac.util.text import to_unicode from trac.util.translation import _ from trac.wiki.formatter import format_to_html from trac.wiki.macros import WikiMacroBase def parse_makro_content(content): """Parse the makro contents holding the configuration for a PDF book. :param content: wiki text specifying the PDF book. :return dict with: {'coverpage': name of wiki page to use as cover, 'toc': True|False - wether to add a table of contents, 'pages': list of wiki page names } Note: see makro documentation for a description of the expected format. """ config = ConfigParser(allow_no_value=True) config.optionxform = to_unicode if PY2: config.readfp(StringIO(content), "PdfBook") else: config.read_file(StringIO(content), "PdfBook") config['DEFAULT'] = {'cover': None, 'toc': False} pages = [page for page in config.options('pages') if page not in ('cover, toc')] data = {'coverpage': config.get('config', 'cover'), 'toc': config.getboolean('config', 'toc'), 'pages': pages} return data class PdfBook(WikiMacroBase): """Create a PDF book with configuration specified in the makro contents. The configuration from the makro is rendered to the user and a button added to create a PDF book. Note that only one !PdfBook makro on a wiki page is supported. Define the makro like this: {{{ {{{#!PdfBook [parameters] cover = CoverPage toc = 1 [pages] WikiStart WikiFormatting }}} }}} Only syntax of WikiProcessors is supported. ==== Configuration The content must be formatted like an ''INI'' file. The following sections are supported: {{{#!ini [parameters] # Name of a wiki page to be used as the cover page cover = CoverPage # Set to 1 for a table of contents, else set to 0 toc = 1 [pages] # Names of wiki pages to be added to the PDF book. WikiStart WikiFormatting }}} """ tmpl = """ Cover page: {coverpage} Table of contents: {toc} Pages: {pages} """ create_button = """ {{{ #!html
}}} """ def expand_macro(self, formatter, name, content, args=None): if args == None: return tag.div(tag.p(_("Makro PdfBook must be called as a WikiProcessor.")), class_="system-message warning") data = parse_makro_content(content) pages = ''.join([' %s[[BR]]' % page for page in data['pages']]) txt = self.tmpl.format(coverpage=data['coverpage'], pages=pages, toc='Yes' if data['toc'] else 'No') # resource.id is the current wiki page name url = formatter.context.href('wikiprintpdfbook', formatter.context.resource.id) txt += self.create_button % url return format_to_html(self.env, formatter.context, txt) trac-wikiprint-4.0.0+svn18614/tracpdf/admin.py0000644000175500017550000001645614050727336020532 0ustar debacledebacle# -*- coding: utf-8 -*- # Copyright (c) 2021 Cinc # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from collections import namedtuple from pkg_resources import resource_filename from trac.env import Component, implements from trac.config import BoolOption, Option from trac.perm import IPermissionRequestor from trac.admin import IAdminPanelProvider from trac.util.translation import _ from trac.web.chrome import add_warning, ITemplateProvider from trac.wiki.model import WikiPage _footer = namedtuple('Footer', 'value label') footerlst = [_footer('', 'No footer'), _footer('[page] / [topage]', '[page] / [topage]'), _footer('{pagename} - [page] / [topage]', ' - [page] / [topage]'),] def prepare_data_dict(self, req): _pp = namedtuple('PageProp', 'value label') stylelst = [_pp('', 'Trac default')] with self.env.db_query as db: for row in db("SELECT DISTINCT name FROM wiki WHERE name LIKE 'WikiPrint/Styles/%'"): stylelst.append(_pp(row[0], row[0].split('/')[-1])) return {'pagesizes': [_pp('A3', 'A3 (297 x 420 mm)'), _pp('A4', 'A4 (210 x 297 mm)'), _pp('A5', 'A5 (148 x 210 mm)'), _pp('B4', 'B4 (250 x 353 mm)'), _pp('B5', 'B5 (176 x 250 mm)'), _pp('B6', 'B6 (125 x 176 mm)'), _pp('Folio', 'Folio (210 x 330 mm)'), _pp('Legal', 'Legal (215.9 x 355.6 mm)'), _pp('Letter', 'Letter (215.9 x 279.4 mm)')], 'footerlst': footerlst, 'pagesize': req.args.get('pagesize') or self.pagesize, 'pdftitle': req.args.get('pdftitle') or self.pdftitle, 'footertext': req.args.get('footertext') or self.footertext, 'stylepage': req.args.get('stylepage') or self.stylepage, 'stylelst': stylelst, 'coverpage': req.args.get('coverpage') or self.coverpage, 'toc': req.args.get('toc', False) if 'coverpage' in req.args else self.toc, } pagesize = Option('wikiprint', 'pagesize', 'A4', 'Page size of PDF. Can be one of {{{A3, A4, A5, B4, B5, B6, Folio, Legal, Letter}}}') pdftitle = Option('wikiprint', 'title', '', 'Title of PDF. Part of the document properties. If left ' 'empty the name of the wikipage will be used.') footertext = Option('wikiprint', 'footertext', '[page] / [topage]', 'Footer text for PDF.[[BR]][[BR]]Note that there is a predefined list of footers used by ' 'the administration page. Any configured footer not in the list will be overwritten when ' 'saving parameters. When left empty no footer is added to the PDF. Currently defined ' 'footers:\n' '* {{{[page] / [topage]}}}\n' '* {{{{pagename} - [page] / [topage]}}}\n') stylepage = Option('wikiprint', 'stylepage', '', 'Wiki page holding CSS styles to apply when creating PDF files. If empty the ' 'Trac default styles will be used.[[BR]][[BR]]' 'The style page must be created at {{{WikiPrint/Styles/}}}.') toc = BoolOption('wikiprint', 'toc', 'enabled', "Whether to add a table of content when creating a PDF book.\n" "* {{{enabled}}}: add the table of content\n" "* {{{disabled}}}: don't add a table of content") coverpage = Option('wikiprint', 'coverpage', '', 'Wiki page to be used as a cover when creating a PDF book. ' 'Leave empty when no cover page should be added.') class WikiPrintAdmin(Component): """Configure PDF page default parameters. === Configuration The parameters configured on this page are written to ''trac.ini''. Here's a description of the relevant section. [[TracIni(wikiprint)]] """ implements(IAdminPanelProvider, IPermissionRequestor, ITemplateProvider) pagesize = pagesize pdftitle = pdftitle footertext = footertext stylepage = stylepage coverpage = coverpage toc = toc # IPermissionRequestor methods def get_permission_actions(self): return ['WIKIPRINT_ADMIN' ] # IAdminPanelProvider methods def get_admin_panels(self, req): if 'WIKIPRINT_ADMIN' in req.perm: yield ('wikiprint', 'Wikiprint', 'pdfparameters', 'Page Parameters') def render_admin_panel(self, req, cat, page, path_info): req.perm.require('WIKIPRINT_ADMIN') if req.method == 'POST' and req.args.get('save'): covpage = req.args.get('coverpage') if covpage: wpage = WikiPage(self.env, covpage) if covpage and not wpage.exists: add_warning(req, _("The given cover page does not exist.")) else: self.config.set('wikiprint', 'pagesize', req.args.get('pagesize')) self.config.set('wikiprint', 'title', req.args.get('pdftitle')) self.config.set('wikiprint', 'footertext', req.args.get('footertext')) self.config.set('wikiprint', 'stylepage', req.args.get('stylepage')) self.config.set('wikiprint', 'coverpage', req.args.get('coverpage')) if req.args.get('toc'): self.config.set('wikiprint', 'toc', 'enabled') else: self.config.set('wikiprint', 'toc', '') self.config.save() data = prepare_data_dict(self, req) return 'wikiprint_admin_parameters.html', data # ITemplateProvider methods def get_templates_dirs(self): """Return the path of the directory containing the provided templates.""" return [resource_filename(__name__, 'templates')] def get_htdocs_dirs(self): return [('wikiprint', resource_filename(__name__, 'htdocs'))] trac-wikiprint-4.0.0+svn18614/tracpdf/wikiprint.py0000644000175500017550000004140014546107647021454 0ustar debacledebacle# -*- coding: utf-8 -*- # Copyright (c) 2021 Cinc # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import base64 import re from pdfkit import from_url from trac.env import Component, implements from trac.mimeview.api import IContentConverter from trac.util.text import to_unicode from trac.util.translation import _ from trac.web.api import IRequestHandler from trac.web.chrome import add_ctxtnav, add_stylesheet, add_warning, web_context from trac.wiki.formatter import format_to_html from trac.wiki.model import WikiPage from trac.wiki.parser import WikiParser from .admin import coverpage, footertext, pagesize, prepare_data_dict, pdftitle, stylepage, toc from .pdfbook import parse_makro_content from .util import get_trac_css, writeResponse class WikiToPdf(Component): """Create a PDF page or a book from a wiki page. ==== Configuration {{{wkhtmltopdf}}} must be installed and in your path. Get it from https://wkhtmltopdf.org/ [[TracIni(wikiprint)]] Configuration can be done on the admin page. """ implements(IContentConverter, IRequestHandler) pagesize = pagesize pdftitle = pdftitle footertext = footertext stylepage = stylepage coverpage = coverpage toc = toc # IRequestHandler methods def match_request(self, req): match = re.match(r'/wikiprintparams(?:/(.+))?$', req.path_info) if match: if match.group(1): req.args['page'] = match.group(1) return True # This is a call from the PdfBook makro match = re.match(r'/wikiprintpdfbook(?:/(.+))?$', req.path_info) if match: if match.group(1): req.args['page'] = match.group(1) req.args['createbook'] = True return True def pagename_version_from_req(self, req): """Parse a request to get the name and version of the wiki page. :param req: Request object return tuple with pagename, version 'Note that version may be None. """ pagename = req.args.get('page') version = None if req.args.get('version'): # Allow version to be empty version = req.args.getint('version') return pagename, version def _get_pdf_book_config(self, req): """Get the PDF book configuration from the wiki page holding the PdfBook makro. :param req: Request object holding wiki page name :return dict with: {'coverpage': name of wiki page to use as cover, 'toc': True|False - wether to add a table of contents, 'pages': list of wiki page names } Note that only one PdfBook makro on the page is supported. """ pagename, version = self.pagename_version_from_req(req) page = WikiPage(self.env, pagename, version) req.perm(page.resource).require('WIKI_VIEW') text = page.text.splitlines() conf = [] in_macro = False for line in text: if not in_macro: block_start_match = None if WikiParser.ENDBLOCK not in line: block_start_match = WikiParser._startblock_re.match(line) # Handle start of a new block if block_start_match: if len(block_start_match.groups()) == 2 and block_start_match.group(2) == 'PdfBook': in_macro = True continue else: if WikiParser.ENDBLOCK not in line: conf.append(line) else: break return parse_makro_content('\n'.join(conf)) def process_request(self, req): """Handle the Pdf parameters page. After the user adjusted settings like cover page or page size he is redirected to the wiki page he came from with format='xxx' arg so the download of the PDF will happen. Additional args specify the chosen settings and control which kind of PDF will be created.""" pagename, version = self.pagename_version_from_req(req) if req.args.get('download'): # Download button on PDF settings page brought us here. covpage = req.args.get('coverpage') if covpage: page = WikiPage(self.env, covpage) if covpage and not page.exists: add_warning(req, _("The given cover page does not exist.")) else: # User adjusted settings. Now call "Download in other format" again. pdf_format = 'pdfbook' if req.args.get('coverpage') else 'pdfpage' req.redirect(req.href('wiki', pagename, version=version, format=pdf_format, pdftitle=req.args.get('pdftitle'), pagesize=req.args.get('pagesize'), footertext=req.args.get('footertext'), stylepage=req.args.get('stylepage'), coverpage=req.args.get('coverpage'), toc=req.args.get('toc'), download=1, pages=req.args.getlist('pages'))) # This overrides global settings from the admin page with adjustments # by the user. data = prepare_data_dict(self, req) if req.args.get('createbook'): # We are coming from the macro holding a list of pages to use for the PDF. # Update settings with config from macro book = self._get_pdf_book_config(req) data.update({'coverpage': req.args.get('coverpage') or book['coverpage'], 'toc': book['toc']}) else: book = {} pages = book['pages'] if 'pages' in book else [] data.update({'pagename': pagename, 'pages': pages, # 'pdfbook' is set when we are coming from 'convert_content()' # 'coverpage' is set when we have a cover page error on the settings page # and reload the page. In that case the 'pdfbook' info is not available. 'pdfbook': req.args.get('pdfbook')}) # or 'coverpage' in req.args}) add_stylesheet(req, 'wikiprint/css/wikiprint.css') add_ctxtnav(req, _("Back to %s" % pagename), req.href('wiki', pagename, version=version)) return 'wikiprint_parameters.html', data # IContentConverter methods def get_supported_conversions(self): """Return an iterable of tuples in the form (key, name, extension, in_mimetype, out_mimetype, quality) representing the MIME conversions supported and the quality ratio of the conversion in the range 0 to 9, where 0 means no support and 9 means "perfect" support. eg. ('latex', 'LaTeX', 'tex', 'text/x-trac-wiki', 'text/plain', 8)""" yield 'pdfpage', _("PDF Page"), 'pdf', 'text/x-trac-wiki', 'application/pdf', 8 yield 'pdfpagecustom', _("PDF Page (custom settings)"), 'pdf', 'text/x-trac-wiki', 'application/pdf', 8 yield 'pdfbook', _("PDF Book"), 'pdf', 'text/x-trac-wiki', 'application/pdf', 8 def convert_content(self, req, mimetype, content, key): """Convert the given content from mimetype to the output MIME type represented by key. Returns a tuple in the form (content, output_mime_type) or None if conversion is not possible. """ # Permission handling is done when creating the HTML data pagename, version = self.pagename_version_from_req(req) if not pagename: return None # Redirect to settings page. After parameters are chosen the method will be called # again but with format='pdfpage' if key == 'pdfpagecustom': req.redirect(req.href('wikiprintparams', pagename, version=version)) elif key == 'pdfbook' and not req.args.get('download'): # When 'download' is set we are coming from the settings page req.redirect(req.href('wikiprintparams', pagename, version=version, pdfbook=1)) pdfoptions = self.prepare_pdf_options(req, pagename) # Wiki urls will be handled using WikiToHtml component cover_page = req.args.get('coverpage') stylepage = req.args.get('stylepage') # If set the known table of content makros are removed from the wiki page filterwiki = 1 if key == 'pdfbook' else None cover_url = req.abs_href('wikiprint', cover_page, stylepage=stylepage) if cover_page else None page_lst = [] if req.args.get('toc'): page_lst.append('toc') # 'pages' are available when we create a PDF book from the makro PdfBook. The # makro holds a list of pages specified by the user. pages = req.args.getlist('pages') if pages: for page in pages: page_lst.append(req.abs_href('wikiprint', page, version=version, stylepage=stylepage, filterwiki=filterwiki)) else: page_lst.append(req.abs_href('wikiprint', pagename, version=version, stylepage=stylepage, filterwiki=filterwiki)) # Now call pdfkit without a file name so it returns the PDF. pdf_page = from_url(page_lst, False, options=pdfoptions, cover=cover_url, verbose=True) return pdf_page, 'application/pdf' def prepare_pdf_options(self, req, pagename): """Prepare the global wkhtmltopdf options used when generating a PDF page or book. :param req: Request object which may hold page settings :param pagename: name of the current wiki page :return: dict with wkhtmltopdf global options """ options = { 'page-size': req.args.get('pagesize') or self.pagesize, 'encoding': "UTF-8", 'outline': None, 'title': req.args.get('pdftitle') or self.pdftitle or pagename, } for name in ('trac_auth', 'trac_session'): if name in req.incookie: options['cookie'] = [(name, req.incookie[name].value)] break authorization = (req.get_header('Authorization') or '').split() if len(authorization) == 2 and authorization[0].lower() == 'basic': try: creds = base64.b64decode(authorization[1]) except: pass else: creds = creds.split(b':', 1) if len(creds) == 2: options['username'] = to_unicode(creds[0]) options['password'] = to_unicode(creds[1]) self._add_footer(options, pagename, req.args.get('footertext')) return options def _add_footer(self, options, pagename, footertext=None): """Add footer information to the global wkhtmltopdf options. :param options: dict with global options :param pagename: the name of the current wiki page :param footertext: footer text specified by the user :return: None The given options dict is updated in place. """ if not self.footertext and not footertext: return footertext = footertext or self.footertext if '{pagename}' in footertext: options.update({'footer-center': footertext.format(pagename=pagename)}) else: options.update({'footer-center': footertext}) options.update({'footer-line': None, 'footer-font-size': 10}) FILTER_WIKI_RES = [ re.compile(r'\[\[TracGuideToc\]\]'), re.compile(r'\[\[PageOutline(\(.*\))?\]\]'), ] default_page_tmpl =u""" {wiki} """ class WikiToHtml(Component): """Create a HTML page from a wiki page. The page only holds the wiki content for easy printing.""" implements(IContentConverter, IRequestHandler) # IRequestHandler methods def match_request(self, req): match = re.match(r'/wikiprint(?:/(.+))?$', req.path_info) if match: if match.group(1): req.args['page'] = match.group(1) return True def process_request(self, req): """Create a HTML page from a wiki page omitting the Trac chrome.""" pagename = req.args.get('page') # We allow page versions version = req.args.get('version', None) page = WikiPage(self.env, pagename, version) req.perm(page.resource).require('WIKI_VIEW') if page.exists: html_page = self.create_html_page(req, page.text) else: html_page = '' writeResponse(req, html_page, content_type='text/html; charset=utf-8') # IContentConverter methods def get_supported_conversions(self): """Return an iterable of tuples in the form (key, name, extension, in_mimetype, out_mimetype, quality), eg. ('latex', 'LaTeX', 'tex', 'text/x-trac-wiki', 'text/plain', 8)""" yield 'htmlpage', _("Printable HTML"), 'html', 'text/x-trac-wiki', 'text/html; charset=utf-8', 8 def convert_content(self, req, mimetype, content, key): """Returns a tuple in the form (content, output_mime_type) or None if conversion is not possible. """ pagename = req.args.get('page') if not pagename: return None version = None if req.args.get('version'): # Allow version to be empty version = req.args.getint('version') # We don't send data for downloading here but redirect to a page only # showing the contents (no Trac chrome). req.redirect(req.href('wikiprint', pagename, version=version)) # html_page = self.create_html_page(req, content) # return html_page, 'text/html; charset=utf-8' # Helper methods for IContentConverter page_tmpl = default_page_tmpl def _get_styles(self, stylepage): page = WikiPage(self.env, stylepage) if page.exists: return page.text # Get standard Trac styles trac_css = get_trac_css(self.env, 'trac.css') wiki_css = get_trac_css(self.env, 'wiki.css') return u"%s\n%s" % (trac_css, wiki_css) def create_html_page(self, req, wikitext): pagename = req.path_info # This is something like /wiki/WikiStart pagename = pagename.split('/')[-1] stylepage = req.args.get('stylepage', 'WikiPrint/StylesHtmlPage') # Filter out macros e.g. [[TracGuideToc]] or [[PageOutline]]. Usually done # when creating a PDF book. if req.args.get('filterwiki'): for rec in FILTER_WIKI_RES: wikitext = rec.sub('', wikitext) wiki_html = wiki_to_html(self.env, req, pagename, wikitext) return self.page_tmpl.format(wiki=wiki_html, style=self._get_styles(stylepage)) def wiki_to_html(env, req, pagename, wikitext): """Convert the given wikitext to html. :param env: Trac Environment object :param req: Request object :param pagename: name of the wiki page :param wikitext: raw eiki page content as users type it :return html data as a string. Note that this is a fragment, meaning no '' tags, no doctype and friends. """ context = web_context(req, 'wiki', pagename) page_html = format_to_html(env, context, wikitext) # Insert style information return to_unicode(page_html) trac-wikiprint-4.0.0+svn18614/tracpdf/templates/0000755000175500017550000000000014052154273021046 5ustar debacledebacletrac-wikiprint-4.0.0+svn18614/tracpdf/templates/wikiprint_parameters.html0000644000175500017550000001136414052154273026204 0ustar debacledebacle{# # Copyright (C) 2021 Cinc # # All rights reserved. # # License: 3-clause BSD #} # extends 'layout.html' # block title PDF Parameters ${ super() } # endblock title # block head ${ super() } # endblock head # block content

PDF Parameters for ${pagename}

# if pdfbook:
${_("Book parameters")}

The following parameters apply when creating a PDF book.

${_("Configure a wiki page used as a cover when creating a PDF book.")}

# if pages:
Pages
    # for page in pages:
  • ${page}
  • # endfor
# endif # endif
${_("Page size")}
${_("Footer")}
${_("Style page")}

Add CSS style information to wiki pages at WikiPrint/Styles/ to define your own styles. For example: WikiPrint/Styles/MyStyle.

${_("Document Properties")}

${_("Leave empty to use the name of the wiki page as the title.")}

Use the context navigation to go back to ${pagename}.

# endblock content trac-wikiprint-4.0.0+svn18614/tracpdf/templates/wikiprint_admin_parameters.html0000644000175500017550000000655614052154273027363 0ustar debacledebacle{# # Copyright (C) 2021 Cinc # # All rights reserved. # # License: 3-clause BSD #} # extends 'admin.html' # block admintitle PDF Parameters # endblock admintitle # block head ${ super() } # endblock head # block adminpanel

PDF Parameters

${jmacros.form_token_input()}

These parameters apply to PDF file creation when not overriden by the user.

${_("Book parameters")}

The following parameters apply when creating a PDF book.

${_("Configure a wiki page used as a cover when creating a PDF book.")}

${_("Page size")}
${_("Footer")}
${_("Style page")}

Add CSS style information to wiki pages at WikiPrint/Styles/ to define your own styles. For example: WikiPrint/Styles/MyStyle.

${_("Document Properties")}

${_("Leave empty to use the name of the wiki page as the title.")}

# endblock adminpanel trac-wikiprint-4.0.0+svn18614/README.md0000644000175500017550000001323414052032150016674 0ustar debacledebacleTracWikiPrintPlugin =================== This plugin allows you to export to PDF (book or article format) or printable HTML format (page contents without Trac headers/footers) allowing easy printing. PDF export is based on [wkhtmltopdf](https://wkhtmltopdf.org/). Older versions up to V3.0.0 used [xhtml2pdf](http://www.xhtml2pdf.com/) for generating PDF files. While having the advantage of being a pure Python solution it was abandoned because the output quality of [wkhtmltopdf](https://wkhtmltopdf.org/) is way better. For these unsupported older releases see [WikiPrintXhtml2pdf](https://trac-hacks.org/wiki/TracWikiPrintPlugin/WikiPrintXhtml2pdf). Key features: * Administration page for default settings. * Customizable footers for PDF. * Customizable front page for PDF book format. * Automatic creation of Table of Contents for PDF books. * The style of the resulting PDF or HTML can be fully customized using CSS. * Different page sizes. * PDF "print dialog" for altering settings prior to PDF file creation. * Makro to specify contents and format of PDF Books with export feature. The plugin is seamlessly integrated in the Trac user interface by adding items to the `Download in other formats` section of each wiki page. The full documentation can be found on the homepage: [TracWikiPrintPlugin](https://trac-hacks.org/wiki/TracWikiPrintPlugin) (https://trac-hacks.org/wiki/TracWikiPrintPlugin) ### Supported Trac releases Trac 1.4 and 1.6 are fully supported. For older releases use TracWikiPrintPlugin V3.x.x or older. License ------- Releases up to V3.x.x were licensed as GPL. With V4.0.0 the plugin was rewritten from scratch and is now BSD licensed. Download -------- Download the zipped source from [here](https://trac-hacks.org/browser/tracwikiprintplugin?format=zip). Source ------ You can check out [TracWikiPrintPlugin](https://trac-hacks.org/wiki/TracWikiPrintPlugin) from [here](https://trac-hacks.org/svn/tracwikiprintplugin) using Subversion, or [browse the source](https://trac-hacks.org/browser/tracwikiprintplugin) with Trac. Installation ------------ To install the plugin from trunk: $ pip install https://trac-hacks.org/svn/tracwikiprintplugin/trunk To install the older `V3.0.0` release: $ pip install https://trac-hacks.org/svn/tracwikiprintplugin/tags/V3.0.0 Install [wkhtmltopdf](https://wkhtmltopdf.org/). *Note:* [wkhtmltopdf](https://wkhtmltopdf.org/) must be in your path or more precisely in the path used by Trac. Enable the plugin using Tracs plugin administration page or by adding `wikiprint.* = enabled` in the components section of your `trac.ini` file: ``` [components] ... wikiprint.* = enabled ``` Usage ----- After the plugin is enabled, a new administration panel will be available under the `Wikiprint` section, and 4 new download formats will be available in the `Download in other formats` section at the end of each wiki page: * Printable HTML * PDF Page * PDF Page (custom settings) * PDF Book A new makro `PdfBook` can be used to create PDF books from any number of wiki pages. ### Administration page The default configuration for page exports may be provided using the `Wikiprint` administration page. These settings apply when not overriden by the user while exporting a PDF. While most settings are related to PDF files the style page specified here also applies when generating the `Printable HTML` page. ### Printable HTML The wiki page is stripped from Tracs footer, header and navigation. The resulting page only contains the wiki content. Styling of the page is according to the style page selected using the administration panel. ### PDF Page `PDF Page` creates a PDF file out of the wiki page, with no cover page. Styles will be used from the style page defined in the global configuration set with the administration panel. Table of contents macros in the wiki page like `[[PageOutline()]]` or others are not stripped from the page. ### PDF Page (custom settings) The wiki page is exported as a PDF file. This is like normal `PDF Page` export but it is possible to override the global configuration while generating the PDF file. A settings page similar to a "print dialog" is presented to the user before the actual export happens. ### PDF Book This will create a book-like PDF document. While exporting the user is presented with a settings page to specify a cover page and whether a table of contents should be added. Styling may be changed by selecting one of the available style page. The cover page used for the book may be any wiki page. Common table of contents macros in the wiki page like `[[PageOutline()]]` or `[[TracGuideToc()]]` are removed from each wiki page. ### PdfBook makro Using the makro it is possible to define PDF books with any number of wiki pages a cover page and table of contents. The configuration specified in the makro may always be overriden by the user while creating the book. This way one may for example change the predefined cover page or omitt the table of contents. Note that you can't add or remove pages while creating the book. The configuration from the makro is rendered to the user and a button added to create the PDF book. Note that only one PdfBook makro on a wiki page is supported. The makro must be specified in WikiProcessors syntax: ``` {{{#!PdfBook ... }}} ``` The contents must be formatted like an INI file. The following sections are defined: * `[parameters]`: specify cover page and table of contents * `[pages]`: list of wiki pages to add to the book. ``` {{{#!PdfBook [parameters] # Name of a wiki page to be used as the cover page cover = CoverPage # Set to 1 for a table of contents, else set to 0 toc = 1 [pages] # Names of wiki pages to be added to the PDF book. WikiStart WikiFormatting }}} ``` trac-wikiprint-4.0.0+svn18614/setup.cfg0000644000175500017550000000015114546110410017234 0ustar debacledebacle[egg_info] tag_build = dev [aliases] release = sdist bdist_wheel bdist_egg [bdist_wheel] universal = 1 trac-wikiprint-4.0.0+svn18614/setup.py0000644000175500017550000000551114546116543017147 0ustar debacledebacle# -*- coding: utf-8 -*- # Copyright (c) 2021 Cinc # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from setuptools import setup with open("README.md", "r") as fh: long_description = fh.read() setup( name='TracWikiPrint', version='4.0.0', packages=['tracpdf'], package_data={ 'tracpdf': ['templates/*.html', 'htdocs/css/*.css'], }, install_requires=['pdfkit', 'trac'], author='Cinc-th', author_email='', maintainer="Cinc-th", license='BSD', url="http://trac-hacks.org/wiki/TracWikiPrintPlugin", description='Create PDF files from Tracs wiki pages', long_description=long_description, long_description_content_type='text/markdown', keywords='PDF wiki trac plugin', classifiers=['Development Status :: 4 - Beta', 'Environment :: Plugins', 'Environment :: Web Environment', 'Framework :: Trac', 'Intended Audience :: End Users/Desktop', 'License :: OSI Approved :: BSD License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', ], entry_points={'trac.plugins': [ 'tracpdf.wikiprint = tracpdf.wikiprint', 'tracpdf.admin = tracpdf.admin', 'tracpdf.pdfbook = tracpdf.pdfbook', ]}, test_suite='tests' )