def render_macro(self, req, name, content): from trac.wiki.formatter import Formatter formatter = Formatter(self.env, req) def getparm(category, target): return req.perm.perms formatter.perm = getparm return self.expand_macro(formatter, name, content)
def format(self, active_page, page, text, out, min_depth, max_depth): self.__page = page # XXX Code copied straight out of OutlineFormatter self.outline = [] class NullOut(object): def write(self, data): pass Formatter.format(self, text, NullOut()) if min_depth > max_depth: min_depth, max_depth = max_depth, min_depth max_depth = min(6, max_depth) min_depth = max(1, min_depth) curr_depth = min_depth - 1 for depth, link in self.outline: active = '' if '/%s' % active_page in link: active = ' class="active"' if depth < min_depth or depth > max_depth: continue if depth < curr_depth: out.write('</li></ol><li%s>' % active * (curr_depth - depth)) elif depth > curr_depth: out.write('<ol><li%s>' % active * (depth - curr_depth)) else: out.write("</li><li%s>\n" % active) curr_depth = depth out.write(link) out.write('</li></ol>' * curr_depth)
def format(self, active_page, page, text, out, min_depth, max_depth): # XXX Code copied straight out of OutlineFormatter self.outline = [] Formatter.format(self, text) active = '' if page == active_page: active = ' class="active"' if min_depth > max_depth: min_depth, max_depth = max_depth, min_depth max_depth = min(6, max_depth) min_depth = max(1, min_depth) curr_depth = min_depth - 1 for depth, anchor, heading in self.outline: if depth < min_depth or depth > max_depth: continue if depth < curr_depth: out.write('</li></ol><li%s>' % active * (curr_depth - depth)) elif depth > curr_depth: out.write('<ol><li%s>' % active * (depth - curr_depth)) else: out.write("</li><li%s>\n" % active) curr_depth = depth out.write('<a href="%s#%s">%s</a>' % (self.href.wiki(page), anchor, heading)) out.write('</li></ol>' * curr_depth)
def __init__(self, env, context, wikidom, accepted_code_processors): self.env = env self.context = context self.accepted_code_processors = accepted_code_processors if isinstance(wikidom, basestring): wikidom = WikiParser(env).parse(wikidom) self.wikidom = wikidom Formatter.__init__(self, env, context)
def _heading_formatter(self, match, fullmatch): Formatter._heading_formatter(self, match, fullmatch) depth = min(len(fullmatch.group('hdepth')), 5) heading = match[depth + 1:len(match) - depth - 1] anchor = self._anchors[-1] text = wiki_to_oneliner(heading, self.env, self.db, self._absurls) text = re.sub(r'</?a(?: .*?)?>', '', text) # Strip out link tags self.outline.append((depth, '<a href="%s#%s">%s</a>' % (self.env.href.wiki(self.__page), anchor, text)))
def expand_macro(self, formatter, name, content): db = self.env.get_db_cnx() txt = content or '' args = txt.split('|') url = args.pop(0).replace("'", "''") if ":" in url: base, name = url.split(":") if base != "wiki": return "Use 'wiki:' prefix in wiki page url", base, name else: name = url sql = "SELECT text from wiki where name = '%s' order by version desc limit 1" % name cs = db.cursor() cs.execute(sql) result = cs.fetchone() if not result: return '<b>Wiki Page %s not found!</b>' % url text = result[0] out = StringIO() codepage = self.env.config.get('trac', 'charset', 'ISO8859-15') Formatter(self.env, formatter.context).format(text, out, False) text = out.getvalue().encode(codepage) return text
def expand_macro(self, formatter, name, content): args, kwargs = parse_args(content) pattern = args[0] if len(args) > 1 and args[1].strip().upper() == "COMPLETED": completed = "AND completed>0" else: completed = "AND completed=0" if len(args) > 2 and args[2].strip().upper() == "ASC": ordering = "ASC" else: ordering = "DESC" db = self.env.get_db_cnx() cursor = db.cursor() print """ SELECT name FROM milestone WHERE name %s %s ORDER BY name %s """ % (db.like(), completed, ordering) cursor.execute( """ SELECT name FROM milestone WHERE name %s %s ORDER BY name %s """ % (db.like(), completed, ordering), (pattern, )) out = StringIO() for name, in cursor.fetchall(): wikitext = """ == [milestone:%(milestonename)s %(milestonename)s] == [[TicketQuery(milestone=%(milestonename)s,order=id,desc=0,format=table,col=summary|owner|ticket_status|type|status)]] """ % { 'milestonename': name } Formatter(self.env, formatter.context).format(wikitext, out) return Markup(out.getvalue())
def test_expand_macro(self): """ Testing the expand_macro method. """ processor = CodeExample(self.env) args = 'test' formatter = Formatter(self.env, self.context) name = 'CodeExample' expected = '<div ' \ 'class="example">\n <div class="title">\n\t' \ '<span class="select_code" id="link1">' \ 'SELECT ALL</span>\n\t\n\t<span>EXAMPLE:</span>\n</div>\n \n ' \ '<div class="code">' \ '\n <pre id="codelink1">test\n</pre>\n </div>\n</div>' self.assertEqual(expected, processor.expand_macro(formatter, name, args)) args = '##type=bad\ntest' expected = '<div ' \ 'class="bad_example">\n <div class="title">\n\t' \ '<span class="select_code" id="link2">' \ 'SELECT ALL</span>\n\t\n\t<span>INCORRECT EXAMPLE:</span>\n' \ '</div>\n \n <div class="code">' \ '\n <pre id="codelink2">test\n</pre>\n </div>\n</div>' self.assertEqual(expected, processor.expand_macro(formatter, name, args)) args = '##type=good\ntest' expected = '<div ' \ 'class="good_example">\n <div class="title">\n\t' \ '<span class="select_code" id="link3">' \ 'SELECT ALL</span>\n\t\n\t<span>CORRECT EXAMPLE:</span>\n</div>' \ '\n \n <div class="code">' \ '\n <pre id="codelink3">test\n</pre>\n </div>\n</div>' self.assertEqual(expected, processor.expand_macro(formatter, name, args))
def expand_macro(self, formatter, name, content): env = formatter.env abs = env.abs_href.base abs = abs[:len(abs) - len(env.href.base)] f = Formatter(formatter.env, formatter.context) def convert(m): pre, target, suf = filter(None, m.groups()) out = StringIO() f.format(target, out) url = re.search(HREF, out.getvalue()).groups()[0] # Trac creates relative links, which Markdown won't touch inside # <autolinks> because they look like HTML if pre == '<' and url != target: pre += abs return pre + str(url) + suf try: from markdown import markdown return markdown(re.sub(LINK, convert, content)) except ImportError: msg = 'Error importing Python Markdown, install it from ' url = 'http://www.freewisdom.org/projects/python-markdown/' return system_message(tag(msg, tag.a('here', href="%s" % url), '.'))
def _macro_formatter(self, match, fullmatch): name = fullmatch.group('macroname') if name in self.allowed_macros: # leapfrog the OneLinerFormatter return Formatter._macro_formatter(self, match, fullmatch) else: # use the OneLinerFormatter return OneLinerFormatter._macro_formatter(self, match, fullmatch)
def process_request(self, req): req.perm.assert_permission('TICKET_VIEW') if 'id' in req.args.keys(): try: ticket = int(req.args.get('id')) except ValueError: raise TracError('Need integer ticket id.') sql = ("SELECT 1 FROM ticket WHERE id=%s" % ticket) db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute(sql) row = cursor.fetchone() if not row: raise TracError( 'Cannot build dependency graph for non-existent ticket %d.' % ticket) depth = -1 for key in req.args.keys(): if key == 'depth': depth = req.args[key] options = '%s,%s' % (ticket, depth) add_ctxtnav(req, 'Back to Ticket #%s' % ticket, req.href.ticket(ticket)) title = 'Ticket #%s Dependency Graph' % ticket headline = 'Dependency Graph for Ticket #%s' % ticket else: constraints = {} for key in req.args.keys(): if isinstance(req.args[key], (list, tuple)): constraints[key] = '|'.join(req.args[key]) else: constraints[key] = req.args[key] options = 'query:' + '&'.join(key + '=' + constraints[key] for key in constraints) title = 'Ticket query Dependency Graph' headline = 'Dependency Graph for Query' add_ctxtnav(req, 'Back to query', req.href('query', **req.args)) data = {} context = Context.from_request(req, '') formatter = Formatter(self.env, context) graph = DepGraphMacro(self.env).expand_macro(formatter, 'DepGraph', options) data['title'] = title data['headline'] = headline data['depgraph'] = Markup(graph) return 'depgraph.html', data, None
def test_wiki_link_foreign(self): attachment = Attachment(self.env, 'ticket', 123) attachment.insert('foo.txt', tempfile.TemporaryFile(), 0) ns, func = AttachmentModule(self.env).get_link_resolvers().next() self.assertEqual('attachment', ns) req = Mock(path_info='/wiki') formatter = Formatter(self.env, req) self.assertEqual('<a class="attachment" title="Attachment #123: ' 'foo.txt" href="/trac.cgi/attachment/ticket/123/' 'foo.txt">Foo</a>', func(formatter, ns, 'ticket:123:foo.txt', 'Foo'))
def test_wiki_link_subpage(self): attachment = Attachment(self.env, 'wiki', 'SomePage/SubPage') attachment.insert('foo.txt', tempfile.TemporaryFile(), 0) ns, func = AttachmentModule(self.env).get_link_resolvers().next() self.assertEqual('attachment', ns) req = Mock(path_info='/wiki/SomePage/SubPage') formatter = Formatter(self.env, req) self.assertEqual( '<a class="attachment" ' 'title="Attachment SomePage/SubPage: foo.txt" ' 'href="/trac.cgi/attachment/wiki/SomePage/SubPage/' 'foo.txt">Foo</a>', func(formatter, ns, 'foo.txt', 'Foo'))
def test_expand_macro_with_unicode(self): """ Testing the expand_macro method with unicode symbols. """ processor = CodeExample(self.env) args = 'ТЕСТ' formatter = Formatter(self.env, self.context) name = 'CodeExample' expected = '<div ' \ 'class="example">\n <div class="title">\n\t' \ '<span class="select_code" id="link1">' \ 'SELECT ALL</span>\n\t\n\t<span>EXAMPLE:</span>\n</div>\n \n ' \ '<div class="code">' \ '\n <pre id="codelink1">ТЕСТ\n</pre>\n </div>\n</div>' self.assertEqual(expected, processor.expand_macro(formatter, name, args))
def expand_macro(self, formatter, name, content): env = formatter.env abs = env.abs_href.base abs = abs[:len(abs) - len(env.href.base)] f = Formatter(formatter.env, formatter.context) def convert_links(m): pre, target, suf = filter(None, m.groups()) out = StringIO() f.format(target, out) url = re.search(HREF, out.getvalue()).groups()[0] # Trac creates relative links, which Markdown won't touch inside # <autolinks> because they look like HTML if pre == '<' and url != target: pre += abs return pre + str(url) + suf def emojify(html): pattern = ":([a-z0-9\\+\\-_]+):" link = "<img\ alt=\"\\1\"\ title=\":\\1:\"\ height=\"20\"\ style=\"vertical-align:middle\"\ width=\"20\"\ src=\"/chrome/markdown/emoji/\\1.png\" />" emojify_html = re.sub(pattern, link, html) return emojify_html try: # Import & convert import markdown2 # autolink http:// n stuff autolinked_content = re.sub(LINK, convert_links, content) # convert to markdown html = markdown2.markdown(autolinked_content, extras=MD_EXTRAS) # substitute emojis emojified_html = emojify(html) return emojified_html except ImportError: # no markdown2 package found? msg = 'Error importing python-markdown2, install it from ' url = 'https://github.com/trentm/python-markdown2' return system_message(tag(msg, tag.a('here', href="%s" % url), '.'))
def process_request(self, req): """Process the request. For ClearSilver, return a (template_name, content_type) tuple, where `template` is the ClearSilver template to use (either a `neo_cs.CS` object, or the file name of the template), and `content_type` is the MIME type of the content. For Genshi, return a (template_name, data, content_type) tuple, where `data` is a dictionary of substitutions for the template. For both templating systems, "text/html" is assumed if `content_type` is `None`. Note that if template processing should not occur, this method can simply send the response itself and not return anything. """ formatter = Formatter(self.env, Context.from_request(req)) intertrac = InterTracDispatcher(self.env) macro = intertrac.expand_macro(formatter, 'InterTrac', '') data = {'macro': macro} return ("intertracinfo.html", data, 'text/html')
def test(self): """Testing WikiFormatter""" # Environment stub from trac.core import ComponentManager from trac.config import Configuration from trac.log import logger_factory from trac.test import InMemoryDatabase from trac.web.href import Href db = InMemoryDatabase() class DummyEnvironment(ComponentManager): def __init__(self): ComponentManager.__init__(self) self.log = logger_factory('null') self.config = Configuration(None) self.href = Href('/') self.abs_href = Href('http://www.example.com/') self._wiki_pages = {} self.path = '' def component_activated(self, component): component.env = self component.config = self.config component.log = self.log def get_db_cnx(self): return db # Load all the components that provide IWikiSyntaxProvider # implementations that are tested. Ideally those should be tested # in separate unit tests. import trac.versioncontrol.web_ui.browser import trac.versioncontrol.web_ui.changeset import trac.Milestone import trac.ticket.query import trac.ticket.report import trac.Search env = DummyEnvironment() out = StringIO.StringIO() Formatter(env).format(self.input, out) v = out.getvalue().replace('\r','') self.assertEquals(self.correct, v)
def test_path_recognition(self): """ Testing correct path requirements. """ processor = CodeExample(self.env) args = '##path=test\nТЕСТ' formatter = Formatter(self.env, self.context) name = 'CodeExample' expected = '<div ' \ 'class="example">\n <div class="title">\n\t' \ '<span class="select_code" id="link1">' \ 'SELECT ALL</span>\n\t\n\t<span>EXAMPLE:</span>\n</div>\n \n ' \ '<div class="system-message">\n <strong>' \ 'During the example analyzing the following problems' \ ' appear:</strong>\n <ul>\n ' \ '<li>Path element is not found.</li>\n '\ '</ul>\n </div>' \ '\n \n <div class="code">' \ '\n <pre id="codelink1">ТЕСТ\n</pre>\n </div>\n</div>' self.assertEqual(expected, processor.expand_macro(formatter, name, args))
def test_macro_with_invalid_lang(self): """ Testing the expand_macro method with invalid language. """ processor = CodeExample(self.env) args = '#!python1\ntest' formatter = Formatter(self.env, self.context) name = 'CodeExample' expected = '<div ' \ 'class="example">\n <div class="title">\n\t' \ '<span class="select_code" id="link1">' \ 'SELECT ALL</span>\n\t\n\t<span>EXAMPLE:</span>\n</div>\n \n ' \ '<div class="system-message">\n <strong>' \ 'During the example analyzing the following problems appear:' \ '</strong>\n ' \ '<ul>\n <li>no lexer for alias \'python1\' found</li>' \ '\n </ul>\n </div>\n \n ' \ '<div class="code">' \ '\n <pre id="codelink1">test\n</pre>\n </div>\n</div>' self.assertEqual(expected, processor.expand_macro(formatter, name, args))
def expand_macro(self, formatter, name, content): (args, kwargs) = parse_args(content, False) page_name = self.MACRO_PAGES + name page = WikiPage(self.env, page_name) if not page.exists: raise RuntimeError(u'Can\'t find page', page_name) for i, arg in enumerate(args): kwargs[unicode(i+1)] = arg text = RelaxedIdTemplate(page.text).safe_substitute(kwargs) out = StringIO() Formatter(self.env, formatter.context).format(text, out) out = out.getvalue().strip() if out.startswith(u'<p>'): out = out[3:] if out.endswith(u'</p>'): out = out[:-4] return out
def pre_process_request(self, req, handler): if req.path_info.startswith('/wiki'): if req.method == 'POST' and req.args.get('action', 'view') == 'view': post_handler = None for poster in self.macro_posters: if not hasattr(poster, 'match_macro_post'): continue rv = poster.match_macro_post(req) if isinstance(rv, (str, unicode)): rv = rv in req.args.keys() if rv: post_handler = poster break if post_handler: post_handler.process_macro_post(req) else: # Silly stuff here self.log.debug( 'MacroPostModule: Unclaimed POST, scanning page %s', req.path_info[6:]) page = WikiPage(self.env, req.path_info[6:]) matches = self.macro_re.findall( page.text) + self.proc_re.findall(page.text) for name in matches: self.log.debug('MacroPostModule: Found macro "%s"', name) resource = Resource('wiki', name) context = Context.from_request(req, resource) wp = WikiProcessor(Formatter(self.env, context), name) if wp.macro_provider is None: self.log.debug( 'MacroPostModule: Invalid name!!! How did that happen' ) continue if hasattr(wp.macro_provider, 'process_macro_post') and \ not hasattr(wp.macro_provider, 'match_macro_post'): wp.macro_provider.process_macro_post(req) req.environ['REQUEST_METHOD'] = 'GET' # Revert back to a GET return handler
def process_request(self, req): req.perm.require('TAGS_VIEW') add_ctxtnav(req, 'Cloud', req.href.tags()) match = re.match(r'/tags/?(.*)', req.path_info) if match.group(1): req.redirect(req.href('tags', q=match.group(1))) add_stylesheet(req, 'tags/css/tractags.css') query = req.args.get('q', '') data = {'title': 'Tags'} formatter = Formatter(self.env, Context.from_request(req, Resource('tag'))) realms = [p.get_taggable_realm() for p in self.tag_providers] checked_realms = [r for r in realms if r in req.args] or realms data['tag_realms'] = [{ 'name': realm, 'checked': realm in checked_realms } for realm in realms] if query: data['tag_title'] = 'Showing objects matching "%s"' % query data['tag_query'] = query from tractags.macros import TagCloudMacro, ListTaggedMacro if not query: macro = TagCloudMacro(self.env) else: macro = ListTaggedMacro(self.env) query = '(%s) (%s)' % (' or '.join( ['realm:' + r for r in realms if r in checked_realms]), query) self.env.log.debug('Tag query: %s', query) try: data['tag_body'] = macro.expand_macro(formatter, None, query) except InvalidQuery, e: data['tag_query_error'] = to_unicode(e) data['tag_body'] = TagCloudMacro(self.env) \ .expand_macro(formatter, None, '')
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. `req` is the current request object, `method` is the Genshi render method (xml, xhtml or text), `filename` is the filename of the template to be rendered, `stream` is the event stream and `data` is the data for the current template. See the Genshi documentation for more information. """ if filename in ('ticket.html', 'agilo_ticket_new.html',): add_stylesheet(req, 'tags/css/tractags.css') add_stylesheet(req, 'loomingclouds/css/tagcloud.css') add_script(req, 'loomingclouds/js/tag_filler.js') formatter = Formatter(self.env, Context.from_request(req)) macro = TagCloudMacro(self.env) cloud = macro.expand_macro(formatter, 'TagCloud', '') stream |= Transformer("//input[@id='field-keywords']").after(cloud).after(tag.a('More...',href='#',class_='tag-cloud-filler')) return stream
def process_request(self, req): req.perm.require('TAGS_VIEW') match = re.match(r'/tags/?(.*)', req.path_info) tag_id = match.group(1) and match.group(1) or None query = req.args.get('q', '') # Consider only providers, that are permitted for display. tag_system = TagSystem(self.env) all_realms = tag_system.get_taggable_realms(req.perm) if not (tag_id or query) or [r for r in all_realms if r in req.args ] == []: for realm in all_realms: if not realm in self.exclude_realms: req.args[realm] = 'on' checked_realms = [r for r in all_realms if r in req.args] if query: # Add permitted realms from query expression. checked_realms.extend(query_realms(query, all_realms)) realm_args = dict( zip([r for r in checked_realms], ['on' for r in checked_realms])) # Switch between single tag and tag query expression mode. if tag_id and not re.match(r"""(['"]?)(\S+)\1$""", tag_id, re.UNICODE): # Convert complex, invalid tag ID's --> query expression. req.redirect(req.href.tags(realm_args, q=tag_id)) elif query: single_page = re.match(r"""(['"]?)(\S+)\1$""", query, re.UNICODE) if single_page: # Convert simple query --> single tag. req.redirect(req.href.tags(single_page.group(2), realm_args)) data = dict(page_title=_("Tags"), checked_realms=checked_realms) # Populate the TagsQuery form field. data['tag_query'] = tag_id and tag_id or query data['tag_realms'] = list( dict(name=realm, checked=realm in checked_realms) for realm in all_realms) if tag_id: data['tag_page'] = WikiPage(self.env, tag_system.wiki_page_prefix + tag_id) if query or tag_id: macro = 'ListTagged' # TRANSLATOR: The meta-nav link label. add_ctxtnav(req, _("Back to Cloud"), req.href.tags()) args = "%s,format=%s,cols=%s" % \ (tag_id and tag_id or query, self.default_format, self.default_cols) data['mincount'] = None else: macro = 'TagCloud' mincount = as_int(req.args.get('mincount', None), self.cloud_mincount) args = mincount and "mincount=%s" % mincount or None data['mincount'] = mincount formatter = Formatter(self.env, Context.from_request(req, Resource('tag'))) self.env.log.debug("%s macro arguments: %s" % (macro, args and args or '(none)')) macros = TagWikiMacros(self.env) try: # Query string without realm throws 'NotImplementedError'. data['tag_body'] = checked_realms and \ macros.expand_macro(formatter, macro, args, realms=checked_realms) \ or '' except InvalidQuery, e: data['tag_query_error'] = to_unicode(e) data['tag_body'] = macros.expand_macro(formatter, 'TagCloud', '')
def wiki(self, text): out = StringIO.StringIO() Formatter(self.formatter.env, self.formatter.context).format(text, out) return out.getvalue()
def formatter(self, env): return Formatter(env)
def __init__(self, env, context, name): Formatter.__init__(self, env, context) self.__name = name self.__marks = [] self.__super = super(DefaultWikiChecker, self)
def code_formatter(env, context, language, text): processor = WikiProcessor(Formatter(env, context), language) html = processor.process(text) raw = nodes.raw('', html, format='html') return raw
def __init__(self, env, context, name): Formatter.__init__(self, env, context) self.__name = name self.__marks = [] self.__super = super()
def __init__(self, env, req=None, absurls=False, db=None, styles=None): Formatter.__init__(self, env, req=None, absurls=False, db=None) self.styles = styles self._in_list_item = False
def convert_content(self, req, input_type, source, output_type): # get parameters from trac ini file self.img_max_x = self.env.config.get('pagetodoc', 'img_max_x', self.img_max_x) self.img_max_y = self.env.config.get('pagetodoc', 'img_max_y', self.img_max_y) self.img_max_y = self.env.config.get('pagetodoc', 'dpi', self.dpi) # XSL-Transformation xsltfilepath = self.env.config.get('pagetodoc', 'xsltfile', '') # TBD: Fehler ausgeben, wenn xsltfile nicht gelesen werden kann # TBD: Parameter aus der trac.ini an zentraler Stelle auslesen if xsltfilepath == '': message = "You have to set the 'xsltfile' option in the " \ "[pagetodoc] section in trac.ini" raise_dependency_issue(message, req, self.env) if not os.path.exists(xsltfilepath): message = ("Value for 'xsltfile' in the [pagetodoc] section in " \ "trac.ini does not exist: '%s'.")% xsltfilepath raise_dependency_issue(message, req, self.env) # maybe for later use #codepage = self.env.config.get('trac', 'charset', 'iso-8859-1') codepage = 'iso-8859-1' # Convert Wiki markup to HTML, new style out = StringIO() context = Context.from_request(req, 'wiki', req.path_info[6:]) Formatter(self.env, context).format(source, out) html = Markup(out.getvalue()).encode(codepage, 'replace') # remove the bad HTML produced by the breadcrumbs plugin # RFE: find a universal way to do this html = re.compile('(<lh[^>]*>)').sub('', html) # temporary files and folders self.tempdir = mkdtemp(prefix="page2doc") htmlfilehandle, htmlfilepath = mkstemp(prefix='trac_', dir=self.tempdir, suffix = ".html") wordfilehandle, wordfilepath = mkstemp(prefix='word_', dir=self.tempdir, suffix = ".doc") os.close(wordfilehandle) # for debug: set all rights #self.chmod_tmp_dir(self.tempdir) # images # replace href with absolute path and if existing, base auth login try: # this will work if the authentication type is basic (and not over SSL?) login = base64.b64decode(req.environ['HTTP_AUTHORIZATION'][6:]) + '@' except (KeyError, TypeError): login = '' html = re.sub('<img src="(?!\w+://)', '<img src="%s://%s%s:%d' % (req.scheme, login, req.server_name, req.server_port), html) # save images to disk html = re.sub('<img src="([^"]*)"', self.download_image, html) # write HTML page to disk os.write(htmlfilehandle, '<html><body>' + html + '</body></html>') os.close(htmlfilehandle) # clean up the HTML page using HTML Tidy args = '-m -asxhtml -latin1 --doctype omit' tidypath = self.env.config.get('pagetodoc', 'tidypath', 'tidy') # verify that Tidy exists and is setup correctly tidy_error = dependency_failure("tidy", tidypath, "-v") if tidy_error: raise_dependency_issue(tidy_error, req, self.env) cmd = '"%s" %s %s' % (tidypath, args, htmlfilepath) self.execute_external_program(cmd) # workaround namespace self.perform_workarounds(htmlfilepath, 'html') if self.verbose: verb = '-v' else: verb = '' xsltprocpath = self.env.config.get('pagetodoc', 'xsltprocpath', 'xsltproc') # verify that Tidy exists and is setup correctly xsltproc_error = dependency_failure("xsltproc", xsltprocpath, "-V") if xsltproc_error: raise_dependency_issue(xsltproc_error, req, self.env) cmd = '%s %s --html -o %s %s %s' % ( xsltprocpath, verb, wordfilepath, xsltfilepath, htmlfilepath) self.execute_external_program(cmd) # workaround pre-tags self.perform_workarounds(wordfilepath, 'pre') zipfilepath = os.path.join( self.tempdir, os.path.basename(str(req.path_info) + '.zip')) # create a zip file and store all files into it zipfilehandle = zipfile.ZipFile(zipfilepath, "w") zipfilehandle.write(wordfilepath, os.path.basename(str(req.path_info) + '.htm')) for image in self.images: zipfilehandle.write(image, self.imagesubdir + os.path.basename(image)) zipfilehandle.close() zip_file = open(zipfilepath, "rb") zip = zip_file.read() zip_file.close() # delete temporary folders and files self.remove_dir(os.path.join(self.tempdir, self.logsubdir)) self.remove_dir(os.path.join(self.tempdir, self.imagesubdir)) self.remove_dir(self.tempdir) # reset image list self.images = [] return (zip, 'application/zip')
class CKEditorFormatter(Formatter): """Extends base wiki formatter by setting code processor's name for code blocks. Thus CKEditor can save it, so it could be processed later by format processor like Pygments (see TracSyntaxColoring). """ data_code_style = None def __init__(self, env, context, wikidom, accepted_code_processors): self.env = env self.context = context self.accepted_code_processors = accepted_code_processors if isinstance(wikidom, basestring): wikidom = WikiParser(env).parse(wikidom) self.wikidom = wikidom Formatter.__init__(self, env, context) # copied from HtmlFormatter def generate(self, escape_newlines=False): """Generate HTML elements. newlines in the wikidom will be preserved if `escape_newlines` is set. """ # FIXME: compatibility code only for now out = StringIO() self.format(self.wikidom, out, escape_newlines) # self.env.log.debug('generated html: %s' % out.getvalue()) return Markup(out.getvalue()) def handle_code_block(self, line, startmatch=None): """Overrides Formatter.handle_code_block, so it adds an additional `pre`-tag with attribute `data-code-style`, in which the code-format is saved. Furthermore the code block is converted into HTML, because otherwise CKEditor ignores empty lines. In this method linebreaks `\n` are replaced by `<br/>`. """ handle_code_style = False if line.strip() == WikiParser.ENDBLOCK and self.code_processor: clean_processor_name = self.code_processor.name self.env.log.debug('clean_processor_name: %s' % clean_processor_name) idx = clean_processor_name.find('; ') if idx >= 0: clean_processor_name = clean_processor_name[:idx] if clean_processor_name == 'default': handle_code_style = True self.data_code_style = '' elif clean_processor_name not in ['diff', 'td']: try: from pygments.lexers import get_lexer_for_mimetype lexer = get_lexer_for_mimetype(clean_processor_name) proc_aliases = lexer.aliases if proc_aliases and len(proc_aliases) > 0: clean_processor_name = proc_aliases[0] else: clean_processor_name = lexer.name if clean_processor_name in self.accepted_code_processors: self.data_code_style = ' data-code-style="%s"' % clean_processor_name handle_code_style = True except Exception, e: self.env.log.warn( "Error when retrieving lexer by mimetype: %s" % e ) self.data_code_style = '' if handle_code_style: self.env.log.debug('processing self.data_code_style: %s' % self.data_code_style) code_text = os.linesep.join(self.code_buf) html_text = WikiProcessor(self, 'default').process(code_text) html_text = _markup_to_unicode( html_text ) html_text = html_text.replace('\n', '<br/>') html = HTML( html_text ) html |= Transformer('//pre').unwrap() buffer = StringIO() html.render(out=buffer, encoding='utf-8') self.out.write( '<pre%s>' % self.data_code_style ) self.out.write( _markup_to_unicode( buffer.getvalue() ) ) self.out.write('</pre>') self.in_code_block = 0 else: Formatter.handle_code_block(self, line, startmatch)