1.4/0000755000175000017500000000000014744202666011537 5ustar bgermannbgermann1.4/setup.cfg0000644000175000017500000000010214744202666013351 0ustar bgermannbgermann[egg_info] tag_build = dev [aliases] release = sdist bdist_wheel 1.4/setup.py0000644000175000017500000000221114744202666013245 0ustar bgermannbgermann""" Copyright (C) 2009 Polar Technologies - www.polartech.es Author: Alvaro Iradier """ from setuptools import setup setup( name='TracWikiPrint', version='3.0', packages=['wikiprint'], package_data={'wikiprint': ['templates/*', 'htdocs/js/*']}, author="Alvaro J. Iradier", author_email="alvaro.iradier@polartech.es", maintainer="Alvaro J. Iradier", maintainer_email="alvaro.iradier@polartech.es", description="Generating PDF files or printable HTML from Wiki pages", long_description="WikiPrintPlugin was developed based on the work of coderanger, athomas and diorgenes (WikiToPdf). It improves WikiToPdfPlugin to use a pure python library (xhtml2pdf/PISA) to generate PDF files. ", license="GPL", keywords="trac plugin wiki pdf", url="http://trac-hacks.org/wiki/TracWikiPrintPlugin", entry_points={ 'trac.plugins': [ 'wikiprint.formats = wikiprint.formats', 'wikiprint.web_ui = wikiprint.web_ui', 'wikiprint.wikiprint = wikiprint.wikiprint', ], }, install_requires=['pillow < 7', 'xhtml2pdf', 'Trac'], ) 1.4/tests/0000755000175000017500000000000014744202666012701 5ustar bgermannbgermann1.4/tests/test_wiki_table.py0000644000175000017500000000702614744202666016431 0ustar bgermannbgermann# -*- coding: utf-8 -*- # Copyright (c) 2019 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 unittest try: import pygments from pygments.formatters.html import HtmlFormatter except ImportError: pygments_loaded = False else: get_style_by_name = pygments.styles.get_style_by_name pygments_loaded = True from trac.test import EnvironmentStub, Mock, MockRequest from wikiprint.wikiprint import WikiPrint class TestWikiTable(unittest.TestCase): @staticmethod def _log(*kwargs): try: msg, parm = kwargs print(msg % parm) except ValueError: print(kwargs[0]) def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'wikiprint.*', ]) self.log = Mock(info=self._log, debug=self._log, error=self._log, handlers=[]) self.env.log = self.log self.plugin = WikiPrint(self.env) def tearDown(self): self.env.shutdown() def test_table(self): req = MockRequest(self.env) table = """== Table ||= Header 1 =||= Header 2 =|| {{{#!td TD 1 }}} {{{#!td TD 2 }}} """ html_page = self.plugin.wikipage_to_html(table, 'FooPage', req) pdf = self.plugin.html_to_pdf(req, [html_page], False) self.assertIsNotNone(pdf) def test_broken_table(self): req = MockRequest(self.env) table = """== Broken Table ||= Header 1 =||= Header 2 =|| {{{#!td TD 1 }}} {{{#!td TD 2 }}} """ # This creates a second table with empty (no ) # There is an empty line preceeding '|--------------' txt = table + "\n|----------------------------------" html_page = self.plugin.wikipage_to_html(txt, 'FooPage', req) self.assertIsNotNone(self.plugin.html_to_pdf(req, [html_page], False)) # This adds an empty to the table txt = table + "|----------------------------------" html_page = self.plugin.wikipage_to_html(txt, 'FooPage', req) self.assertIsNotNone(self.plugin.html_to_pdf(req, [html_page], False)) if __name__ == '__main__': unittest.main() 1.4/docs/0000755000175000017500000000000014744202666012467 5ustar bgermannbgermann1.4/docs/trac.ini.example0000644000175000017500000000050214744202666015550 0ustar bgermannbgermann[components] wikiprint.* = enabled [wikiprint] toc_title = "Table of Contents" #CSS and content files (or URLS, using http://...) css_url=c:/path/to/file.css article_css_url=c:/path/to/article.css book_css_url=c:/path/to/book.css frontpage_url=c:/path/to/frontpage.html extracontent_url=c:/path/to/extracontent.html1.4/wikiprint/0000755000175000017500000000000014744202666013557 5ustar bgermannbgermann1.4/wikiprint/formats.py0000644000175000017500000000454114744202666015610 0ustar bgermannbgermann""" Copyright (C) 2008 Prognus Software Livre - www.prognus.com.br Author: Diorgenes Felipe Grzesiuk Modified by: Alvaro Iradier """ from trac.core import Component, implements from trac.web.api import RequestDone from trac.wiki.model import WikiPage from .api import IWikiPrintFormat from .wikiprint import WikiPrint class WikiPrintOutput(Component): """Add output formats PDF using PISA (xhtml2pdf) or Printable HTML to the WikiPrint plugin.""" implements(IWikiPrintFormat) def wikiprint_formats(self, req): yield 'pdfarticle', 'PDF Article' yield 'pdfbook', 'PDF Book' yield 'printhtml', 'HTML' def process_wikiprint(self, req, format, title, subject, pages, version, date, pdfname): wikiprint = WikiPrint(self.env) html_pages = [ wikiprint.wikipage_to_html(WikiPage(self.env, p).text, p, req) for p in pages ] # Send the output req.send_response(200) req.send_header('Content-Type', { 'pdfbook': 'application/pdf', 'pdfarticle': 'application/pdf', 'printhtml': 'text/html'}[format]) out = '' if format == 'pdfbook': out = wikiprint.html_to_pdf(req, html_pages, book=True, title=title, subject=subject, version=version, date=date) req.send_header('Content-Disposition', 'attachment; filename=' + pdfname + '.pdf') elif format == 'pdfarticle': out = wikiprint.html_to_pdf(req, html_pages, book=False, title=title, subject=subject, version=version, date=date) req.send_header('Content-Disposition', 'attachment; filename=' + pdfname + '.pdf') elif format == 'printhtml': out = wikiprint.html_to_printhtml(req, html_pages, title=title, subject=subject, version=version, date=date) req.send_header('Content-Length', len(out)) req.end_headers() req.write(out) raise RequestDone 1.4/wikiprint/__init__.py0000644000175000017500000000007314744202666015670 0ustar bgermannbgermannimport pkg_resources pkg_resources.require('Trac >= 1.4') 1.4/wikiprint/api.py0000644000175000017500000000120114744202666014674 0ustar bgermannbgermann""" Copyright (C) 2008 Prognus Software Livre - www.prognus.com.br Author: Diorgenes Felipe Grzesiuk Modified by: Alvaro Iradier """ from trac.core import Interface class IWikiPrintFormat(Interface): """An extension point for adding output formats to the WikiPrint plugin.""" def wikiprint_formats(self, req): """Return an iterable of (format, name).""" def process_wikiprint(self, req, format, title, subject, top, bottom, right, left, header, toctitle, pages): """Process and return the wiki output in the given format.""" 1.4/wikiprint/wikiprint.py0000644000175000017500000004512414744202666016157 0ustar bgermannbgermann# -*- coding: utf-8 -*- # Copyright (C) 2008 Prognus Software Livre - www.prognus.com.br # Copyright (C) 2021 Cinc # # Author: Diorgenes Felipe Grzesiuk # Modified by: Alvaro Iradier import os import re import tempfile import time try: from StringIO import StringIO as WikiPrintIO import urllib2 as url_lib import urlparse as url_parse import defaults PY2 = True except ImportError: import urllib.request as url_lib import urllib.parse as url_parse from io import BytesIO as WikiPrintIO from io import StringIO as OutlineIO import wikiprint.defaults as defaults PY2 = False from pkg_resources import resource_filename from trac.config import Option, BoolOption, ListOption from trac.core import * from trac.mimeview.api import IContentConverter from trac.resource import Resource from trac.web.api import IAuthenticator from trac.web.chrome import web_context from trac.wiki.formatter import OutlineFormatter, format_to_html from trac.wiki.model import WikiPage from trac.util import hex_entropy from trac.util.datefmt import format_datetime, to_datetime from trac.util.html import Markup from trac.util.text import to_unicode try: import xhtml2pdf.pisa as pisa except ImportError: import ho.pisa as pisa # Kludge to workaround the lack of absolute imports in Python version prior to # 2.5 try: # TODO: A better way of importing and checking pygments? # Copied from trac.mimeview.pigments pygments = __import__('pygments', {}, {}, ['lexers', 'styles', 'formatters']) except ImportError: pygments_loaded = False else: HtmlFormatter = pygments.formatters.html.HtmlFormatter get_style_by_name = pygments.styles.get_style_by_name pygments_loaded = True EXCLUDE_RES = [ re.compile(r'\[\[TracGuideToc([^]]*)\]\]'), re.compile(r'----(\r)?$\n^Back up: \[\[ParentWiki\]\]', re.M | re.I), ] FIX_HTML_RES = [ # removing empty reportlab/platypus/tables.py chokes on re.compile(r'\s*') ] class linkLoader: """ Helper to load page from an URL and load corresponding files to temporary files. If getFileName is called it returns the temporary filename and takes care to delete it when linkLoader is unloaded. """ def __init__(self, env, req, auth_cookie=None, allow_local=False): self.tfileList = [] self.env = env self.auth_cookie = auth_cookie self.req = req self.allow_local = allow_local self.env.log.debug('WikiPrint.linkLoader => Initializing') def __del__(self): for path in self.tfileList: self.env.log.debug("WikiPrint.linkLoader => deleting %s", path) os.remove(path) def getFileName(self, name, relative=''): try: if name.startswith('http://') or name.startswith('https://'): self.env.log.debug( "WikiPrint.linkLoader => Resolving URL: %s", name) url = url_parse.urljoin(relative, name) self.env.log.debug( "WikiPrint.linkLoader => urljoined URL: %s", url) elif self.allow_local: self.req.perm.assert_permission('WIKIPRINT_FILESYSTEM') self.env.log.debug( "WikiPrint.linkLoader => Resolve local filesystem %s", name) return name else: # Relative path self.env.log.debug( "WikiPrint.linkLoader => Relative path %s to %s", name, url_parse.urljoin(self.req.abs_href(), name)) url = url_parse.urljoin(self.req.abs_href(), name) path = url_parse.urlsplit(url)[2] self.env.log.debug("WikiPrint.linkLoader => path: %s", path) suffix = '' if '.' in path: new_suffix = '.' + path.split(".")[-1].lower() if new_suffix in ('.css', '.gif', '.jpg', '.png', '.ttf', '.ttc'): suffix = new_suffix path = tempfile.mktemp(prefix='pisa-', suffix=suffix) # Allow wikiprint to authenticate using user and password, # Basic HTTP Auth or Digest if self.env.config.get('wikiprint', 'httpauth_user'): pwmgr = url_lib.HTTPPasswordMgrWithDefaultRealm() pwmgr.add_password( None, url, self.env.config.get('wikiprint', 'httpauth_user'), self.env.config.get('wikiprint', 'httpauth_password')) auth_handler = url_lib.HTTPBasicAuthHandler(pwmgr) auth_handler2 = url_lib.HTTPDigestAuthHandler(pwmgr) opener = url_lib.build_opener(auth_handler, auth_handler2) url_lib.install_opener(opener) # Prepare the request with the auth cookie request = url_lib.Request(url) self.env.log.debug( "Adding cookie to HTTP request: pdfgenerator_cookie=%s", self.auth_cookie) request.add_header( "Cookie", "pdfgenerator_cookie=%s" % self.auth_cookie) # Make the request and download the file ufile = url_lib.urlopen(request) tfile = file(path, 'wb') size = 0 while True: data = ufile.read(1024) if not data: break # print data size += len(data) tfile.write(data) ufile.close() tfile.close() self.tfileList.append(path) self.env.log.debug( "WikiPrint.linkLoader => loading %s to %s, %d bytes", url, path, size) return path except Exception as e: self.env.log.debug("WikiPrint.linkLoader ERROR: %s", e) return None class WikiPrint(Component): """The core module where all conversion takes place. It must be enabled for the other modules to work correctly""" toc_title = Option('wikiprint', 'toc_title', 'Table of Contents') css_url = Option('wikiprint', 'css_url') book_css_url = Option('wikiprint', 'book_css_url') article_css_url = Option('wikiprint', 'article_css_url') frontpage_url = Option('wikiprint', 'frontpage_url') extracontent_url = Option('wikiprint', 'extracontent_url') httpauth_user = Option('wikiprint', 'httpauth_user') httpauth_password = Option('wikiprint', 'httpauth_password') omit_links = BoolOption('wikiprint', 'omit_links') local_anchor = BoolOption('wikiprint', 'local_anchor', False) omit_macros = ListOption('wikiprint', 'omit_macros') rebase_links = Option('wikiprint', 'rebase_links') default_charset = Option('trac', 'default_charset', 'utf-8') implements(IAuthenticator) def _get_name_for_cookie(self, cookie): for name, in self.env.db_query(""" SELECT name FROM auth_cookie WHERE cookie=%s """, (cookie.value,)): return name ### IAuthenticator methods def authenticate(self, req): authname = None self.env.log.debug("Trying pdfgenerator_cookie authentication") if 'pdfgenerator_cookie' in req.incookie: self.env.log.debug("Cookie found: %s", req.incookie['pdfgenerator_cookie'].value) authname = \ self._get_name_for_cookie(req.incookie['pdfgenerator_cookie']) return authname ### Public methods def wikipage_to_html(self, text, page_name, req): """Converts a wiki text to HTML, and makes some replacements in order to fix internal and external links and references """ self.env.log.debug('WikiPrint => Start function wikipage_to_html') #Remove exclude expressions for r in EXCLUDE_RES: text = r.sub('', text) #Escape [[PageOutline]], to avoid wiki processing for r in [re.compile(r'\[\[TOC(\(.*\))?\]\]'), re.compile(r'\[\[PageOutline(\(.*\))?\]\]')]: text = r.sub('![[pdf-toc]]', text) for macro in self.omit_macros: r = re.compile(r'\[\[' + macro + r'\(.*?\]\]') text = r.sub('', text) r = re.compile(r'^\{\{\{\r?\n#!' + macro + r'\r?\n(^.*\r?\n)*?^\}\}\}', re.MULTILINE) text = r.sub('', text) link_format = req.args.get('link_format', None) if self.omit_links: r1 = re.compile(r'\[wiki:(.*?) (.*?)\]') text = r1.sub('[\g<2>]', text) r2 = re.compile(r'\[wiki:(.*?)\]') text = r2.sub('[\g<1>]', text) elif link_format: #Keep links to the same export format r = re.compile(r'(?<=\[wiki:)(.*?)(?=(?: .*?)?\])') text = r.sub('\g<1>?format=%s&link_format=%s' % (link_format, link_format), text) if self.rebase_links: r = re.compile(r'\[wiki:(.*?)\]') text = r.sub('[%s/wiki/\g<1>]' % self.rebase_links, text) self.env.log.debug('WikiPrint => Wiki input for WikiPrint: %r', text) context = web_context(req, Resource('wiki', page_name)) page = format_to_html(self.env, context, text) for r in FIX_HTML_RES: page = r.sub('', page) self.env.log.debug('WikiPrint => Wiki to HTML output: %r', page) # Link to internal sections of document. if self.local_anchor: page = Markup('') + page r = re.compile(re.escape(req.abs_href.wiki()) + r'/([a-zA-Z0-9_/]*)(#?)') page = r.sub('#\g<1>/', page) r1 = re.compile(r'(span class="wikianchor" id=")(.*)(/span)') page = r1.sub('a name="' + page_name + '/\g<2>/a', page) r2 = re.compile(r'(h[0-9] id=")(.*)(">)') page = r2.sub('\g<1>' + page_name + '/\g<2>\g<3>', page) self.env.log.debug("WikiPrint => HTML input to html_to_pdf is: %r", page) self.env.log.debug('WikiPrint => Finish function wikipage_to_html') return page def html_to_pdf(self, req, html_pages, book=True, title='', subject='', version='', date=''): self.env.log.debug('WikiPrint => Start function html_to_pdf') page = Markup('\n
'.join(html_pages)) # Replace PageOutline macro with Table of Contents if book: # If book, remove [[TOC]], and add at beginning page = page.replace('[[pdf-toc]]', '') page = Markup(self.get_toc()) + Markup(page) else: page = page.replace('[[pdf-toc]]', self.get_toc()) page = self.add_headers(req, page, book, title=title, subject=subject, version=version, date=date) # page = page.encode(self.default_charset, 'replace') page = to_unicode(page) css_data = self.get_css(req) pdf_file = WikiPrintIO() auth_cookie = hex_entropy() loader = linkLoader(self.env, req, auth_cookie) # Temporary authentication self.env.log.debug("Storing temporary auth cookie %s for user %s", auth_cookie, req.authname) self.env.db_transaction(""" INSERT INTO auth_cookie (cookie, name, ipnr, time) VALUES (%s, %s, %s, %s) """, (auth_cookie, req.authname, '127.0.0.1', int(time.time()))) pdf = pisa.CreatePDF(page, pdf_file, show_errors_as_pdf=True, default_css=css_data, link_callback=loader.getFileName) out = pdf_file.getvalue() pdf_file.close() self.env.db_transaction(""" DELETE FROM auth_cookie WHERE cookie=%s """, (auth_cookie,)) self.env.log.debug('WikiPrint => Finish function html_to_pdf') return out def html_to_printhtml(self, req, html_pages, title='', subject='', version='', date='', ): self.env.log.debug('WikiPrint => Start function html_to_printhtml') page = Markup('
'.join(html_pages)) #TO-DO: Make a nice TOC for HTML printable output page = page.replace('[[pdf-toc]]', '') css_data = '' % self.get_css(req) page = self.add_headers(req, page, book=False, title=title, subject=subject, version=version, date=date, extra_headers=css_data) page = page.encode(self.default_charset, 'replace') return page def add_headers(self, req, page, book=False, title='', subject='', version='', date='', extra_headers=''): """Add HTML standard begin and end tags, and header tags and styles. Add front page and extra contents (header/footer), replacing #EXPRESSIONS (title, subject, version and date) """ extra_content = self.get_extracontent(req) extra_content = extra_content.replace('#TITLE', title) extra_content = extra_content.replace('#VERSION', version) extra_content = extra_content.replace('#DATE', date) extra_content = extra_content.replace('#SUBJECT', subject) if book: frontpage = self.get_frontpage(req) frontpage = frontpage.replace('#TITLE', title) frontpage = frontpage.replace('#VERSION', version) frontpage = frontpage.replace('#DATE', date) frontpage = frontpage.replace('#SUBJECT', subject) page = Markup(frontpage) + Markup(page) style = Markup(self.get_book_css(req)) else: style = Markup(self.get_article_css(req)) # Get pygments style if pygments_loaded: try: style_cls = get_style_by_name('trac') parts = style_cls.__module__.split('.') filename = resource_filename('.'.join(parts[:-1]), parts[-1] + '.py') formatter = HtmlFormatter(style=style_cls) content = to_unicode(u'\n\n'.join([ formatter.get_style_defs('div.code pre'), formatter.get_style_defs('table.code td') ])) style += Markup(content) except ValueError: pass page = \ Markup('') + \ Markup('' % self.default_charset) + \ Markup(extra_headers) + \ Markup('') + \ Markup('%s' % extra_content) + \ Markup(page) + \ Markup('') return page def get_file_or_default(self, req, file_or_url, default): loader = linkLoader(self.env, req, allow_local=True) if file_or_url: file_or_url = loader.getFileName(file_or_url) self.env.log.debug("wikiprint => Loading URL: %s", file_or_url) try: with open(file_or_url) as f: data = f.read() except: data = default else: data = default return to_unicode(data) def get_css(self, req): return self.get_file_or_default(req, self.css_url, defaults.CSS) def get_book_css(self, req): return self.get_file_or_default(req, self.book_css_url, defaults.BOOK_EXTRA_CSS) def get_article_css(self, req): return self.get_file_or_default(req, self.article_css_url, defaults.ARTICLE_EXTRA_CSS) def get_frontpage(self, req): return self.get_file_or_default(req, self.frontpage_url, defaults.FRONTPAGE) def get_extracontent(self, req): return self.get_file_or_default(req, self.extracontent_url, defaults.EXTRA_CONTENT) def get_toc(self): return Markup('

%s

' '
' % self.toc_title) class WikiToPDFPage(Component): """Add an option in wiki pages to export to PDF using PISA""" implements(IContentConverter) ### IContentConverter methods def get_supported_conversions(self): yield ('pdfarticle', 'PDF Article', 'pdf', 'text/x-trac-wiki', 'application/pdf', 7) yield ('pdfbook', 'PDF Book', 'pdf', 'text/x-trac-wiki', 'application/pdf', 7) def convert_content(self, req, input_type, text, output_type): page_name = req.args.get('page', 'WikiStart') wikipage = WikiPage(self.env, page_name) wikiprint = WikiPrint(self.env) page = wikiprint.wikipage_to_html(text, page_name, req) # Get page title from first header in outline if PY2: out = WikiPrintIO() else: out = OutlineIO() context = web_context(req, Resource('wiki', page_name)) outline = OutlineFormatter(self.env, context) outline.format(to_unicode(text), out, 1, 1) title = wikipage.name for depth, anchor, text in outline.outline: if depth == 1: title = text break out = \ wikiprint.html_to_pdf(req, [page], book=(output_type == 'pdfbook'), title=title, subject="%s - %s" % (self.env.project_name, page_name), version=to_unicode(wikipage.version), date=format_datetime(to_datetime(None))) return out, 'application/pdf' class WikiToHtmlPage(WikiPrint): """Add an option in wiki pages to export to printable HTML""" implements(IContentConverter) ### IContentConverter methods def get_supported_conversions(self): yield ('printhtml', 'Printable HTML', 'html', 'text/x-trac-wiki', 'text/html', 7) def convert_content(self, req, input_type, text, output_type): wikiprint = WikiPrint(self.env) page = wikiprint.wikipage_to_html(text, req.args.get('page', 'WikiStart'), req) out = wikiprint.html_to_printhtml(req, [page], self.default_charset) return out, 'text/html' 1.4/wikiprint/web_ui.py0000644000175000017500000002214714744202666015411 0ustar bgermannbgermann# -*- coding: utf-8 -*- # # Copyright (C) 2008 Prognus Software Livre - www.prognus.com.br # Copyright (C) 2021 Cinc # # Author: Diorgenes Felipe Grzesiuk # Modified by: Alvaro Iradier from trac.admin.api import IAdminPanelProvider from trac.core import Component, ExtensionPoint, TracError, implements from trac.perm import IPermissionRequestor from trac.util.text import to_unicode from trac.wiki.api import WikiSystem from trac.web.api import RequestDone from trac.web.chrome import add_notice, add_script, Chrome, ITemplateProvider try: import defaults except ImportError: import wikiprint.defaults as defaults from .api import IWikiPrintFormat from .wikiprint import linkLoader try: dict.iteritems except AttributeError: # Python 3 def itervalues(d): return iter(d.values()) def iteritems(d): return iter(d.items()) else: # Python 2 def itervalues(d): return d.itervalues() def iteritems(d): return d.iteritems() class WikiPrintAdmin(Component): """A plugin allowing the export of multiple wiki pages in a single file.""" formats = ExtensionPoint(IWikiPrintFormat) implements(IAdminPanelProvider, IPermissionRequestor, ITemplateProvider) # IPermissionRequestor methods def get_permission_actions(self): return ['WIKIPRINT_ADMIN', 'WIKIPRINT_FILESYSTEM', 'WIKIPRINT_BOOK'] # ITemplateProvider methods def get_templates_dirs(self): from pkg_resources import resource_filename return [resource_filename(__name__, 'templates')] def get_htdocs_dirs(self): from pkg_resources import resource_filename return [('wikiprint', resource_filename(__name__, 'htdocs'))] # IAdminPanelProvider methods def get_admin_panels(self, req): if req.perm.has_permission('WIKIPRINT_ADMIN'): yield ('wikiprint', 'WikiPrint', 'options', 'Options') if req.perm.has_permission('WIKIPRINT_BOOK'): yield ('wikiprint', 'WikiPrint', 'makebook', 'Make Book') def render_admin_panel(self, req, cat, page, component): if page == 'makebook': return self._render_book(req, cat, page, component) if page == 'options': return self._render_options(req, cat, page, component) def _render_book(self, req, cat, page, component): req.perm.assert_permission('WIKIPRINT_BOOK') data = {} allpages = list(WikiSystem(self.env).get_pages()) rightpages = [x for x in req.session.get('wikiprint_rightpages', '').split(',') if x] formats = {} for provider in self.formats: for format, name in provider.wikiprint_formats(req): formats[format] = { 'name': name, 'provider': provider, } if req.method == 'POST' and req.args.get('create'): rightpages = req.args.get('rightpages_all') title = req.args.get('title') or self.env.project_name subject = req.args.get('subject') date = req.args.get('date') version = req.args.get('version') format = req.args.get('format') req.session['wikiprint_rightpages'] = rightpages rightpages = rightpages.split(',') if not format or format not in formats: raise TracError('Bad format given for WikiPrint output.') pdfbookname = title.replace(' ', '_') \ .replace(':', '_') \ .replace(',', '_') return formats[format]['provider'] \ .process_wikiprint(req, format, title, subject, rightpages, version, date, pdfbookname) data['allpages'] = allpages leftpages = [x for x in allpages if x not in rightpages] leftpages.sort() data['leftpages'] = leftpages data['rightpages'] = rightpages data['formats'] = formats data['default_format'] = next(iter(formats)) data['iteritems'] = iteritems add_script(req, 'wikiprint/js/admin_wikiprint.js') if hasattr(Chrome, 'jenv'): return 'admin_wikibook_jinja.html', data else: return 'admin_wikibook.html', data def _render_options(self, req, cat, page, component): req.perm.assert_permission('WIKIPRINT_ADMIN') data = {} if req.method == 'POST' and req.args.get('saveurls'): self.env.config.set('wikiprint', 'css_url', req.args.get('css_url')) self.env.config.set('wikiprint', 'article_css_url', req.args.get('article_css_url')) self.env.config.set('wikiprint', 'book_css_url', req.args.get('book_css_url')) self.env.config.set('wikiprint', 'frontpage_url', req.args.get('frontpage_url')) self.env.config.set('wikiprint', 'extracontent_url', req.args.get('extracontent_url')) add_notice(req, "URLs saved") self.env.config.save() elif req.method == 'POST' and req.args.get('savehttpauth'): self.env.config.set('wikiprint', 'httpauth_user', req.args.get('httpauth_user')) self.env.config.set('wikiprint', 'httpauth_password', req.args.get('httpauth_password')) add_notice(req, "User and password saved") self.env.config.save() elif req.method == 'POST' and req.args.get('viewcss'): self.env.log.debug("Wikiprint, Viewing CSS") return self._send_resource_file(req, 'text/css', req.args.get('css_url'), defaults.CSS) elif req.method == 'POST' and req.args.get('viewbookcss'): self.env.log.debug("Wikiprint, Viewing Book CSS") return self._send_resource_file(req, 'text/css', req.args.get('book_css_url'), defaults.BOOK_EXTRA_CSS) elif req.method == 'POST' and req.args.get('viewarticlecss'): self.env.log.debug("Wikiprint, Viewing Article CSS") return self._send_resource_file(req, 'text/css', req.args.get('article_css_url'), defaults.ARTICLE_EXTRA_CSS) elif req.method == 'POST' and req.args.get('viewfrontpage'): self.env.log.debug("Wikiprint, Viewing Front page") return self._send_resource_file(req, 'text/html', req.args.get('frontpage_url'), defaults.FRONTPAGE) elif req.method == 'POST' and req.args.get('viewextracontent'): self.env.log.debug("Wikiprint, Viewing Extra Contents") return self._send_resource_file(req, 'text/html', req.args.get('extracontent_url'), defaults.EXTRA_CONTENT) data['css_url'] = self.env.config.get('wikiprint', 'css_url') data['article_css_url'] = \ self.env.config.get('wikiprint', 'article_css_url') data['book_css_url'] = \ self.env.config.get('wikiprint', 'book_css_url') data['frontpage_url'] = \ self.env.config.get('wikiprint', 'frontpage_url') data['extracontent_url'] = \ self.env.config.get('wikiprint', 'extracontent_url') data['httpauth_user'] = \ self.env.config.get('wikiprint', 'httpauth_user') data['httpauth_password'] = \ self.env.config.get('wikiprint', 'httpauth_password') if hasattr(Chrome, 'jenv'): return 'admin_wikiprint_jinja.html', data else: return 'admin_wikiprint.html', data def _send_resource_file(self, req, content_type, file, default_value): # Send the output if not file: out = default_value else: self.log.debug('## Viewing file %s' % file) linkloader = linkLoader(self.env, req, allow_local=True) resolved_file = linkloader.getFileName(file) if not resolved_file: raise Exception("File or URL load problem: %s (need " + "WIKIPRINT_FILESYSTEM permissions?)" % file) try: f = open(resolved_file) out = f.read() f.close() except IOError: raise Exception("File or URL load problem: %s (IO Error)" % file) del linkloader writeResponse(req, to_unicode(out)) 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) 1.4/wikiprint/templates/0000755000175000017500000000000014744202666015555 5ustar bgermannbgermann1.4/wikiprint/templates/admin_wikibook_jinja.html0000644000175000017500000001013114744202666022600 0ustar bgermannbgermann# extends 'admin.html' # block admintitle Make WikiPrint Book # endblock admintitle # block head ${ super() } # endblock head # block adminpanel

Create WikiPrint Book

${jmacros.form_token_input()}
Book Properties
Title:
Subject:
Version:
Date:
Select pages
All Pages
  
Selected Pages


Output Format # for format_name, format in iteritems(formats) # endfor
# endblock adminpanel 1.4/wikiprint/templates/admin_wikibook.html0000644000175000017500000000620214744202666021431 0ustar bgermannbgermann Make WikiPrint Book

Create WikiPrint Book

Book Properties
Title:
Subject:
Version:
Date:
Select pages
All Pages
  
Selected Pages


Output Format
1.4/wikiprint/templates/admin_wikiprint.html0000644000175000017500000000554414744202666021643 0ustar bgermannbgermann WikiPrint Options

Wikiprint Options

Style/Content Properties
Specify a path to a file in the local filesystem, or an URL to the resource.
Leave blank for using default styles or content.
CSS file or URL:
Book additional CSS file or URL:
Article additional CSS file or URL:
Book front page file or URL:
Header/footer/extra content file or URL:
HTTP Authentication
Specify a username and password that will be used when Wikiprint makes HTTP requests to recover document images or resources.
Supported methods are Basic and Digest authentication.
Username:
Password:
1.4/wikiprint/templates/admin_wikiprint_jinja.html0000644000175000017500000000727414744202666023020 0ustar bgermannbgermann# extends 'admin.html' # block admintitle WikiPrint Options # endblock admintitle # block head ${ super() } # endblock head # block adminpanel

Wikiprint Options

${jmacros.form_token_input()}
Style/Content Properties
Specify a path to a file in the local filesystem, or an URL to the resource.
Leave blank for using default styles or content.
CSS file or URL:
Book additional CSS file or URL:
Article additional CSS file or URL:
Book front page file or URL:
Header/footer/extra content file or URL:
HTTP Authentication
Specify a username and password that will be used when Wikiprint makes HTTP requests to recover document images or resources.
Supported methods are Basic and Digest authentication.
Username:
Password:
# endblock adminpanel 1.4/wikiprint/htdocs/0000755000175000017500000000000014744202666015043 5ustar bgermannbgermann1.4/wikiprint/htdocs/js/0000755000175000017500000000000014744202666015457 5ustar bgermannbgermann1.4/wikiprint/htdocs/js/admin_wikiprint.js0000644000175000017500000000207414744202666021210 0ustar bgermannbgermannfunction move_item(from, to) { var from_box = document.getElementById(from+'pages_select'); var to_box = document.getElementById(to+'pages_select'); for (var i = 0; i < from_box.options.length; i++) { var opt = from_box.options[i]; if (opt.selected) { var newopt = new Option(opt.innerHTML, opt.value); to_box.options.add(newopt); from_box.options[i] = null; i--; } } } function reorder_item(from, dir) { var box = document.getElementById(from+'pages_select'); var i = box.selectedIndex; var j = i + dir; if(j<0 || j>=box.options.length) { return } var temp = box.options[i]; var temp2 = box.options[j]; box.options[i] = new Option(temp2.value, temp2.value); box.options[j] = new Option(temp.value, temp.value); box.selectedIndex = j; } function compile_pages(form) { var arr = []; for(var i=0; i """ #Default CSS to use for xhtml2pdf CSS = """ html { font-family: Helvetica; font-size: 10px; font-weight: normal; color: #000000; background-color: transparent; margin: 0; padding: 0; line-height: 150%; border: 1px none; display: inline; width: auto; height: auto; white-space: normal; } b, strong { font-weight: bold; } i, em { font-style: italic; } u, .underline { text-decoration: underline; } s, strike { text-decoration: line-through; } a { text-decoration: underline; color: blue; } ins { color: green; text-decoration: underline; } del { color: red; text-decoration: line-through; } pre, code, kbd, samp, tt { font-family: "Courier New"; } h1, h2, h3, h4, h5, h6 { font-weight:bold; /* xhtml2 specific, include headers in outline */ -pdf-outline: true; -pdf-outline-open: false; } h1 { /*18px via YUI Fonts CSS foundation*/ font-size:138.5%; -pdf-outline-level: 0; } pdftoc.pdftoclevel0 { font-weight: bold; } h2 { /*16px via YUI Fonts CSS foundation*/ font-size:123.1%; -pdf-outline-level: 1; } h3 { /*14px via YUI Fonts CSS foundation*/ font-size:108%; -pdf-outline-level: 2; } h4 { -pdf-outline-level: 3; } h5 { -pdf-outline-level: 4; } h6 { -pdf-outline-level: 5; } /* xhtml2 specific, margin for outline items */ pdftoc.pdftoclevel1 { margin-left: 1.0em; font-weight: normal; } pdftoc.pdftoclevel2 { margin-left: 2.0em; } pdftoc.pdftoclevel3 { margin-left: 3.0em; } pdftoc.pdftoclevel4 { margin-left: 4.0em; } pdftoc.pdftoclevel5 { margin-left: 5.0em; } h1, h2, h3, h4, h5, h6, p, pre, hr { margin:1em 0; } address, blockquote, body, center, dl, dir, div, fieldset, form, h1, h2, h3, h4, h5, h6, hr, isindex, menu, noframes, noscript, ol, ul, p, pre, table, th, tr, td, dd, dt, pdftoc { display: block; } table { -pdf-keep-in-frame-mode: shrink; } tr, th, td { vertical-align: middle; width: auto; padding: 2px; } th { text-align: center; font-weight: bold; } center { text-align: center; } big { font-size: 125%; } small { font-size: 75%; } li { /* Ugly fix for PISA? It won't line break instead... but this breaks display in Printable HTML */ display: block; } ul { margin-left: 1.5em; list-style-type: disc; } ul ul { margin-left: 1.5em; /* Looks like stly is ignored in PISA */ list-style-type: circle; } ul ul ul { margin-left: 1.5em; /* Looks like stly is ignored in PISA */ list-style-type: square; } ol { list-style-type: decimal; margin-left: 1.5em; } ol.loweralpha { margin-left: 1.5em; /* Looks like stly is ignored in PISA */ list-style-type: lower-latin; } ol.lowerroman, ol { margin-left: 1.5em; /* Looks like stly is ignored in PISA */ list-style-type: lower-roman; } dd { margin-left: 2.0em; } pre { white-space: pre; } blockquote { margin-left: 1.5em; margin-right: 1.5em; } blockquote.citation { margin-left: 1.5em; margin-right: 1.5em; border-left-style: solid; border-left-color: #a0a0a0; border-left-width: 2px; padding-left: 1em; } /* Add a border on code bocks */ div.code pre, pre.wiki { border: 1px solid black; padding: 5px; } /* Hide border for images */ img { border: 0px; } /* Add a border on wiki tables */ table.wiki { border: 1px solid gray; } """ # This CSS is included when creating Books. Default @page style is not # specified, so front page has no header or footer. After front_page, # 'standard' template must be selected using: #
BOOK_EXTRA_CSS = """ /* Set options when using 'standard' template */ @page standard { margin: 1.5cm; margin-top: 2.5cm; margin-bottom: 2.5cm; @frame header { /* -pdf-frame-border: 1; */ -pdf-frame-content: headerContent; margin-left: 1.5cm; margin-right: 1.5cm; top: 1cm; height: 0.5cm; } @frame footer { /* -pdf-frame-border: 1; */ -pdf-frame-content: footerContent; margin-left: 1.5cm; margin-right: 1.5cm; bottom: 1cm; height: 0.5cm; } } """ #This CSS is included when creating PDF articles, not of book type ARTICLE_EXTRA_CSS = """ /* Set default styles por all pages */ @page { margin: 1.5cm; margin-top: 2.5cm; margin-bottom: 2.5cm; /* Define a header frame. Frame contents will be taken from 'headerContent' element (
) */ @frame header { /* -pdf-frame-border: 1; */ -pdf-frame-content: headerContent; margin-left: 1.5cm; margin-right: 1.5cm; top: 1cm; height: 0.5cm; } /* Define a footer frame. Frame contents will be taken from 'footerContent' element (
) */ @frame footer { /* -pdf-frame-border: 1; */ -pdf-frame-content: footerContent; margin-left: 1.5cm; margin-right: 1.5cm; bottom: 1cm; height: 0.5cm; } } """ # Example front page, just use plain HTML, without or tags FRONTPAGE = """

Wikiprint Book

Title: #TITLE

Subject: #SUBJECT

Version: #VERSION

Date: #DATE

""" EXTRA_CONTENT = """
WikiPrint - from Polar Technologies
"""