tracwikiprintplugin/0000755000175500017550000000000013245346717014735 5ustar debacledebacletracwikiprintplugin/1.0/0000755000175500017550000000000013161312331015211 5ustar debacledebacletracwikiprintplugin/1.0/setup.cfg0000644000175500017550000000003312733030215017030 0ustar debacledebacle[egg_info] tag_build = dev tracwikiprintplugin/1.0/docs/0000755000175500017550000000000011165105024016142 5ustar debacledebacletracwikiprintplugin/1.0/docs/trac.ini.example0000644000175500017550000000050211165105024021223 0ustar debacledebacle[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.htmltracwikiprintplugin/1.0/wikiprint/0000755000175500017550000000000013161312331017231 5ustar debacledebacletracwikiprintplugin/1.0/wikiprint/wikiprint.py0000644000175500017550000004506213161312331021632 0ustar debacledebacle""" Copyright (C) 2008 Prognus Software Livre - www.prognus.com.br Author: Diorgenes Felipe Grzesiuk Modified by: Alvaro Iradier """ import StringIO import os import re import tempfile import time import urllib2 import urlparse from pkg_resources import resource_filename from genshi.builder import Markup from trac.config import Option, BoolOption, ListOption from trac.core import * from trac.mimeview.api import IContentConverter, Context from trac.resource import Resource from trac.web.api import IAuthenticator 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.text import to_unicode try: import xhtml2pdf.pisa as pisa except ImportError: import ho.pisa as pisa import defaults # 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), ] 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 = urlparse.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, urlparse.urljoin(self.req.abs_href(), name)) url = urlparse.urljoin(self.req.abs_href(), name) path = urlparse.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 = urllib2.HTTPPasswordMgrWithDefaultRealm() pwmgr.add_password( None, url, self.env.config.get('wikiprint', 'httpauth_user'), self.env.config.get('wikiprint', 'httpauth_password')) auth_handler = urllib2.HTTPBasicAuthHandler(pwmgr) auth_handler2 = urllib2.HTTPDigestAuthHandler(pwmgr) opener = urllib2.build_opener(auth_handler, auth_handler2) urllib2.install_opener(opener) # Prepare the request with the auth cookie request = urllib2.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 = urllib2.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, 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) #First create a Context object from the wiki page context = Context(Resource('wiki', page_name), req.abs_href, req.perm) context.req = req #Now convert in that context page = format_to_html(self.env, context, text) 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') css_data = self.get_css(req) pdf_file = StringIO.StringIO() 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 = u'\n\n'.join([ formatter.get_style_defs('div.code pre'), formatter.get_style_defs('table.code td') ]).encode('utf-8') style += Markup(content) except ValueError, e: 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 out = StringIO.StringIO() context = Context(Resource('wiki', page_name), req.abs_href, req.perm) context.req = req outline = OutlineFormatter(self.env, context) outline.format(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=str(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' tracwikiprintplugin/1.0/wikiprint/api.py0000644000175500017550000000121512156705421020364 0ustar debacledebacle""" 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.""" tracwikiprintplugin/1.0/wikiprint/formats.py0000644000175500017550000000457312156705421021300 0ustar debacledebacle""" 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 tracwikiprintplugin/1.0/wikiprint/templates/0000755000175500017550000000000011340513665021241 5ustar debacledebacletracwikiprintplugin/1.0/wikiprint/templates/admin_wikibook.html0000644000175500017550000000620211340513665025115 0ustar debacledebacle Make WikiPrint Book

Create WikiPrint Book

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


Output Format
tracwikiprintplugin/1.0/wikiprint/templates/admin_wikiprint.html0000644000175500017550000000554411340513665025327 0ustar debacledebacle 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:
tracwikiprintplugin/1.0/wikiprint/web_ui.py0000644000175500017550000002102712156705421021070 0ustar debacledebacle""" Copyright (C) 2008 Prognus Software Livre - www.prognus.com.br Author: Diorgenes Felipe Grzesiuk Modified by: Alvaro Iradier """ from trac.admin.web_ui import IAdminPanelProvider from trac.core import Component, ExtensionPoint, TracError, implements from trac.perm import IPermissionRequestor from trac.wiki.api import WikiSystem from trac.web.api import RequestDone from trac.web.chrome import ITemplateProvider, add_notice, add_script import defaults import wikiprint from api import IWikiPrintFormat class WikiPrintAdmin(Component): """A plugin allowing the export of multiple wiki pages in a single file.""" formats = ExtensionPoint(IWikiPrintFormat) implements(IPermissionRequestor, IAdminPanelProvider, 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'] = formats.iterkeys().next() add_script(req, 'wikiprint/js/admin_wikiprint.js') 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') return 'admin_wikiprint.html', data def _send_resource_file(self, req, content_type, file, default_value): # Send the output req.send_response(200) req.send_header('Content-Type', 'text/plain') if not file: out = default_value else: linkloader = wikiprint.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 req.send_header('Content-Length', len(out)) req.end_headers() req.write(out) raise RequestDone tracwikiprintplugin/1.0/wikiprint/__init__.py0000644000175500017550000000000011200757777021353 0ustar debacledebacletracwikiprintplugin/1.0/wikiprint/defaults.py0000644000175500017550000001430512156705421021426 0ustar debacledebacle""" Author: Alvaro Iradier """ #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
"""tracwikiprintplugin/1.0/wikiprint/htdocs/0000755000175500017550000000000012156705421020526 5ustar debacledebacletracwikiprintplugin/1.0/wikiprint/htdocs/js/0000755000175500017550000000000012156705421021142 5ustar debacledebacletracwikiprintplugin/1.0/wikiprint/htdocs/js/admin_wikiprint.js0000644000175500017550000000207412156705421024673 0ustar debacledebaclefunction 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 """ from setuptools import setup setup( name='TracWikiPrintPlugin', version='2.0.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=['xhtml2pdf', 'Trac'], ) tracwikiprintplugin/0.11/0000755000175500017550000000000012543134545015306 5ustar debacledebacletracwikiprintplugin/0.11/setup.cfg0000644000175500017550000000005712543134545017131 0ustar debacledebacle[egg_info] tag_build = tag_svn_revision = true tracwikiprintplugin/0.11/docs/0000755000175500017550000000000011165105024016223 5ustar debacledebacletracwikiprintplugin/0.11/docs/trac.ini.example0000644000175500017550000000050211165105024021304 0ustar debacledebacle[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.htmltracwikiprintplugin/0.11/wikiprint/0000755000175500017550000000000012156705441017325 5ustar debacledebacletracwikiprintplugin/0.11/wikiprint/wikiprint.py0000644000175500017550000004464512156705441021734 0ustar debacledebacle""" Copyright (C) 2008 Prognus Software Livre - www.prognus.com.br Author: Diorgenes Felipe Grzesiuk Modified by: Alvaro Iradier """ import StringIO import defaults import os import re import tempfile import time import urllib2 import urlparse from pkg_resources import resource_filename from genshi.builder import Markup from trac.config import Option, BoolOption, ListOption from trac.core import * from trac.mimeview.api import IContentConverter, Context from trac.resource import Resource from trac.web.api import IAuthenticator 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.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 pigments_loaded = False try: # TODO: A better way of importing and checking pigments? # Copied from trac.mimeview.pigments pygments = __import__('pygments', {}, {}, ['lexers', 'styles', 'formatters']) HtmlFormatter = pygments.formatters.html.HtmlFormatter get_style_by_name = pygments.styles.get_style_by_name pigments_loaded = True except: pass EXCLUDE_RES = [ re.compile(r'\[\[TracGuideToc([^]]*)\]\]'), re.compile(r'----(\r)?$\n^Back up: \[\[ParentWiki\]\]', re.M | re.I), ] 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 = urlparse.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, urlparse.urljoin(self.req.abs_href(), name)) url = urlparse.urljoin(self.req.abs_href(), name) path = urlparse.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 = urllib2.HTTPPasswordMgrWithDefaultRealm() pwmgr.add_password( None, url, self.env.config.get('wikiprint', 'httpauth_user'), self.env.config.get('wikiprint', 'httpauth_password')) auth_handler = urllib2.HTTPBasicAuthHandler(pwmgr) auth_handler2 = urllib2.HTTPDigestAuthHandler(pwmgr) opener = urllib2.build_opener(auth_handler, auth_handler2) urllib2.install_opener(opener) # Prepare the request with the auth cookie request = urllib2.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 = urllib2.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, 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') 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): db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute(""" SELECT name FROM auth_cookie WHERE cookie=%s""", (cookie.value,)) row = cursor.fetchone() if not row: return None self.env.log.debug("Cookie for user: %s", row[0]) return row[0] ### 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) #First create a Context object from the wiki page context = Context(Resource('wiki', page_name), req.abs_href, req.perm) context.req = req #Now convert in that context page = format_to_html(self.env, context, text) self.env.log.debug('WikiPrint => Wiki to HTML output: %r' % page) self.env.log.debug('WikiPrint => HTML output for WikiPrint 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') css_data = self.get_css(req) pdf_file = StringIO.StringIO() 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) db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute(""" INSERT INTO auth_cookie (cookie, name, ipnr, time) VALUES (%s, %s, %s, %s) """, (auth_cookie, req.authname, '127.0.0.1', int(time.time()))) db.commit() 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() cursor.execute(""" DELETE FROM auth_cookie WHERE cookie=%s""", (auth_cookie,)) db.commit() 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 pigments_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 = u'\n\n'.join([ formatter.get_style_defs('div.code pre'), formatter.get_style_defs('table.code td') ]).encode('utf-8') style += Markup(content) except ValueError, e: 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: f = open(file_or_url) data = f.read() f.close() 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 out = StringIO.StringIO() context = Context(Resource('wiki', page_name), req.abs_href, req.perm) context.req = req outline = OutlineFormatter(self.env, context) outline.format(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=str(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' tracwikiprintplugin/0.11/wikiprint/api.py0000644000175500017550000000121512156705421020445 0ustar debacledebacle""" 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.""" tracwikiprintplugin/0.11/wikiprint/formats.py0000644000175500017550000000457312156705421021361 0ustar debacledebacle""" 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 tracwikiprintplugin/0.11/wikiprint/templates/0000755000175500017550000000000011340513665021322 5ustar debacledebacletracwikiprintplugin/0.11/wikiprint/templates/admin_wikibook.html0000644000175500017550000000620211340513665025176 0ustar debacledebacle Make WikiPrint Book

Create WikiPrint Book

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


Output Format
tracwikiprintplugin/0.11/wikiprint/templates/admin_wikiprint.html0000644000175500017550000000554411340513665025410 0ustar debacledebacle 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:
tracwikiprintplugin/0.11/wikiprint/web_ui.py0000644000175500017550000002102712156705421021151 0ustar debacledebacle""" Copyright (C) 2008 Prognus Software Livre - www.prognus.com.br Author: Diorgenes Felipe Grzesiuk Modified by: Alvaro Iradier """ from trac.admin.web_ui import IAdminPanelProvider from trac.core import Component, ExtensionPoint, TracError, implements from trac.perm import IPermissionRequestor from trac.wiki.api import WikiSystem from trac.web.api import RequestDone from trac.web.chrome import ITemplateProvider, add_notice, add_script import defaults import wikiprint from api import IWikiPrintFormat class WikiPrintAdmin(Component): """A plugin allowing the export of multiple wiki pages in a single file.""" formats = ExtensionPoint(IWikiPrintFormat) implements(IPermissionRequestor, IAdminPanelProvider, 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'] = formats.iterkeys().next() add_script(req, 'wikiprint/js/admin_wikiprint.js') 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') return 'admin_wikiprint.html', data def _send_resource_file(self, req, content_type, file, default_value): # Send the output req.send_response(200) req.send_header('Content-Type', 'text/plain') if not file: out = default_value else: linkloader = wikiprint.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 req.send_header('Content-Length', len(out)) req.end_headers() req.write(out) raise RequestDone tracwikiprintplugin/0.11/wikiprint/__init__.py0000644000175500017550000000000011200757777021434 0ustar debacledebacletracwikiprintplugin/0.11/wikiprint/defaults.py0000644000175500017550000001430512156705421021507 0ustar debacledebacle""" Author: Alvaro Iradier """ #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
"""tracwikiprintplugin/0.11/wikiprint/htdocs/0000755000175500017550000000000012156705421020607 5ustar debacledebacletracwikiprintplugin/0.11/wikiprint/htdocs/js/0000755000175500017550000000000012156705421021223 5ustar debacledebacletracwikiprintplugin/0.11/wikiprint/htdocs/js/admin_wikiprint.js0000644000175500017550000000207412156705421024754 0ustar debacledebaclefunction 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 """ from setuptools import setup setup( name='TracWikiPrintPlugin', version='1.9.4', 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=['xhtml2pdf', 'Trac'], )