def _launch(self, encoded_input, *args): """Launch a process (cmd), and returns exitcode, stdout + stderr""" # Note: subprocess.Popen doesn't support unicode options arguments # (http://bugs.python.org/issue1759845) so we have to encode them. # Anyway, dot expects utf-8 or the encoding specified with -Gcharset. encoded_cmd = [] for arg in args: if isinstance(arg, unicode): arg = arg.encode(self.encoding, 'replace') encoded_cmd.append(arg) p = subprocess.Popen(encoded_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if input: p.stdin.write(encoded_input) p.stdin.close() out = p.stdout.read() err = p.stderr.read() reason = None if p.wait() != 0: reason = _("failed with the following output:") if err or out: reason = _("succeeded but emitted the following output:") if reason: return tag.p(tag.br(), _("The command:"), tag.pre(repr(' '.join(encoded_cmd))), reason, out and tag.pre(repr(out)), err and tag.pre(repr(err)))
def launch(self, proc_cmd, encoded_input, *args): """Launch a process (cmd), and returns exitcode, stdout + stderr""" # Note: subprocess.Popen doesn't support unicode options arguments # (http://bugs.python.org/issue1759845) so we have to encode them. # Anyway, dot expects utf-8 or the encoding specified with -Gcharset. encoded_cmd = proc_cmd proc = subprocess.Popen(encoded_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if encoded_input: proc.stdin.write(encoded_input) proc.stdin.close() out = proc.stdout.read() err = proc.stderr.read() failure = proc.wait() != 0 if failure or err or out: return (failure, tag.div(tag.br(), _("The command:"), tag.pre(repr(' '.join(encoded_cmd))), (_("succeeded but emitted the following output:"), _("failed with the following output:"))[failure], out and tag.pre(out), err and tag.pre(err), class_="system-message")) else: return (False, None)
def _launch(self, encoded_input, *args): """Launch a process (cmd), and returns exitcode, stdout + stderr""" # Note: subprocess.Popen doesn't support unicode options arguments # (http://bugs.python.org/issue1759845) so we have to encode them. # Anyway, dot expects utf-8 or the encoding specified with -Gcharset. encoded_cmd = [] for arg in args: if isinstance(arg, unicode): arg = arg.encode(self.encoding, 'replace') encoded_cmd.append(arg) p = subprocess.Popen(encoded_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if encoded_input: p.stdin.write(encoded_input) p.stdin.close() out = p.stdout.read() err = p.stderr.read() failure = p.wait() != 0 if failure or err or out: return (failure, tag.p(tag.br(), _("The command:"), tag.pre(repr(' '.join(encoded_cmd))), (_("succeeded but emitted the following output:"), _("failed with the following output:"))[failure], out and tag.pre(repr(out)), err and tag.pre(repr(err)))) else: return (False, None)
def pygmentize_to_tag(code, language, linenos=False, **kwargs): """ Rebuild a raw pygmentize highlighting as tag elements, avoiding Genshi to delete blank lines. See http://genshi.edgewall.org/wiki/GenshiFaq#WhatisGenshidoingwiththewhitespaceinmymarkuptemplate """ codeblock = pygmentize(code, language, linenos, **kwargs) pre = re.findall("<pre>(.*?)\n*</pre>", codeblock, re.DOTALL) if len(pre) == 1: return tag.pre(Markup(pre[0]), data_language=language) return tag.table( tag.tr(tag.td(tag.pre(pre[0])), tag.td(tag.pre(Markup(pre[1])))), data_language=language # line numbers # code )
def process_request(self, req): if req.path_info == '/mindmap/status': db = self.env.get_db_cnx() cursor = db.cursor() try: cursor.execute('SELECT hash,content FROM mindmapcache') content = tag.html( tag.body( tag.dd([[ tag.dt(tag.a(k, href=req.href.mindmap(k + '.mm'))), tag.dd(tag.pre(v)) ] for k, v in cursor.fetchall()]))) except Exception, e: content = tag.html( tag.body(tag.strong("DB Error: " + unicode(e)))) html = content.generate().render("xhtml") req.send_response(200) req.send_header('Cache-control', 'must-revalidate') req.send_header('Content-Type', 'text/html;charset=utf-8') req.send_header('Content-Length', len(html)) req.end_headers() if req.method != 'HEAD': req.write(html) raise RequestDone
def expand_macro(self, formatter, name, content, args=None): # pylint: disable=too-many-function-args args = args or {} reponame = args.get('repository') or '' rev = args.get('revision') # pylint: disable=no-member repos = RepositoryManager(self.env).get_repository(reponame) try: changeset = repos.get_changeset(rev) message = changeset.message rev = changeset.rev resource = repos.resource except Exception: # pylint: disable=broad-except message = content resource = Resource('repository', reponame) if ChangesetModule(self.env).wiki_format_messages: return tag.div(format_to_html(self.env, formatter.context.child( 'changeset', rev, parent=resource), message, escape_newlines=True), class_='message') else: return tag.pre(message, class_='message')
def expand_macro(self, formatter, name, content, args=None): args = args or {} reponame = args.get('repository') or '' rev = args.get('revision') repos = RepositoryManager(self.env).get_repository(reponame) try: changeset = repos.get_changeset(rev) message = changeset.message rev = changeset.rev resource = repos.resource except Exception: message = content resource = Resource('repository', reponame) if formatter.context.resource.realm == 'ticket': ticket_re = CommitTicketUpdater.ticket_re if not any(int(tkt_id) == int(formatter.context.resource.id) for tkt_id in ticket_re.findall(message)): return tag.p(_("(The changeset message doesn't reference this " "ticket)"), class_='hint') if ChangesetModule(self.env).wiki_format_messages: return tag.div(format_to_html(self.env, formatter.context.child('changeset', rev, parent=resource), message, escape_newlines=True), class_='message') else: return tag.pre(message, class_='message')
def _render_source(self, context, stream, annotations, marks=None): from trac.web.chrome import add_warning annotators, labels, titles = {}, {}, {} for annotator in self.annotators: atype, alabel, atitle = annotator.get_annotation_type() if atype in annotations: labels[atype] = alabel titles[atype] = atitle annotators[atype] = annotator annotations = [a for a in annotations if a in annotators] if isinstance(stream, list): stream = HTMLParser(StringIO(u'\n'.join(stream))) elif isinstance(stream, unicode): text = stream def linesplitter(): for line in text.splitlines(True): yield TEXT, line, (None, -1, -1) stream = linesplitter() annotator_datas = [] for a in annotations: annotator = annotators[a] try: data = (annotator, annotator.get_annotation_data(context)) except TracError, e: self.log.warning("Can't use annotator '%s': %s", a, e.message) add_warning(context.req, tag.strong( tag_("Can't use %(annotator)s annotator: %(error)s", annotator=tag.em(a), error=tag.pre(e.message)))) data = (None, None) annotator_datas.append(data)
def safe_wiki_to_html(context, text): try: return format_to_html(self.env, context, text) except Exception, e: self.log.error('Unable to render component documentation: %s', exception_to_unicode(e, traceback=True)) return tag.pre(text)
def expand_macro(self, formatter, name, content, args={}): reponame = args.get('repository') or '' rev = args.get('revision') repos = RepositoryManager(self.env).get_repository(reponame) try: changeset = repos.get_changeset(rev) message = changeset.message rev = changeset.rev resource = repos.resource except Exception: message = content resource = Resource('repository', reponame) if formatter.context.resource.realm == 'ticket': ticket_re = CommitTicketUpdater.ticket_re if not any( int(tkt_id) == int(formatter.context.resource.id) for tkt_id in ticket_re.findall(message)): return tag.p( "(The changeset message doesn't reference this " "ticket)", class_='hint') if ChangesetModule(self.env).wiki_format_messages: return tag.div(format_to_html(self.env, formatter.context.child( 'changeset', rev, parent=resource), message, escape_newlines=True), class_='message') else: return tag.pre(message, class_='message')
def expand_macro(self, formatter, name, content, args={}): reponame = args.get("repository") or "" rev = args.get("revision") repos = RepositoryManager(self.env).get_repository(reponame) try: changeset = repos.get_changeset(rev) message = changeset.message rev = changeset.rev resource = repos.resource except Exception: message = content resource = Resource("repository", reponame) if formatter.context.resource.realm == "ticket": ticket_re = CommitTicketUpdater.ticket_re if not any(int(tkt_id) == int(formatter.context.resource.id) for tkt_id in ticket_re.findall(message)): return tag.p("(The changeset message doesn't reference this " "ticket)", class_="hint") if ChangesetModule(self.env).wiki_format_messages: return tag.div( format_to_html( self.env, formatter.context.child("changeset", rev, parent=resource), message, escape_newlines=True ), class_="message", ) else: return tag.pre(message, class_="message")
def safe_wiki_to_html(context, text): try: return format_to_html(self.env, context, text) except Exception as e: self.log.error("Unable to render component documentation: %s", exception_to_unicode(e, traceback=True)) return tag.pre(text)
def expand_macro(self, formatter, name, content, args): add_stylesheet(formatter.req, 'text_boxes/css/text_boxes.css') # TODO(holtgrew): Actually, we would like to add a style sheet but this does not work. Thus we use a style tag below. #add_stylesheet(formatter.req, 'text_boxes/css/text_boxes.css') className = CLASSES.get(name, 'ShellBox') if name in ['TextIcon']: args = trac.wiki.parse_args(content) if not args or not args[0]: # Handle case of empty entry. return None DEFAULT = 'gray' COLOR_CLASSES = ['green', 'red', 'yellow', 'black', 'gray', 'blue'] color_class_name = args[1].get('color', DEFAULT) if not color_class_name in COLOR_CLASSES: color_class_name = DEFAULT return tag.span(args[0], class_=('text_icon %s' % color_class_name)) elif name in ['MenuTrace']: args = trac.wiki.parse_args(content) if not args[0]: return None result = tag.span(args[0][0], class_='menu_item') for text in args[0][1:]: result += tag.span(u' \u25B8 ', class_='arrow') result += tag.span(text, class_='menu_item') return tag.span(result, class_='menu_trace') elif name in ['WarningBox', 'InfoBox', 'ImportantBox', 'AssignmentBox']: content_html = self.format_wiki(formatter, content) return tag.div(genshi.core.Markup(content_html), class_=className) else: return tag.pre(content, class_='wiki ' + className)
def expand_macro(self, formatter, name, content, args): add_stylesheet(formatter.req, 'text_boxes/css/text_boxes.css') # TODO(holtgrew): Actually, we would like to add a style sheet but this does not work. Thus we use a style tag below. #add_stylesheet(formatter.req, 'text_boxes/css/text_boxes.css') className = CLASSES.get(name, 'ShellBox') if name in ['TextIcon']: args = trac.wiki.parse_args(content) if not args or not args[0]: # Handle case of empty entry. return None DEFAULT = 'gray' COLOR_CLASSES = ['green', 'red', 'yellow', 'black', 'gray', 'blue'] color_class_name = args[1].get('color', DEFAULT) if not color_class_name in COLOR_CLASSES: color_class_name = DEFAULT return tag.span(args[0], class_=('text_icon %s' % color_class_name)) elif name in ['MenuTrace']: args = trac.wiki.parse_args(content) if not args[0]: return None result = tag.span(args[0][0], class_='menu_item') for text in args[0][1:]: result += tag.span(u' \u25B8 ', class_='arrow') result += tag.span(text, class_='menu_item') return tag.span(result, class_='menu_trace') elif name in [ 'WarningBox', 'InfoBox', 'ImportantBox', 'AssignmentBox' ]: content_html = self.format_wiki(formatter, content) return tag.div(genshi.core.Markup(content_html), class_=className) else: return tag.pre(content, class_='wiki ' + className)
def render(self, context, mimetype, content, filename=None, url=None): self.log.debug("Using Markdown Mimeviewer") req = context.req add_stylesheet(req, 'readme/readme.css') add_script(req, 'readme/marked.js') content = content_to_unicode(self.env, content, mimetype) # for some insane reason genshi will only preserve whitespace of <pre> elements, trac calls Stream.render() inappropriately. return tag.pre(content.encode('utf-8'))
def _render_source(self, context, stream, annotations): from trac.web.chrome import add_warning annotators, labels, titles = {}, {}, {} for annotator in self.annotators: atype, alabel, atitle = annotator.get_annotation_type() if atype in annotations: labels[atype] = alabel titles[atype] = atitle annotators[atype] = annotator annotations = [a for a in annotations if a in annotators] if isinstance(stream, list): stream = HTMLParser(StringIO(u'\n'.join(stream))) elif isinstance(stream, unicode): text = stream def linesplitter(): for line in text.splitlines(True): yield TEXT, line, (None, -1, -1) stream = linesplitter() annotator_datas = [] for a in annotations: annotator = annotators[a] try: data = (annotator, annotator.get_annotation_data(context)) except TracError as e: self.log.warning("Can't use annotator '%s': %s", a, e.message) add_warning( context.req, tag.strong( tag_("Can't use %(annotator)s annotator: %(error)s", annotator=tag.em(a), error=tag.pre(e.message)))) data = (None, None) annotator_datas.append(data) def _head_row(): return tag.tr([ tag.th(labels[a], class_=a, title=titles[a]) for a in annotations ] + [tag.th(u'\xa0', class_='content')]) def _body_rows(): for idx, line in enumerate(_group_lines(stream)): row = tag.tr() for annotator, data in annotator_datas: if annotator: annotator.annotate_row(context, row, idx + 1, line, data) else: row.append(tag.td()) row.append(tag.td(line)) yield row return tag.table(class_='code')(tag.thead(_head_row()), tag.tbody(_body_rows()))
def _error_div(self, msg): """Display msg in an error box, using Trac style.""" if isinstance(msg, str): msg = to_unicode(msg) self.log.error(msg) if isinstance(msg, unicode): msg = tag.pre(escape(msg)) return tag.div( tag.strong(_("Graphviz macro processor has detected an error. " "Please fix the problem before continuing.")), msg, class_="system-message")
def _error_div(self, msg): """Display msg in an error box, using Trac style.""" if isinstance(msg, str): msg = to_unicode(msg) self.log.error(msg) if isinstance(msg, unicode): msg = tag.pre(escape(msg)) return tag.div( tag.strong(_("Canviz macro processor has detected an error. " "Please fix the problem before continuing.")), msg, class_="system-message")
class CommitTicketReferenceMacro(WikiMacroBase): """This is intended to replace the builtin macro by providing additional code review status info for the changeset. To use, disable the builtin macro as follows: [components] tracopt.ticket.commit_updater.committicketreferencemacro = disabled """ def expand_macro(self, formatter, name, content, args={}): reponame = args.get('repository') or '' rev = args.get('revision') repos = RepositoryManager(self.env).get_repository(reponame) try: changeset = repos.get_changeset(rev) message = changeset.message # add review status to commit message ( review = CodeReview(self.env, reponame, rev) status = review.encode(review.status) message += '\n\n{{{#!html \n' message += '<div class="codereviewstatus">' message += ' <div class="system-message %s">' % status.lower() message += ' <p>Code review status: ' message += ' <span>%s</span>' % review.status message += ' </p>' message += ' </div>' message += '</div>' message += '\n}}}' rev = changeset.rev resource = repos.resource except Exception, e: message = content resource = Resource('repository', reponame) if formatter.context.resource.realm == 'ticket': ticket_re = CommitTicketUpdater.ticket_re if not any( int(tkt_id) == int(formatter.context.resource.id) for tkt_id in ticket_re.findall(message)): return tag.p( "(The changeset message doesn't reference this " "ticket)", class_='hint') if ChangesetModule(self.env).wiki_format_messages: return tag.div(format_to_html(self.env, formatter.context('changeset', rev, parent=resource), message, escape_newlines=True), class_='message') else: return tag.pre(message, class_='message')
def include(self, name, parse=True, raw=False, context="block", data=None): if name in self.storage: text = self.storage.page_text(name) if parse: return self.parser.generate(text, context=context, environ=(self, data)) else: if raw: return Markup(text) else: return tag.pre(text) else: return tag.div(tag.p(u"Page %s Not Found" % name), class_="error")
def expand_macro(self, formatter, name, content, args=None): # pylint: disable=too-many-function-args args = args or {} reponame = args.get('repository') or '' rev = args.get('revision') # pylint: disable=no-member repos = RepositoryManager(self.env).get_repository(reponame) try: changeset = repos.get_changeset(rev) message = changeset.message rev = changeset.rev resource = repos.resource except Exception: # pylint: disable=broad-except message = content resource = Resource('repository', reponame) config = self.ticket_replace_section fields = {} for key, value in config.options(): idx = key.rfind('.') if idx >= 0: prefix, attribute = key[:idx], key[idx + 1:] field = fields.setdefault(prefix, {}) field[attribute] = config.get(key) else: fields[key] = {'': value} for prefix, field in fields.iteritems(): if not all(k in field for k in ['pattern', 'replace']): self.log.warn( "Ignoring [%s] %s, missing .pattern or .replace" % (self.ticket_replace_section_name, key)) continue subst = {'repository': reponame, 'revision': rev} pattern = field['pattern'].replace('$(', '%(') % subst replace = field['replace'].replace('$(', '%(') % subst message = re.sub(pattern, replace, message) if ChangesetModule(self.env).wiki_format_messages: message = '\n'.join( map(lambda line: "> " + line, message.split('\n'))) return tag.div(format_to_html(self.env, formatter.context.child( 'changeset', rev, parent=resource), message, escape_newlines=True), class_='message') else: return tag.pre(message, class_='message')
def highlight(text, mime=None, lang=None, linenos=False, title=""): formatter = HTMLFormatter(cssclass="code", linenos=linenos, full=True, title=title) try: if mime: lexer = pygments.lexers.get_lexer_for_mimetype(mime) elif lang: lexer = pygments.lexers.get_lexer_by_name(lang) else: lexer = pygments.lexers.guess_lexer(text) except pygments.util.ClassNotFound: return tag.pre(text) return Markup(pygments.highlight(text, lexer, formatter))
def include(macro, environ, data, *args, **kwargs): """Include the contents of another wiki page. This macro allows you to include the contents of another wiki page, optinoally allowing you to include it parsed (//the default//) or unparsed (//parse=False//). If the specified page does not exist, then "Page Not Found" will be displayed. **Arguments:** * name=None (//the name of the page to include//) * parse=True (//whether to parse the page//) * raw=False (//whether to include this raw//) * source=False (//whether to display the genereated HTML / source//) **Example(s):** {{{ <<include "SandBox">> }}} <<include "SandBox">> {{{ <<include "SandBox", parse=False>> }}} <<include "SandBox", parse=False>> """ name = kwargs.get("name", (args and args[0]) or None) if name is None: return None parse = kwargs.get("parse", True) raw = kwargs.get("raw", False) source = kwargs.get("source", False) contents = environ.include(name, parse, raw, data=data) if source: return tag.pre("".join(serializer(contents))) else: return contents
def highlight(text, mime=None, lang=None, linenos=False, title=""): formatter = HTMLFormatter( cssclass="code", linenos=linenos, full=True, title=title ) try: if mime: lexer = pygments.lexers.get_lexer_for_mimetype(mime) elif lang: lexer = pygments.lexers.get_lexer_by_name(lang) else: lexer = pygments.lexers.guess_lexer(text) except pygments.util.ClassNotFound: return tag.pre(text) return Markup(pygments.highlight(text, lexer, formatter))
def process_request(self, req): if req.path_info == '/mindmap/status': db = self.env.get_db_cnx() cursor = db.cursor() try: cursor.execute('SELECT hash,content FROM mindmapcache') content = tag.html(tag.body(tag.dd( [ [tag.dt(tag.a(k,href=req.href.mindmap(k + '.mm'))),tag.dd(tag.pre(v))] for k,v in cursor.fetchall()] ))) except Exception, e: content = tag.html(tag.body(tag.strong("DB Error: " + unicode(e)))) html = content.generate().render("xhtml") req.send_response(200) req.send_header('Cache-control', 'must-revalidate') req.send_header('Content-Type', 'text/html;charset=utf-8') req.send_header('Content-Length', len(html)) req.end_headers() if req.method != 'HEAD': req.write(html) raise RequestDone
def source(macro, environ, data, *args, **kwargs): """Display the HTML source of some parsed wiki text This macro allows you to display the genereated HTML source of some parsed wiki text. (//Useful mostly for debugging//). **Arguments:** //No Arguments// **Example(s):** {{{ <<source>>**Hello World!**<</source>> }}} <<source>>**Hello World!**<</source>> """ if not macro.body: return None contents = environ.parser.generate(macro.body, context="inline", environ=(environ, data)) return tag.pre("".join(serializer(contents)))
def expand_macro(self, formatter, name, content, args={}): if args: reponame = args.get('repository', '') rev = args.get('revision') else: if ',' in content: reponame = '' rev = 0 for c in [x.strip() for x in content.split(',')]: if c.isnumeric(): rev = c else: reponame = c else: rev = content.strip() reponame = '' repos = RepositoryManager(self.env).get_repository(reponame) if repos: changeset = repos.get_changeset(rev) message = changeset.message rev = changeset.rev else: message = content if formatter.context.resource.realm == 'ticket': ticket_re = CommitTicketUpdater.ticket_re if not any(int(tkt_id) == formatter.context.resource.id for tkt_id in ticket_re.findall(message)): return tag.div(tag.p(_("(The changeset message doesn't " "reference this ticket)"), class_='hint'), class_='commitmessage') if ChangesetModule(self.env).wiki_format_messages: return tag.div(format_to_html(self.env, formatter.context('changeset', rev, parent=repos.resource), message, escape_newlines=True), class_='commitmessage') else: return tag.pre(message, class_='commitmessage')
def _render_view(self, req, id): """Retrieve the report results and pre-process them for rendering.""" title, description, sql = self.get_report(id) try: args = self.get_var_args(req) except ValueError as e: raise TracError(_("Report failed: %(error)s", error=e)) # If this is a saved custom query, redirect to the query module # # A saved query is either an URL query (?... or query:?...), # or a query language expression (query:...). # # It may eventually contain newlines, for increased clarity. # query = ''.join([line.strip() for line in sql.splitlines()]) if query and (query[0] == '?' or query.startswith('query:?')): query = query if query[0] == '?' else query[6:] report_id = 'report=%s' % id if 'report=' in query: if not report_id in query: err = _('When specified, the report number should be ' '"%(num)s".', num=id) req.redirect(req.href.report(id, action='edit', error=err)) else: if query[-1] != '?': query += '&' query += report_id req.redirect(req.href.query() + quote_query_string(query)) elif query.startswith('query:'): try: from trac.ticket.query import Query, QuerySyntaxError query = Query.from_string(self.env, query[6:], report=id) req.redirect(query.get_href(req.href)) except QuerySyntaxError as e: req.redirect(req.href.report(id, action='edit', error=to_unicode(e))) format = req.args.get('format') if format == 'sql': self._send_sql(req, id, title, description, sql) title = '{%i} %s' % (id, title) report_resource = Resource('report', id) req.perm(report_resource).require('REPORT_VIEW') context = web_context(req, report_resource) page = int(req.args.get('page', '1')) default_max = {'rss': self.items_per_page_rss, 'csv': 0, 'tab': 0}.get(format, self.items_per_page) max = req.args.get('max') limit = as_int(max, default_max, min=0) # explict max takes precedence offset = (page - 1) * limit sort_col = req.args.get('sort', '') asc = req.args.get('asc', 1) asc = bool(int(asc)) # string '0' or '1' to int/boolean def report_href(**kwargs): """Generate links to this report preserving user variables, and sorting and paging variables. """ params = args.copy() if sort_col: params['sort'] = sort_col params['page'] = page if max: params['max'] = max params.update(kwargs) params['asc'] = '1' if params.get('asc', asc) else '0' return req.href.report(id, params) data = {'action': 'view', 'report': {'id': id, 'resource': report_resource}, 'context': context, 'title': sub_vars(title, args), 'description': sub_vars(description or '', args), 'max': limit, 'args': args, 'show_args_form': False, 'message': None, 'paginator': None, 'report_href': report_href, } res = self.execute_paginated_report(req, id, sql, args, limit, offset) if len(res) == 2: e, sql = res data['message'] = \ tag_("Report execution failed: %(error)s %(sql)s", error=tag.pre(exception_to_unicode(e)), sql=tag(tag.hr(), tag.pre(sql, style="white-space: pre"))) return 'report_view.html', data, None cols, results, num_items, missing_args, limit_offset = res need_paginator = limit > 0 and limit_offset need_reorder = limit_offset is None results = [list(row) for row in results] numrows = len(results) paginator = None if need_paginator: paginator = Paginator(results, page - 1, limit, num_items) data['paginator'] = paginator if paginator.has_next_page: add_link(req, 'next', report_href(page=page + 1), _('Next Page')) if paginator.has_previous_page: add_link(req, 'prev', report_href(page=page - 1), _('Previous Page')) pagedata = [] shown_pages = paginator.get_shown_pages(21) for p in shown_pages: pagedata.append([report_href(page=p), None, str(p), _('Page %(num)d', num=p)]) fields = ['href', 'class', 'string', 'title'] paginator.shown_pages = [dict(zip(fields, p)) for p in pagedata] paginator.current_page = {'href': None, 'class': 'current', 'string': str(paginator.page + 1), 'title': None} numrows = paginator.num_items # Place retrieved columns in groups, according to naming conventions # * _col_ means fullrow, i.e. a group with one header # * col_ means finish the current group and start a new one field_labels = TicketSystem(self.env).get_ticket_field_labels() header_groups = [[]] for idx, col in enumerate(cols): if col in field_labels: title = field_labels[col] else: title = col.strip('_').capitalize() header = { 'col': col, 'title': title, 'hidden': False, 'asc': None, } if col == sort_col: header['asc'] = asc if not paginator and need_reorder: # this dict will have enum values for sorting # and will be used in sortkey(), if non-empty: sort_values = {} if sort_col in ('status', 'resolution', 'priority', 'severity'): # must fetch sort values for that columns # instead of comparing them as strings with self.env.db_query as db: for name, value in db( "SELECT name, %s FROM enum WHERE type=%%s" % db.cast('value', 'int'), (sort_col,)): sort_values[name] = value def sortkey(row): val = row[idx] # check if we have sort_values, then use them as keys. if sort_values: return sort_values.get(val) # otherwise, continue with string comparison: if isinstance(val, basestring): val = val.lower() return val results = sorted(results, key=sortkey, reverse=(not asc)) header_group = header_groups[-1] if col.startswith('__') and col.endswith('__'): # __col__ header['hidden'] = True elif col[0] == '_' and col[-1] == '_': # _col_ header_group = [] header_groups.append(header_group) header_groups.append([]) elif col[0] == '_': # _col header['hidden'] = True elif col[-1] == '_': # col_ header_groups.append([]) header_group.append(header) # Structure the rows and cells: # - group rows according to __group__ value, if defined # - group cells the same way headers are grouped chrome = Chrome(self.env) row_groups = [] authorized_results = [] prev_group_value = None for row_idx, result in enumerate(results): col_idx = 0 cell_groups = [] row = {'cell_groups': cell_groups} realm = self.realm parent_realm = '' parent_id = '' email_cells = [] for header_group in header_groups: cell_group = [] for header in header_group: value = cell_value(result[col_idx]) cell = {'value': value, 'header': header, 'index': col_idx} col = header['col'] col_idx += 1 # Detect and create new group if col == '__group__' and value != prev_group_value: prev_group_value = value # Brute force handling of email in group by header row_groups.append( (value and chrome.format_author(req, value), [])) # Other row properties row['__idx__'] = row_idx if col in self._html_cols: row[col] = value if col in ('report', 'ticket', 'id', '_id'): row['id'] = value # Special casing based on column name col = col.strip('_') if col in ('reporter', 'cc', 'owner'): email_cells.append(cell) elif col == 'realm': realm = value elif col == 'parent_realm': parent_realm = value elif col == 'parent_id': parent_id = value cell_group.append(cell) cell_groups.append(cell_group) if parent_realm: resource = Resource(realm, row.get('id'), parent=Resource(parent_realm, parent_id)) else: resource = Resource(realm, row.get('id')) # FIXME: for now, we still need to hardcode the realm in the action if resource.realm.upper()+'_VIEW' not in req.perm(resource): continue authorized_results.append(result) if email_cells: for cell in email_cells: emails = chrome.format_emails(context.child(resource), cell['value']) result[cell['index']] = cell['value'] = emails row['resource'] = resource if row_groups: row_group = row_groups[-1][1] else: row_group = [] row_groups = [(None, row_group)] row_group.append(row) data.update({'header_groups': header_groups, 'row_groups': row_groups, 'numrows': numrows}) if format == 'rss': data['context'] = web_context(req, report_resource, absurls=True) return 'report.rss', data, 'application/rss+xml' elif format == 'csv': filename = 'report_%s.csv' % id if id else 'report.csv' self._send_csv(req, cols, authorized_results, mimetype='text/csv', filename=filename) elif format == 'tab': filename = 'report_%s.tsv' % id if id else 'report.tsv' self._send_csv(req, cols, authorized_results, '\t', mimetype='text/tab-separated-values', filename=filename) else: p = page if max is not None else None add_link(req, 'alternate', auth_link(req, report_href(format='rss', page=None)), _('RSS Feed'), 'application/rss+xml', 'rss') add_link(req, 'alternate', report_href(format='csv', page=p), _('Comma-delimited Text'), 'text/plain') add_link(req, 'alternate', report_href(format='tab', page=p), _('Tab-delimited Text'), 'text/plain') if 'REPORT_SQL_VIEW' in req.perm('report', id): add_link(req, 'alternate', req.href.report(id=id, format='sql'), _('SQL Query'), 'text/plain') # reuse the session vars of the query module so that # the query navigation links on the ticket can be used to # navigate report results as well try: req.session['query_tickets'] = \ ' '.join([str(int(row['id'])) for rg in row_groups for row in rg[1]]) req.session['query_href'] = \ req.session['query_href'] = report_href() # Kludge: we have to clear the other query session # variables, but only if the above succeeded for var in ('query_constraints', 'query_time'): if var in req.session: del req.session[var] except (ValueError, KeyError): pass if set(data['args']) - set(['USER']): data['show_args_form'] = True add_script(req, 'common/js/folding.js') if missing_args: add_warning(req, _( 'The following arguments are missing: %(args)s', args=", ".join(missing_args))) return 'report_view.html', data, None
'max': limit, 'args': args, 'show_args_form': False, 'message': None, 'paginator': None, 'report_href': report_href, } try: cols, results, num_items, missing_args = \ self.execute_paginated_report(req, db, id, sql, args, limit, offset) results = [list(row) for row in results] numrows = len(results) except Exception, e: db.rollback() data['message'] = tag_('Report execution failed: %(error)s', error=tag.pre(to_unicode(e))) return 'report_view.html', data, None paginator = None if limit > 0: paginator = Paginator(results, page - 1, limit, num_items) data['paginator'] = paginator if paginator.has_next_page: add_link(req, 'next', report_href(page=page + 1), _('Next Page')) if paginator.has_previous_page: add_link(req, 'prev', report_href(page=page - 1), _('Previous Page')) pagedata = [] shown_pages = paginator.get_shown_pages(21)
def _do_save(self, req, db, milestone): if milestone.exists: req.perm(milestone.resource).require('MILESTONE_MODIFY') else: req.perm(milestone.resource).require('MILESTONE_CREATE') ticket_module = TicketModule(self.env) ticket_module._populate(req, milestone.ticket, False) if not milestone.exists: reporter_id = get_reporter_id(req, 'author') milestone.ticket.values['reporter'] = reporter_id action = req.args.get('action', 'leave') field_changes, problems = ticket_module.get_ticket_changes(req, milestone.ticket, action) if problems: for problem in problems: add_warning(req, problem) add_warning(req, tag(tag.p('Please review your configuration, ' 'probably starting with'), tag.pre('[trac]\nworkflow = ...\n'), tag.p('in your ', tag.tt('trac.ini'), '.')) ) ticket_module._apply_ticket_changes(milestone.ticket, field_changes) old_name = milestone.name new_name = milestone.ticket['summary'] milestone.name = new_name milestone.description = milestone.ticket['description'] due = req.args.get('duedate', '') milestone.due = due and parse_date(due, tzinfo=req.tz) or None milestone.ticket['duedate']=milestone.due and str(to_timestamp(milestone.due)) or None completed = req.args.get('completedate', '') retarget_to = req.args.get('target') # Instead of raising one single error, check all the constraints and # let the user fix them by going back to edit mode showing the warnings warnings = [] def warn(msg): add_warning(req, msg) warnings.append(msg) # -- check the name if new_name: if new_name != old_name: # check that the milestone doesn't already exists # FIXME: the whole .exists business needs to be clarified # (#4130) and should behave like a WikiPage does in # this respect. try: other_milestone = StructuredMilestone(self.env, new_name, db) warn(_('Milestone "%(name)s" already exists, please ' 'choose another name', name=new_name)) except ResourceNotFound: pass else: warn(_('You must provide a name for the milestone.')) # -- check completed date if action in MilestoneSystem(self.env).starting_action: milestone.ticket['started'] = str(to_timestamp(datetime.now(utc))) if action in MilestoneSystem(self.env).completing_action: milestone.completed = datetime.now(utc) if warnings: return self._render_editor(req, db, milestone) # -- actually save changes if milestone.exists: cnum = req.args.get('cnum') replyto = req.args.get('replyto') internal_cnum = cnum if cnum and replyto: # record parent.child relationship internal_cnum = '%s.%s' % (replyto, cnum) now = datetime.now(utc) milestone.save_changes(get_reporter_id(req, 'author'), req.args.get('comment'), when=now, cnum=internal_cnum) # eventually retarget opened tickets associated with the milestone if 'retarget' in req.args and completed: cursor = db.cursor() cursor.execute("UPDATE ticket SET milestone=%s WHERE " "milestone=%s and status != 'closed'", (retarget_to, old_name)) self.env.log.info('Tickets associated with milestone %s ' 'retargeted to %s' % (old_name, retarget_to)) else: milestone.insert() db.commit() add_notice(req, _('Your changes have been saved.')) jump_to = req.args.get('jump_to', 'roadmap') if jump_to=='roadmap': req.redirect(req.href.roadmap()) elif jump_to =='whiteboard': req.redirect(req.href.whiteboard('team_tasks')+'#'+milestone.name) else: req.redirect(req.href.milestone(milestone.name))
def render(self, context, mimetype, content, filename=None, url=None, annotations=None, force_source=False): """Render an XHTML preview of the given `content`. `content` is the same as an `IHTMLPreviewRenderer.render`'s `content` argument. The specified `mimetype` will be used to select the most appropriate `IHTMLPreviewRenderer` implementation available for this MIME type. If not given, the MIME type will be infered from the filename or the content. Return a string containing the XHTML text. When rendering with an `IHTMLPreviewRenderer` fails, a warning is added to the request associated with the context (if any), unless the `disable_warnings` hint is set to `True`. """ if not content: return '' if not isinstance(context, RenderingContext): raise TypeError("RenderingContext expected (since 0.11)") # Ensure we have a MIME type for this content full_mimetype = mimetype if not full_mimetype: if hasattr(content, 'read'): content = content.read(self.max_preview_size) full_mimetype = self.get_mimetype(filename, content) if full_mimetype: mimetype = ct_mimetype(full_mimetype) # split off charset else: mimetype = full_mimetype = 'text/plain' # fallback if not binary # Determine candidate `IHTMLPreviewRenderer`s candidates = [] for renderer in self.renderers: qr = renderer.get_quality_ratio(mimetype) if qr > 0: candidates.append((qr, renderer)) candidates.sort(lambda x, y: cmp(y[0], x[0])) # Wrap file-like object so that it can be read multiple times if hasattr(content, 'read'): content = Content(content, self.max_preview_size) # First candidate which renders successfully wins. # Also, we don't want to expand tabs more than once. expanded_content = None for qr, renderer in candidates: if force_source and not getattr(renderer, 'returns_source', False): continue # skip non-source renderers in force_source mode if isinstance(content, Content): content.reset() try: ann_names = ', '.join(annotations) if annotations else \ 'no annotations' self.log.debug('Trying to render HTML preview using %s [%s]', renderer.__class__.__name__, ann_names) # check if we need to perform a tab expansion rendered_content = content if getattr(renderer, 'expand_tabs', False): if expanded_content is None: content = content_to_unicode(self.env, content, full_mimetype) expanded_content = content.expandtabs(self.tab_width) rendered_content = expanded_content result = renderer.render(context, full_mimetype, rendered_content, filename, url) if not result: continue if not (force_source or getattr(renderer, 'returns_source', False)): # Direct rendering of content if isinstance(result, basestring): if not isinstance(result, unicode): result = to_unicode(result) return Markup(to_unicode(result)) elif isinstance(result, Fragment): return result.generate() else: return result # Render content as source code if annotations: marks = context.req.args.get('marks') if context.req \ else None if marks: context.set_hints(marks=marks) return self._render_source(context, result, annotations) else: if isinstance(result, list): result = Markup('\n').join(result) return tag.div(class_='code')(tag.pre(result)).generate() except Exception as e: self.log.warning('HTML preview using %s failed: %s', renderer.__class__.__name__, exception_to_unicode(e, traceback=True)) if context.req and not context.get_hint('disable_warnings'): from trac.web.chrome import add_warning add_warning( context.req, _("HTML preview using %(renderer)s failed (%(err)s)", renderer=renderer.__class__.__name__, err=exception_to_unicode(e)))
'paginator': None, 'report_href': report_href, } with self.env.db_query as db: try: cols, results, num_items, missing_args = \ self.execute_paginated_report(req, db, id, sql, args, limit, offset) results = [list(row) for row in results] numrows = len(results) except Exception, e: data['message'] = tag_( 'Report execution failed: %(error)s', error=tag.pre(exception_to_unicode(e, traceback=True))) return 'report_view.html', data, None paginator = None if limit > 0: paginator = Paginator(results, page - 1, limit, num_items) data['paginator'] = paginator if paginator.has_next_page: add_link(req, 'next', report_href(page=page + 1), _('Next Page')) if paginator.has_previous_page: add_link(req, 'prev', report_href(page=page - 1), _('Previous Page')) pagedata = [] shown_pages = paginator.get_shown_pages(21)
def _do_save(self, req, db, milestone): if milestone.exists: req.perm(milestone.resource).require('MILESTONE_MODIFY') else: req.perm(milestone.resource).require('MILESTONE_CREATE') ticket_module = TicketModule(self.env) ticket_module._populate(req, milestone.ticket, False) if not milestone.exists: reporter_id = get_reporter_id(req, 'author') milestone.ticket.values['reporter'] = reporter_id action = req.args.get('action', 'leave') field_changes, problems = ticket_module.get_ticket_changes( req, milestone.ticket, action) if problems: for problem in problems: add_warning(req, problem) add_warning( req, tag( tag.p('Please review your configuration, ' 'probably starting with'), tag.pre('[trac]\nworkflow = ...\n'), tag.p('in your ', tag.tt('trac.ini'), '.'))) ticket_module._apply_ticket_changes(milestone.ticket, field_changes) old_name = milestone.name new_name = milestone.ticket['summary'] milestone.name = new_name milestone.description = milestone.ticket['description'] due = req.args.get('duedate', '') milestone.due = due and parse_date(due, tzinfo=req.tz) or None milestone.ticket['duedate'] = milestone.due and str( to_timestamp(milestone.due)) or None completed = req.args.get('completedate', '') retarget_to = req.args.get('target') # Instead of raising one single error, check all the constraints and # let the user fix them by going back to edit mode showing the warnings warnings = [] def warn(msg): add_warning(req, msg) warnings.append(msg) # -- check the name if new_name: if new_name != old_name: # check that the milestone doesn't already exists # FIXME: the whole .exists business needs to be clarified # (#4130) and should behave like a WikiPage does in # this respect. try: other_milestone = StructuredMilestone( self.env, new_name, db) warn( _( 'Milestone "%(name)s" already exists, please ' 'choose another name', name=new_name)) except ResourceNotFound: pass else: warn(_('You must provide a name for the milestone.')) # -- check completed date if action in MilestoneSystem(self.env).starting_action: milestone.ticket['started'] = str(to_timestamp(datetime.now(utc))) if action in MilestoneSystem(self.env).completing_action: milestone.completed = datetime.now(utc) if warnings: return self._render_editor(req, db, milestone) # -- actually save changes if milestone.exists: cnum = req.args.get('cnum') replyto = req.args.get('replyto') internal_cnum = cnum if cnum and replyto: # record parent.child relationship internal_cnum = '%s.%s' % (replyto, cnum) now = datetime.now(utc) milestone.save_changes(get_reporter_id(req, 'author'), req.args.get('comment'), when=now, cnum=internal_cnum) # eventually retarget opened tickets associated with the milestone if 'retarget' in req.args and completed: cursor = db.cursor() cursor.execute( "UPDATE ticket SET milestone=%s WHERE " "milestone=%s and status != 'closed'", (retarget_to, old_name)) self.env.log.info('Tickets associated with milestone %s ' 'retargeted to %s' % (old_name, retarget_to)) else: milestone.insert() db.commit() add_notice(req, _('Your changes have been saved.')) jump_to = req.args.get('jump_to', 'roadmap') if jump_to == 'roadmap': req.redirect(req.href.roadmap()) elif jump_to == 'whiteboard': req.redirect( req.href.whiteboard('team_tasks') + '#' + milestone.name) else: req.redirect(req.href.milestone(milestone.name))
'title': title, 'description': description, 'max': limit, 'args': args, 'show_args_form': False, 'message': None, 'paginator': None, 'report_href': report_href, } res = None with self.env.db_query as db: res = self.execute_paginated_report(req, db, id, sql, args, limit, offset) if len(res) == 2: e, sql = res data['message'] = \ tag_("Report execution failed: %(error)s %(sql)s", error=tag.pre(exception_to_unicode(e)), sql=tag(tag.hr(), tag.pre(sql, style="white-space: pre"))) return 'report_view.html', data, None cols, results, num_items, missing_args, limit_offset = res need_paginator = limit > 0 and limit_offset need_reorder = limit_offset is None results = [list(row) for row in results] numrows = len(results) paginator = None if need_paginator: paginator = Paginator(results, page - 1, limit, num_items) data['paginator'] = paginator if paginator.has_next_page:
def _render_view(self, req, id): """Retrieve the report results and pre-process them for rendering.""" title, description, sql = self.get_report(id) try: args = self.get_var_args(req) except ValueError as e: raise TracError(_("Report failed: %(error)s", error=e)) # If this is a saved custom query, redirect to the query module # # A saved query is either an URL query (?... or query:?...), # or a query language expression (query:...). # # It may eventually contain newlines, for increased clarity. # query = ''.join([line.strip() for line in sql.splitlines()]) if query and (query[0] == '?' or query.startswith('query:?')): query = query if query[0] == '?' else query[6:] report_id = 'report=%s' % id if 'report=' in query: if not report_id in query: err = _( 'When specified, the report number should be ' '"%(num)s".', num=id) req.redirect(req.href.report(id, action='edit', error=err)) else: if query[-1] != '?': query += '&' query += report_id req.redirect(req.href.query() + quote_query_string(query)) elif query.startswith('query:'): try: from trac.ticket.query import Query, QuerySyntaxError query = Query.from_string(self.env, query[6:], report=id) req.redirect(query.get_href(req)) except QuerySyntaxError as e: req.redirect( req.href.report(id, action='edit', error=to_unicode(e))) format = req.args.get('format') if format == 'sql': self._send_sql(req, id, title, description, sql) title = '{%i} %s' % (id, title) report_resource = Resource('report', id) req.perm(report_resource).require('REPORT_VIEW') context = web_context(req, report_resource) page = int(req.args.get('page', '1')) default_max = { 'rss': self.items_per_page_rss, 'csv': 0, 'tab': 0 }.get(format, self.items_per_page) max = req.args.get('max') limit = as_int(max, default_max, min=0) # explict max takes precedence offset = (page - 1) * limit sort_col = req.args.get('sort', '') asc = req.args.get('asc', 1) asc = bool(int(asc)) # string '0' or '1' to int/boolean def report_href(**kwargs): """Generate links to this report preserving user variables, and sorting and paging variables. """ params = args.copy() if sort_col: params['sort'] = sort_col params['page'] = page if max: params['max'] = max params.update(kwargs) params['asc'] = '1' if params.get('asc', asc) else '0' return req.href.report(id, params) data = { 'action': 'view', 'report': { 'id': id, 'resource': report_resource }, 'context': context, 'title': sub_vars(title, args), 'description': sub_vars(description or '', args), 'max': limit, 'args': args, 'show_args_form': False, 'message': None, 'paginator': None, 'report_href': report_href, } res = self.execute_paginated_report(req, id, sql, args, limit, offset) if len(res) == 2: e, sql = res data['message'] = \ tag_("Report execution failed: %(error)s %(sql)s", error=tag.pre(exception_to_unicode(e)), sql=tag(tag.hr(), tag.pre(sql, style="white-space: pre"))) return 'report_view.html', data, None cols, results, num_items, missing_args, limit_offset = res need_paginator = limit > 0 and limit_offset need_reorder = limit_offset is None results = [list(row) for row in results] numrows = len(results) paginator = None if need_paginator: paginator = Paginator(results, page - 1, limit, num_items) data['paginator'] = paginator if paginator.has_next_page: add_link(req, 'next', report_href(page=page + 1), _('Next Page')) if paginator.has_previous_page: add_link(req, 'prev', report_href(page=page - 1), _('Previous Page')) pagedata = [] shown_pages = paginator.get_shown_pages(21) for p in shown_pages: pagedata.append([ report_href(page=p), None, str(p), _('Page %(num)d', num=p) ]) fields = ['href', 'class', 'string', 'title'] paginator.shown_pages = [dict(zip(fields, p)) for p in pagedata] paginator.current_page = { 'href': None, 'class': 'current', 'string': str(paginator.page + 1), 'title': None } numrows = paginator.num_items # Place retrieved columns in groups, according to naming conventions # * _col_ means fullrow, i.e. a group with one header # * col_ means finish the current group and start a new one field_labels = TicketSystem(self.env).get_ticket_field_labels() header_groups = [[]] for idx, col in enumerate(cols): if col in field_labels: title = field_labels[col] else: title = col.strip('_').capitalize() header = { 'col': col, 'title': title, 'hidden': False, 'asc': None, } if col == sort_col: header['asc'] = asc if not paginator and need_reorder: # this dict will have enum values for sorting # and will be used in sortkey(), if non-empty: sort_values = {} if sort_col in ('status', 'resolution', 'priority', 'severity'): # must fetch sort values for that columns # instead of comparing them as strings with self.env.db_query as db: for name, value in db( "SELECT name, %s FROM enum WHERE type=%%s" % db.cast('value', 'int'), (sort_col, )): sort_values[name] = value def sortkey(row): val = row[idx] # check if we have sort_values, then use them as keys. if sort_values: return sort_values.get(val) # otherwise, continue with string comparison: if isinstance(val, basestring): val = val.lower() return val results = sorted(results, key=sortkey, reverse=(not asc)) header_group = header_groups[-1] if col.startswith('__') and col.endswith('__'): # __col__ header['hidden'] = True elif col[0] == '_' and col[-1] == '_': # _col_ header_group = [] header_groups.append(header_group) header_groups.append([]) elif col[0] == '_': # _col header['hidden'] = True elif col[-1] == '_': # col_ header_groups.append([]) header_group.append(header) # Structure the rows and cells: # - group rows according to __group__ value, if defined # - group cells the same way headers are grouped chrome = Chrome(self.env) row_groups = [] authorized_results = [] prev_group_value = None for row_idx, result in enumerate(results): col_idx = 0 cell_groups = [] row = {'cell_groups': cell_groups} realm = 'ticket' parent_realm = '' parent_id = '' email_cells = [] for header_group in header_groups: cell_group = [] for header in header_group: value = cell_value(result[col_idx]) cell = {'value': value, 'header': header, 'index': col_idx} col = header['col'] col_idx += 1 # Detect and create new group if col == '__group__' and value != prev_group_value: prev_group_value = value # Brute force handling of email in group by header row_groups.append( (value and chrome.format_author(req, value), [])) # Other row properties row['__idx__'] = row_idx if col in self._html_cols: row[col] = value if col in ('report', 'ticket', 'id', '_id'): row['id'] = value # Special casing based on column name col = col.strip('_') if col in ('reporter', 'cc', 'owner'): email_cells.append(cell) elif col == 'realm': realm = value elif col == 'parent_realm': parent_realm = value elif col == 'parent_id': parent_id = value cell_group.append(cell) cell_groups.append(cell_group) if parent_realm: resource = Resource(realm, row.get('id'), parent=Resource(parent_realm, parent_id)) else: resource = Resource(realm, row.get('id')) # FIXME: for now, we still need to hardcode the realm in the action if resource.realm.upper() + '_VIEW' not in req.perm(resource): continue authorized_results.append(result) if email_cells: for cell in email_cells: emails = chrome.format_emails(context.child(resource), cell['value']) result[cell['index']] = cell['value'] = emails row['resource'] = resource if row_groups: row_group = row_groups[-1][1] else: row_group = [] row_groups = [(None, row_group)] row_group.append(row) data.update({ 'header_groups': header_groups, 'row_groups': row_groups, 'numrows': numrows }) if format == 'rss': data['email_map'] = chrome.get_email_map() data['context'] = web_context(req, report_resource, absurls=True) return 'report.rss', data, 'application/rss+xml' elif format == 'csv': filename = 'report_%s.csv' % id if id else 'report.csv' self._send_csv(req, cols, authorized_results, mimetype='text/csv', filename=filename) elif format == 'tab': filename = 'report_%s.tsv' % id if id else 'report.tsv' self._send_csv(req, cols, authorized_results, '\t', mimetype='text/tab-separated-values', filename=filename) else: p = page if max is not None else None add_link(req, 'alternate', auth_link(req, report_href(format='rss', page=None)), _('RSS Feed'), 'application/rss+xml', 'rss') add_link(req, 'alternate', report_href(format='csv', page=p), _('Comma-delimited Text'), 'text/plain') add_link(req, 'alternate', report_href(format='tab', page=p), _('Tab-delimited Text'), 'text/plain') if 'REPORT_SQL_VIEW' in req.perm('report', id): add_link(req, 'alternate', req.href.report(id=id, format='sql'), _('SQL Query'), 'text/plain') # reuse the session vars of the query module so that # the query navigation links on the ticket can be used to # navigate report results as well try: req.session['query_tickets'] = \ ' '.join([str(int(row['id'])) for rg in row_groups for row in rg[1]]) req.session['query_href'] = \ req.session['query_href'] = report_href() # Kludge: we have to clear the other query session # variables, but only if the above succeeded for var in ('query_constraints', 'query_time'): if var in req.session: del req.session[var] except (ValueError, KeyError): pass if set(data['args']) - set(['USER']): data['show_args_form'] = True add_script(req, 'common/js/folding.js') if missing_args: add_warning( req, _('The following arguments are missing: %(args)s', args=", ".join(missing_args))) return 'report_view.html', data, None
def expand_macro(self, formatter, name, content): """ """ args, kwargs = parse_args(content, strict=False) kwargs = string_keys(kwargs) cite_list = getattr(formatter, CITE_LIST, []) cite_dict = getattr(formatter, CITE_DICT, {}) if len(args) == 1: label = args[0] description = '' if len(args) == 2: label = args[0] description = args[1] # Allow for extra parameters, people can use it to store BibTeX data. if len(args) == 0: raise TracError('At the very least a `label` is required.') # `makeindex` will not make sense to non-LaTeX users. if label == 'references': h = kwargs.get('h', '1') backref = kwargs.get('backref') tags = [] if h == '1': root = tag.h1 elif h == '2': root = tag.h2 elif h == '3': root = tag.h3 elif h == '4': root = tag.h4 else: root = tag.h5 tags.append(root(id='References')('References')) li = [] for index, label in enumerate(cite_list): description, params = cite_dict[label] if description: line = [description] else: line = [] for key in REFERENCE_SEQUENCE: value = params.get(key) if value: reference_formatter = REFERENCE_FORMAT[key] if callable(reference_formatter): value = reference_formatter(value, params) elif reference_formatter.find('%s') >= 0: value = reference_formatter % value else: continue if value: line.append(value) entry = ', '.join(line) url = params.get('url') if entry and url: entry += ',' if entry: if url: if backref: li.append(tag.li(tag.a(name=label), tag.a(href='#cite_%s' % label)('^'), ' ', entry, tag.br(), tag.a(href=url)(url))) else: li.append(tag.li(tag.a(name=label), entry, tag.br(), tag.a(href=url)(url))) else: if backref: li.append(tag.li(tag.a(name=label), tag.a(href='#cite_%s' % label)('^'), ' ', entry)) else: li.append(tag.li(tag.a(name=label), entry)) else: if url: if backref: li.append(tag.li(tag.a(name=label), tag.a(href='#cite_%s' % label)('^'), ' ', tag.a(href=url)(url))) else: li.append(tag.li(tag.a(name=label), tag.a(href=url)(url))) ol = tag.ol(*li) tags.append(ol) # This is ugly but it is easy. return tag.div(id='References')(*tags) elif label == 'bibtex': indent = kwargs.get('indent', 2) try: indent = int(indent) indent = (indent, 0)[indent < 0] indent = (indent, 8)[indent > 8] except ValueError: intent = 2 references = [] for index, label in enumerate(cite_list): description, params = cite_dict[label] reftype = params.get('reftype', 'Book') reference = [] reference.append('@%s{%s' % (reftype, label)) for key in BIBTEX_SEQUENCE: value = params.get(key) if value: bibtex_formatter = BIBTEX_FORMAT[key] if callable(bibtex_formatter): value = bibtex_formatter(value, params) elif bibtex_formatter.find('%s') >= 0: value = bibtex_formatter % value else: continue if value: reference.append(',\n%s%s = "%s"' % (' ' * indent, key, value)) if len(reference) == 1: reference.append(',') reference.append('\n};') references.append(''.join(reference)) if 'class' in kwargs: kwargs['class_'] = kwargs.pop('class') return tag.pre('\n\n'.join(references), **kwargs) else: if label not in cite_list: cite_list.append(label) cite_dict[label] = (description, kwargs) setattr(formatter, CITE_LIST, cite_list) setattr(formatter, CITE_DICT, cite_dict) backref = True else: backref = False index = cite_list.index(label) + 1 if backref: return ''.join(['[', str(tag.a(name='cite_%s' % label)), str(tag.a(href='#%s' % label)('%d' % index)), ']']) else: return ''.join(['[', str(tag.a(href='#%s' % label)('%d' % index)), ']'])
def expand_macro(self, formatter, name, content): args, kwargs = parse_args(content, strict=True) try: kwargs = string_keys(kwargs) except: raise TracError('Error #3922, content: %s, args: %s, kwargs: %s', (str(content), str(args), kwargs)) if len(args) >= 1: url = args[0] elif len(args) == 0: raise TracError('URL to the mindmap at least required.') embed_count = getattr(formatter, EMBED_COUNT, 0) embed_count += 1 setattr(formatter, EMBED_COUNT, embed_count) if embed_count == 1: add_script(formatter.req, 'freemind/js/flashobject.js') url = get_absolute_url(url, formatter) base = url[:url.rfind('/')+1] #script = '''\ # $(document).ready(function() { # $("#flashcontent%(count)02d").mouseover(function() { # document.visorFreeMind%(count)02d.focus(); # }); # # var fo = new FlashObject("%(visor)s", "visorFreeMind%(count)02d", "100%%", "100%%", 6, "#9999ff"); # # fo.addParam("quality","high"); # fo.addParam("bgcolor","#a0a0f0"); # fo.addVariable("openUrl","_blank"); # fo.addVariable("startCollapsedToLevel","3"); # fo.addVariable("maxNodeWidth","200"); # fo.addVariable("mainNodeShape","elipse"); # fo.addVariable("justMap","false"); # fo.addVariable("initLoadFile","%(file)s"); # fo.addVariable("defaultToolTipWordWrap",200); # fo.addVariable("offsetX","left"); # fo.addVariable("offsetY","top"); # fo.addVariable("buttonsPos","top"); # fo.addVariable("min_alpha_buttons",20); # fo.addVariable("max_alpha_buttons",100); # fo.addVariable("scaleTooltips","false"); # fo.addVariable("baseImagePath","%(base)s"); # fo.addVariable("CSSFile","%(css)s"); # //fo.addVariable("toolTipsBgColor","0xa0a0f0"); # //fo.addVariable("genAllShots","true"); # //fo.addVariable("unfoldAll","true"); # fo.write("flashcontent%(count)02d"); # }); #''' % { # 'count': embed_count, # 'visor': get_absolute_url('htdocs://freemind/swf/visorFreemind.swf', formatter), # 'file': url, # 'base': base, # 'css': get_absolute_url('htdocs://freemind/css/flashfreemind.css', formatter), #} script = '''\ $(document).ready(function() { $("#flashcontent%(count)02d").mouseover(function() { document.visorFreeMind%(count)02d.focus(); }); }); // url: %(url)s // base: %(base)s ''' % {'count': embed_count, 'url': url, 'base': base} flash_dict = { 'openUrl': '_blank', 'initLoadFile': url, 'startCollapsedToLevel': '3', 'defaultToolTipWordWrap': '200', 'baseImagePath': base, 'min_alpha_buttons': '20', 'max_alpha_buttons': '100' } flash_vars = '&'.join(['%s=%s' % (k, v) for k, v in flash_dict.items()]) embed = tag.embed(type='application/x-shockwave-flash', src=get_absolute_url('htdocs://freemind/swf/visorFreemind.swf', formatter), id='visorFreeMind%02d' % embed_count, bgcolor='#ffffff', quality='high', flashvars=flash_vars, align='middle', height='100%', width='100%') # Debugging. if 'debug' in args: import os import datetime output = "FreemindMacro Debug Log\n"\ "=======================\n\n"\ "time: %(time)s\n"\ "version: %(version)s\n"\ "content: %(content)s\n"\ "args: %(args)s\n"\ "kwargs: %(kwargs)s\n"\ "formatter.href.base: %(base)s\n"\ "script: \n\n"\ "%(script)s" % { 'time': datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%SZ'), 'version': __version__, 'content': content, 'args': str(args), 'kwargs': str(kwargs), 'base': str(formatter.href.base), 'script': script } return tag.pre(output, style='border: 2px dashed red; padding: 5px; background: #eee;') style_dict = xform_style(kwargs.get('style', '')) width = kwargs.pop('width', style_dict.get('width', '800px')) height = kwargs.pop('height', style_dict.get('height', '600px')) style_dict['border'] = style_dict.get('border', '1px solid #cccccc;') style_dict['margin'] = style_dict.get('margin', '0 auto') style_dict['width'] = width style_dict['height'] = height kwargs['style'] = xform_style(style_dict) # You can't touch this... kwargs.pop('id', None) if 'class' in kwargs: kwargs['class_'] = kwargs.pop('class') tags = [] #tags.append(tag.div('Flash plugin or JavaScript are turned off. Activate both and reload to view the mindmap.', # id='flashcontent%02d' % embed_count, **kwargs)) tags.append(tag.div(embed, id='flashcontent%02d' % embed_count, **kwargs)) tags.append(tag.script(script)) return ''.join([str(i) for i in tags])
def _render(self, text=None): if text is None: text = self._get_text() return tag.pre(text)
def render_macro(self, req, name, content): args,kwargs = parse_args(content) if len(args) == 0: ul = tag.ul(class_="mailinglistlist") for mailinglist in Mailinglist.select(self.env): if "MAILINGLIST_VIEW" in req.perm(mailinglist.resource): ul.append(tag.li(tag.a(mailinglist.name, href=get_resource_url(self.env, mailinglist.resource, req.href)))) return ul if kwargs.has_key('limit'): limit = int(kwargs['limit']) elif len(args) > 1: limit = int(args[1]) else: limit = 10 resource = Resource("mailinglist",args[0]) instance = MailinglistSystem(self.env).get_instance_for_resource(resource) if isinstance(instance, Mailinglist): if not req.perm(instance.resource).has_permission('MAILINGLIST_VIEW'): return system_message("Permission denied viewing mailinglist: %s" % instance.name) ul = tag.ul() for message in instance.messages(limit=limit, insubject=kwargs.get('insubject', None),desc=True): ul.append(tag.li( tag.a(tag.span(message.subject, class_="messagesubject"), href=get_resource_url(self.env, message.resource, req.href)), " (", dateinfo(message.date), ")", )) ul.append(tag.li(tag.a("(%d messages...)" % instance.count_messages(insubject=kwargs.get('insubject', None)), href=get_resource_url(self.env, instance.resource, req.href)))) return tag.div("Mailinglist: ", tag.a(instance.name, href=get_resource_url(self.env, instance.resource, req.href)), ul, class_="mailinglistfeed") elif isinstance(instance, MailinglistMessage): if not req.perm(instance.resource).has_permission('MAILINGLIST_VIEW'): return system_message("Permission denied viewing mail.") else: limit = None text = wrap_and_quote(instance.body, 78)[0] if limit: text = "\n".join(text.split("\n")[0:limit]) textelement = tag.pre(text) + tag.a(tag.pre("(More...)"), href=get_resource_url(self.env, instance.resource, req.href)) else: textelement = tag.pre(text) return tag.div( tag.div("Mailinglist: ", tag.a(instance.conversation.mailinglist.name, href=get_resource_url(self.env, instance.conversation.mailinglist.resource, req.href))), tag.div("Subject: ", tag.a(instance.subject, href=get_resource_url(self.env, instance.resource, req.href))), tag.div("From: ", tag.a(instance.from_name, href="mailto:%s" % instance.from_email)), tag.div("To: ", instance.to_header), tag.div("Date: ", dateinfo(instance.date)), tag.div(textelement), class_="mailinglistmessage") return system_message("Unknown Mailinglist: %s" % content)
def expand_macro(self, formatter, name, content, args=None): # Utility methods def lte_ie8(req): user_agent = formatter.req.get_header('user-agent') msie = user_agent.find('MSIE ') return (msie != -1) and user_agent[msie + 5:msie + 6] in ['6', '7', '8'] def after_AS(string): index = string.find(' AS ') return index > 0 and string[index + 4:] or string def before_AS(string): index = string.find(' AS ') return index > 0 and string[:index] or string # add scripts if lte_ie8(formatter.req): add_script(formatter.req, "statushistorychart/js/flot/excanvas.js") add_script(formatter.req, "statushistorychart/js/flot/jquery.flot.js") add_script(formatter.req, "statushistorychart/js/flot/jquery.flot.time.js") add_script(formatter.req, "statushistorychart/js/enabler.js") # from macro parameters query = None query_href = None status_list = ['new', 'assigned', 'accepted', 'closed'] # default if(content): # replace parameters for match in reversed([match for match in re_param.finditer(content)]): param_name = match.group(0) if param_name == '$USER': authname = formatter.req.authname if authname == 'anonymous': authname = 'anonymous||somebody' content = content.replace(param_name, authname) else: param_value = formatter.req.args.get(param_name[1:]) if param_value: content = content.replace(param_name, param_value) # execute query query = Query.from_string(formatter.env, content) field = query and query.id or 'status' # stopgap implementation; I use 'report' for y-axis parameter field = filter(lambda x: x['name'] == field, TicketSystem(self.env).fields) if len(field) <= 0: return tag.div(tag.strong('Error: Macro %s failed' % name), tag.pre("%s is not field name" % query.id), class_="system-message") field = field[0] custom = 'custom' in field and field['custom'] or None status_list = query and query.format and query.format.split('/') or \ 'options' in field and copy.copy(field['options']) or status_list if field['name'] == 'status' and not (query and query.format): def isprime(item): primaries = ['new', 'assigned', 'accepted', 'closed'] return (item in primaries and [primaries.index(item)] or [len(primaries)])[0] status_list.sort(key=isprime) if '*' not in status_list: status_list.append('*') default_status = status_list.index('*') # execute query for ids of ticket if(query and len(query.constraint_cols) > 0): result = query.execute() or [{'id':-1}] # Sentinel for no result cond = "ticket.id in (%s)" % ', '.join([str(t['id']) for t in result]) elif formatter.resource.realm == 'milestone': cond = "ticket.milestone='%s'" % formatter.resource.id elif('query_tickets' in formatter.req.session): # You Feeling Lucky query_tickets = formatter.req.session.get('query_tickets', '') query_href = formatter.req.session.get('query_href', '') tickets = len(query_tickets) and query_tickets.split(' ') or ['-1'] # Sentinel for no result cond = "ticket.id in (%s)" % ', '.join(tickets) else: raise TracError("%sMacro: Empty. There are no content and no context." % name) # execute query for value changes of each ticket join_clause_dummy = '' join_clause = "JOIN ticket_custom ON ticket.id = ticket_custom.ticket and ticket_custom.name = '%s'" cursor = formatter.env.get_read_db().cursor() cursor.execute(""" SELECT id, time, null, %s FROM ticket %s WHERE %s UNION SELECT id, ticket_change.time, oldvalue, newvalue FROM ticket JOIN ticket_change ON ticket.id = ticket_change.ticket WHERE %s AND field='%s' ORDER BY id, time """ % (custom and "'\uFEFF'" or field['name'], # ZERO WIDTH NO-BREAK SPACE; uses for mark of invalid data custom and (join_clause % field['name']) or join_clause_dummy, cond, cond, field['name'])) changes = [row for row in cursor.fetchall()] # transform (ticket, time, status)* ==> (ticket <>- status)* tid = 0 # position of ticket id tickets = {} for change in changes: ticket = tickets.get(change[tid]) # slot is exist, or if ticket is None: ticket = tickets[change[tid]] = [] # create new slot and use it ticket.append(list(change)) # generate status_list splitted, {a, b+c, d} => {a:0, b+c:1, b:1, c:1, d:2} status_list_splitted = {} for index, status in enumerate(map(before_AS, status_list)): status_list_splitted[status] = index if status.find('+') >= 0: for each in status.split('+'): status_list_splitted[each] = index # groupstats = self.compmgr[DefaultTicketGroupStatsProvider] # ticket_groups = groupstats._get_ticket_groups() # for group in ticket_groups: # pass for tid in tickets: if len(tickets[tid]) > 1: tickets[tid][0][3] = tickets[tid][1][2] # override last value with initial value # generate data data = [] # points too_many_tickets = len(tickets) > 200 for no, tid in enumerate(sorted(tickets)): if not too_many_tickets or tickets[tid][-1][3] != 'closed': void, time, void, state = tickets[tid][-1] # @UnusedVariable index = status_list_splitted.get(state, default_status) data.append({'points': {'show': True, 'radius': 8, 'color': no}, 'label': tid, 'data': [[time / 1000, index]]}) # lines for no, tid in enumerate(sorted(tickets)): data.append({'color': no, 'label': tid, 'data': [[time / 1000, status_list_splitted.get(state, default_status)] for void, time, void, state in tickets[tid]]}) # @UnusedVariable from trac import __version__ as VERSION if VERSION[0:1] != '0': # render for trac 1.0 or later add_script_data(formatter.req, {'statushistorychart_yaxis': map(after_AS, status_list)}) add_script_data(formatter.req, {'statushistorychart_data': data}) return tag.a(_("Return to Last Query"), href=query_href) \ + tag.div(id="statushistorychart", style="width: 800px; height: 400px;") else: # if trac < 1.0 or earlier from trac.util.presentation import to_json return tag.script("var statushistorychart_yaxis = %s; var statushistorychart_data = %s" \ % (to_json(map(after_AS, status_list)), to_json(data)), type="text/javascript") \ + tag.a(_("Return to Last Query"), href=query_href) \ + tag.div(id="statushistorychart", style="width: 800px; height: 400px;")
def render(self, context, mimetype, content, filename=None, url=None, annotations=None, force_source=False): """Render an XHTML preview of the given `content`. `content` is the same as an `IHTMLPreviewRenderer.render`'s `content` argument. The specified `mimetype` will be used to select the most appropriate `IHTMLPreviewRenderer` implementation available for this MIME type. If not given, the MIME type will be infered from the filename or the content. Return a string containing the XHTML text. When rendering with an `IHTMLPreviewRenderer` fails, a warning is added to the request associated with the context (if any), unless the `disable_warnings` hint is set to `True`. """ if not content: return '' if not isinstance(context, RenderingContext): raise TypeError("RenderingContext expected (since 0.11)") # Ensure we have a MIME type for this content full_mimetype = mimetype if not full_mimetype: if hasattr(content, 'read'): content = content.read(self.max_preview_size) full_mimetype = self.get_mimetype(filename, content) if full_mimetype: mimetype = ct_mimetype(full_mimetype) # split off charset else: mimetype = full_mimetype = 'text/plain' # fallback if not binary # Determine candidate `IHTMLPreviewRenderer`s candidates = [] for renderer in self.renderers: qr = renderer.get_quality_ratio(mimetype) if qr > 0: candidates.append((qr, renderer)) candidates.sort(lambda x, y: cmp(y[0], x[0])) # Wrap file-like object so that it can be read multiple times if hasattr(content, 'read'): content = Content(content, self.max_preview_size) # First candidate which renders successfully wins. # Also, we don't want to expand tabs more than once. expanded_content = None for qr, renderer in candidates: if force_source and not getattr(renderer, 'returns_source', False): continue # skip non-source renderers in force_source mode if isinstance(content, Content): content.reset() try: ann_names = ', '.join(annotations) if annotations else \ 'no annotations' self.log.debug('Trying to render HTML preview using %s [%s]', renderer.__class__.__name__, ann_names) # check if we need to perform a tab expansion rendered_content = content if getattr(renderer, 'expand_tabs', False): if expanded_content is None: content = content_to_unicode(self.env, content, full_mimetype) expanded_content = content.expandtabs(self.tab_width) rendered_content = expanded_content result = renderer.render(context, full_mimetype, rendered_content, filename, url) if not result: continue if not (force_source or getattr(renderer, 'returns_source', False)): # Direct rendering of content if isinstance(result, basestring): if not isinstance(result, unicode): result = to_unicode(result) return Markup(to_unicode(result)) elif isinstance(result, Fragment): return result.generate() else: return result # Render content as source code if annotations: m = context.req.args.get('marks') if context.req else None return self._render_source(context, result, annotations, m and Ranges(m)) else: if isinstance(result, list): result = Markup('\n').join(result) return tag.div(class_='code')(tag.pre(result)).generate() except Exception, e: self.log.warning('HTML preview using %s failed: %s', renderer.__class__.__name__, exception_to_unicode(e, traceback=True)) if context.req and not context.get_hint('disable_warnings'): from trac.web.chrome import add_warning add_warning(context.req, _("HTML preview using %(renderer)s failed (%(err)s)", renderer=renderer.__class__.__name__, err=exception_to_unicode(e)))
"args": args, "show_args_form": False, "message": None, "paginator": None, "report_href": report_href, } res = None with self.env.db_query as db: res = self.execute_paginated_report(req, db, id, sql, args, limit, offset) if len(res) == 2: e, sql = res data["message"] = tag_( "Report execution failed: %(error)s %(sql)s", error=tag.pre(exception_to_unicode(e)), sql=tag(tag.hr(), tag.pre(sql, style="white-space: pre")), ) return "report_view.html", data, None cols, results, num_items, missing_args, limit_offset = res need_paginator = limit > 0 and limit_offset need_reorder = limit_offset is None results = [list(row) for row in results] numrows = len(results) paginator = None if need_paginator: paginator = Paginator(results, page - 1, limit, num_items) data["paginator"] = paginator if paginator.has_next_page:
'max': limit, 'args': args, 'show_args_form': False, 'message': None, 'paginator': None, 'report_href': report_href, } with self.env.db_query as db: try: cols, results, num_items, missing_args = \ self.execute_paginated_report(req, db, id, sql, args, limit, offset) results = [list(row) for row in results] numrows = len(results) except Exception, e: data['message'] = tag_('Report execution failed: %(error)s', error=tag.pre(exception_to_unicode(e, traceback=True))) return 'report_view.html', data, None paginator = None if limit > 0: paginator = Paginator(results, page - 1, limit, num_items) data['paginator'] = paginator if paginator.has_next_page: add_link(req, 'next', report_href(page=page + 1), _('Next Page')) if paginator.has_previous_page: add_link(req, 'prev', report_href(page=page - 1), _('Previous Page')) pagedata = [] shown_pages = paginator.get_shown_pages(21)
'message': None, 'paginator': None, 'report_href': report_href, } try: cols, results, num_items, missing_args = \ self.execute_paginated_report(req, db, id, sql, args, limit, offset) results = [list(row) for row in results] numrows = len(results) except Exception, e: db.rollback() data['message'] = tag_('Report execution failed: %(error)s', error=tag.pre(to_unicode(e))) return 'report_view.html', data, None paginator = None if limit > 0: paginator = Paginator(results, page - 1, limit, num_items) data['paginator'] = paginator if paginator.has_next_page: add_link(req, 'next', report_href(page=page + 1), _('Next Page')) if paginator.has_previous_page: add_link(req, 'prev', report_href(page=page - 1), _('Previous Page')) pagedata = [] shown_pages = paginator.get_shown_pages(21)
def expand_macro(self, formatter, name, content): args, kwargs = parse_args(content, strict=True) try: kwargs = string_keys(kwargs) except: raise TracError('Error #3922, content: %s, args: %s, kwargs: %s', (str(content), str(args), kwargs)) if len(args) >= 1: url = args[0] elif len(args) == 0: raise TracError('URL to the mindmap at least required.') embed_count = getattr(formatter, EMBED_COUNT, 0) embed_count += 1 setattr(formatter, EMBED_COUNT, embed_count) if embed_count == 1: add_script(formatter.req, 'freemind/js/flashobject.js') url = get_absolute_url(url, formatter) base = url[:url.rfind('/') + 1] #script = '''\ # $(document).ready(function() { # $("#flashcontent%(count)02d").mouseover(function() { # document.visorFreeMind%(count)02d.focus(); # }); # # var fo = new FlashObject("%(visor)s", "visorFreeMind%(count)02d", "100%%", "100%%", 6, "#9999ff"); # # fo.addParam("quality","high"); # fo.addParam("bgcolor","#a0a0f0"); # fo.addVariable("openUrl","_blank"); # fo.addVariable("startCollapsedToLevel","3"); # fo.addVariable("maxNodeWidth","200"); # fo.addVariable("mainNodeShape","elipse"); # fo.addVariable("justMap","false"); # fo.addVariable("initLoadFile","%(file)s"); # fo.addVariable("defaultToolTipWordWrap",200); # fo.addVariable("offsetX","left"); # fo.addVariable("offsetY","top"); # fo.addVariable("buttonsPos","top"); # fo.addVariable("min_alpha_buttons",20); # fo.addVariable("max_alpha_buttons",100); # fo.addVariable("scaleTooltips","false"); # fo.addVariable("baseImagePath","%(base)s"); # fo.addVariable("CSSFile","%(css)s"); # //fo.addVariable("toolTipsBgColor","0xa0a0f0"); # //fo.addVariable("genAllShots","true"); # //fo.addVariable("unfoldAll","true"); # fo.write("flashcontent%(count)02d"); # }); #''' % { # 'count': embed_count, # 'visor': get_absolute_url('htdocs://freemind/swf/visorFreemind.swf', formatter), # 'file': url, # 'base': base, # 'css': get_absolute_url('htdocs://freemind/css/flashfreemind.css', formatter), #} script = '''\ $(document).ready(function() { $("#flashcontent%(count)02d").mouseover(function() { document.visorFreeMind%(count)02d.focus(); }); }); // url: %(url)s // base: %(base)s ''' % { 'count': embed_count, 'url': url, 'base': base } flash_dict = { 'openUrl': '_blank', 'initLoadFile': url, 'startCollapsedToLevel': '3', 'defaultToolTipWordWrap': '200', 'baseImagePath': base, 'min_alpha_buttons': '20', 'max_alpha_buttons': '100' } flash_vars = '&'.join( ['%s=%s' % (k, v) for k, v in flash_dict.items()]) embed = tag.embed(type='application/x-shockwave-flash', src=get_absolute_url( 'htdocs://freemind/swf/visorFreemind.swf', formatter), id='visorFreeMind%02d' % embed_count, bgcolor='#ffffff', quality='high', flashvars=flash_vars, align='middle', height='100%', width='100%') # Debugging. if 'debug' in args: import os import datetime output = "FreemindMacro Debug Log\n"\ "=======================\n\n"\ "time: %(time)s\n"\ "version: %(version)s\n"\ "content: %(content)s\n"\ "args: %(args)s\n"\ "kwargs: %(kwargs)s\n"\ "formatter.href.base: %(base)s\n"\ "script: \n\n"\ "%(script)s" % { 'time': datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%SZ'), 'version': __version__, 'content': content, 'args': str(args), 'kwargs': str(kwargs), 'base': str(formatter.href.base), 'script': script } return tag.pre( output, style='border: 2px dashed red; padding: 5px; background: #eee;' ) style_dict = xform_style(kwargs.get('style', '')) width = kwargs.pop('width', style_dict.get('width', '800px')) height = kwargs.pop('height', style_dict.get('height', '600px')) style_dict['border'] = style_dict.get('border', '1px solid #cccccc;') style_dict['margin'] = style_dict.get('margin', '0 auto') style_dict['width'] = width style_dict['height'] = height kwargs['style'] = xform_style(style_dict) # You can't touch this... kwargs.pop('id', None) if 'class' in kwargs: kwargs['class_'] = kwargs.pop('class') tags = [] #tags.append(tag.div('Flash plugin or JavaScript are turned off. Activate both and reload to view the mindmap.', # id='flashcontent%02d' % embed_count, **kwargs)) tags.append( tag.div(embed, id='flashcontent%02d' % embed_count, **kwargs)) tags.append(tag.script(script)) return ''.join([str(i) for i in tags])
def _render_source(self, context, stream, annotations): from trac.web.chrome import add_warning annotators, labels, titles = {}, {}, {} for annotator in self.annotators: atype, alabel, atitle = annotator.get_annotation_type() if atype in annotations: labels[atype] = alabel titles[atype] = atitle annotators[atype] = annotator annotations = [a for a in annotations if a in annotators] if isinstance(stream, list): stream = HTMLParser(StringIO(u"\n".join(stream))) elif isinstance(stream, unicode): text = stream def linesplitter(): for line in text.splitlines(True): yield TEXT, line, (None, -1, -1) stream = linesplitter() annotator_datas = [] for a in annotations: annotator = annotators[a] try: data = (annotator, annotator.get_annotation_data(context)) except TracError as e: self.log.warning("Can't use annotator '%s': %s", a, e) add_warning( context.req, tag.strong( tag_("Can't use %(annotator)s annotator: %(error)s", annotator=tag.em(a), error=tag.pre(e)) ), ) data = None, None annotator_datas.append(data) def _head_row(): return tag.tr( [tag.th(labels[a], class_=a, title=titles[a]) for a in annotations] + [tag.th(u"\xa0", class_="content")] ) def _body_rows(): for idx, line in enumerate(_group_lines(stream)): row = tag.tr() for annotator, data in annotator_datas: if annotator: annotator.annotate_row(context, row, idx + 1, line, data) else: row.append(tag.td()) row.append(tag.td(line)) yield row return tag.table(class_="code")(tag.thead(_head_row()), tag.tbody(_body_rows()))