trac-wikiprint-4.0.0+svn18314/ 0000755 0001755 0001755 00000000000 14513443135 015422 5 ustar debacle debacle trac-wikiprint-4.0.0+svn18314/COPYING 0000644 0001755 0001755 00000002546 14050534752 016466 0 ustar debacle debacle 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. trac-wikiprint-4.0.0+svn18314/tracpdf/ 0000755 0001755 0001755 00000000000 14052154273 017045 5 ustar debacle debacle trac-wikiprint-4.0.0+svn18314/tracpdf/util.py 0000644 0001755 0001755 00000005102 14052032150 020357 0 ustar debacle debacle # -*- 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 os
from imp import find_module
from trac.util.text import to_unicode
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.
try:
with open(os.path.join(mod[1], 'htdocs', 'css', css_file), 'r') as f:
return to_unicode(f.read(-1))
except FileNotFoundError:
return to_unicode(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+svn18314/tracpdf/htdocs/ 0000755 0001755 0001755 00000000000 14051376115 020331 5 ustar debacle debacle trac-wikiprint-4.0.0+svn18314/tracpdf/htdocs/css/ 0000755 0001755 0001755 00000000000 14051376115 021121 5 ustar debacle debacle trac-wikiprint-4.0.0+svn18314/tracpdf/htdocs/css/wikiprint.css 0000644 0001755 0001755 00000000042 14051376115 023647 0 ustar debacle debacle .pdf-parameters {
width: 40em;
} trac-wikiprint-4.0.0+svn18314/tracpdf/__init__.py 0000644 0001755 0001755 00000003106 14051376115 021156 0 ustar debacle debacle # -*- 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+svn18314/tracpdf/pdfbook.py 0000644 0001755 0001755 00000011267 14051376115 021052 0 ustar debacle debacle # -*- 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+svn18314/tracpdf/admin.py 0000644 0001755 0001755 00000016456 14050727336 020527 0 ustar debacle debacle # -*- 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+svn18314/tracpdf/wikiprint.py 0000644 0001755 0001755 00000040250 14052154273 021440 0 ustar debacle debacle # -*- 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 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)
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,
'cookie': [
('trac_auth', req.incookie['trac_auth'].value),
]
}
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+svn18314/tracpdf/templates/ 0000755 0001755 0001755 00000000000 14052154273 021043 5 ustar debacle debacle trac-wikiprint-4.0.0+svn18314/tracpdf/templates/wikiprint_parameters.html 0000644 0001755 0001755 00000011364 14052154273 026201 0 ustar debacle debacle {#
# 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}
# endblock content
trac-wikiprint-4.0.0+svn18314/tracpdf/templates/wikiprint_admin_parameters.html 0000644 0001755 0001755 00000006556 14052154273 027360 0 ustar debacle debacle {#
# 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
# endblock adminpanel
trac-wikiprint-4.0.0+svn18314/README.md 0000644 0001755 0001755 00000013234 14052032150 016671 0 ustar debacle debacle TracWikiPrintPlugin
===================
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+svn18314/setup.cfg 0000644 0001755 0001755 00000000114 14050534752 017241 0 ustar debacle debacle [egg_info]
tag_build = dev
[aliases]
release = sdist bdist_wheel bdist_egg
trac-wikiprint-4.0.0+svn18314/setup.py 0000644 0001755 0001755 00000005412 14051667261 017143 0 ustar debacle debacle # -*- 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'
]
},
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,
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'
)