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 == 'ticket.html': ticket = data['ticket'] if ticket.exists: if req.perm.has_permission('SENSITIVE_VIEW'): qry = DBSession().query(CustomerRequest) if not qry.get(ticket.values.get('customerrequest')).active: div = tag.div( tag.div( tag.strong(u'Heads up! '), tag.span(u'This ticket is assigned to an inactive customer request.',), class_="alert alert-info"), id='inactive_cr_ticket') return stream | Transformer("//div[@id='ticket']").before(div) return stream
def filter_stream(self, req, method, filename, stream, data): """ Wrap the banner and mainnav in a single banner_wrapper div """ add_stylesheet(req, "http://fonts.googleapis.com/css?family=Ubuntu") add_stylesheet(req, "lightertheme/theme.css") stream |= Transformer("//div[@id='banner']").wrap(tag.div(class_="banner_wrapper banner_wrapper_first")) stream |= Transformer("//div[@id='mainnav']").wrap(tag.div(class_="banner_wrapper banner_wrapper_second")) stream |= Transformer("//div[@class='banner_wrapper banner_wrapper_first']").append(tag.hr()) return stream filter = Transformer("//div[@id='banner']") stream |= ( filter.wrap(tag.div(id="banner_wrapper")) .end() .select("//div[@id='mainnav']") .cut(buffer, accumulate=True) .end() .buffer() .select("//div[@id='banner_wrapper']") .append(tag.hr()) .append(buffer) .end() ) return stream
def filter_stream(self, req, method, filename, stream, data): if filename == 'browser.html' and req.method == 'GET': # we can only work from the 'dir' view at the moment if data.get('file'): return stream # TODO check that contextmenu's InternalNameHolder is enabled, as our js needs it? add_stylesheet(req, 'sourcesharer/filebox.css') add_javascript(req, 'sourcesharer/filebox.js') # Render the filebox template for stream insertion # TODO introduce a new interface to allow putting extra buttons into this filebox? tmpl = TemplateLoader(self.get_templates_dirs()).load('filebox.html') filebox = tmpl.generate(href=req.href, reponame=data['reponame'] or '', rev=data['rev'], files=[]) # Wrap and float dirlist table, add filebox div # TODO change the id names, left/right seems a bit generic to assume we can have to ourselves stream |= Transformer('//table[@id="dirlist"]').wrap(tag.div(id="outer",style="clear:both")).wrap(tag.div(id="left")) stream |= Transformer('//div[@id="outer"]').append(tag.div(filebox, id="right")) is_svn_repo = False if 'repos' in data: is_svn_repo = isinstance(data.get('repos'), (SvnCachedRepository, SubversionRepository)) or False if is_svn_repo: add_ctxtnav(req, tag.a(_(tag.i(class_="fa fa-envelope-o")), " Send", href="", title=_("Send selected files"), id='share-files', class_='alt-button share-files-multiple'), category='ctxtnav', order=10) return stream
def _render_full_format(self, formatter, post_list, post_instances, heading, max_size, show_meta): """ Renters full blog posts. """ out = tag.div(class_="blog") out.append(tag.div(heading, class_="blog-list-title")) for post in post_instances: data = { 'post': post, 'blog_personal_blog': self.config.getbool('fullblog', 'personal_blog'), 'list_mode': True, 'show_meta': show_meta, 'execute_blog_macro': True } if max_size: data['blog_max_size'] = max_size out.append( Chrome(self.env).render_template(formatter.req, 'fullblog_macro_post.html', data=data, fragment=True)) return out
def expand_macro(self, formatter, name, content, args=None): hint = '|| yyyy-mm-ddThh:mm:ss || yyyy-mm-ddThh:mm:ss || message' pattern = "\s*||(.*)||(.*)||(.*)".replace('|', '\|') pattern = re.compile(pattern) try: if content == None: return tag.div('ShowWhen Macro is not supported. Use WikiProcessor-style instead.', \ class_="system-message") now = datetime.now(utc) for line in content.split('\n'): matched = pattern.match(line) if matched: result = matched.groups() by, to, text = result by, to = parse_date(by, None, hint), parse_date(to, None, hint) self.env.log.debug('parsed time range: %s / %s' % (by, to)) if by <= now and now <= to: return format_to_html(self.env, formatter.context, text) return None except Exception, e: return tag.div(tag.strong(e.title), ': ' + e.message, class_="system-message")
def render_timeline_event(self, context, field, event): """Display the title of the event in the given context. Full description here http://trac.edgewall.org/browser/trunk/trac/timeline/api.py """ if field == 'url': return event[3]['url'] elif field == 'title': return "Build %s #%s was %s" % (event[3]['builder'], event[3]['num'], event[0]) elif field == 'description': data = event[3] msg = tag.span() if data['source'] and data["rev"]: rev_msg = tag.div("rev: ", tag.a(data['rev'][:7], href=context.href("/browser/%s" % data['source'], rev=data['rev'])), " ", tag.a(tag.img(src=context.href("/chrome/common/changeset.png")), href=context.href("/changeset/%s/%s" % (data['rev'], data['source']))) ) msg.append(rev_msg) if 'error' in event[3] and event[3]['error']: error_msg = tag.div(event[3]['error'], " ") if 'error_log' in event[3] and event[3]['error_log']: error_msg.append(tag.a("Log", href=event[3]['error_log'])) msg.append(error_msg) return msg
def _reminder_tags(self, req, data): if 'ticket' not in data or not data['ticket'].id: return None ticket = data['ticket'] if ticket['status'] == 'closed': return None li_tags = [tag.li(self._format_reminder(req, ticket, *args)) for args in self._get_reminders(ticket.id)] if li_tags: list_tags = tag.ul(li_tags, class_="reminders") else: list_tags = [] add_form = self._reminder_add_form(req) if not list_tags and not add_form: return None return \ tag.div( tag.h2("Reminders", class_="foldable"), tag.div( list_tags, add_form, ), id="reminders", )
def filter_stream(self, req, method, filename, stream, data): if req.get_header("X-Moz") == "prefetch": return stream if filename == "ticket.html": if not self.check_permissions(req): return stream chrome = Chrome(self.env) filter = Transformer('//fieldset[@id="properties"]') # add a hidden div to hold the ticket_fields input snippet = tag.div(style="display:none;") snippet = tag.input(type="hidden", id="field-ticket_fields", name="field_ticket_fields", value=','.join(data['ticket_fields'])) stream = stream | filter.after(snippet) if req.path_info != '/newticket': # insert the ticket field groups after the standard trac 'Change Properties' field group stream = stream | filter.after(chrome.render_template(req, 'ticket_fields_datatable.html', data, fragment=True)) elif filename == "admin_enums.html": if not self.check_permissions(req) or not req.args.get('path_info'): return stream for k,v in {'cat_id':'ticket', 'panel_id':'type'}.iteritems(): if k not in req.args or req.args.get(k) != v: return stream if 'ticket_fields' in data: chrome = Chrome(self.env) filter = Transformer('//div[@class="buttons"]') # add a hidden div to hold the ticket_fields input snippet = tag.div(style="display:none;") snippet = tag.input(type="hidden", id="field-ticket_fields", name="field_ticket_fields", value=','.join(data['ticket_fields'])) stream = stream | filter.before(snippet) stream = stream | filter.before(chrome.render_template(req, 'ticket_fields_datatable.html', data, fragment=True)) return stream
def render_statistics(self,ticketlist): # fallback if preconditions are not holding if len(ticketlist) == 0 or self.statistics_fields == []: return tag.span() # create a new map statistics_values = {} for field in self.statistics_fields: statistics_values[field] = 0 # map containing titles field_titles = {} for field in self.statistics_fields: field_titles[field] = 'sum of "%s"' % (field,) # summarize the field values of each ticket html = tag.div() for ticket in ticketlist: for field in self.statistics_fields: try: statistics_values[field] += int(ticket.getfield(field)) except: field_titles[field] = '"%s" could not be parsed to number' % (field,) # create html construct separator = '' for field in self.statistics_fields: html(separator, tag.span('%s' % (statistics_values[field],), title=field_titles[field]) ) separator = '/' return tag.div(html, class_='pptableticketperdaystatistics')
def process_request(self, req): """Redirect to pre-selected target.""" if self.redirect_target or self._check_redirect(req): target = self.redirect_target # Check for self-redirect: if target and target == req.href(req.path_info): message = tag.div('Please ', tag.a("change the redirect target", href=target + "?action=edit"), ' to another page.', class_="system-message") data = { 'title': "Page redirects to itself!", 'message': message, 'type': 'TracError', } req.send_error(data['title'], status=409, env=self.env, data=data) raise RequestDone # Check for redirect pair, i.e. A->B, B->A if target and target == req.href.wiki( req.args.get('redirectedfrom', '')): message = tag.div( 'Please change the redirect target from either ', tag.a("this page", href=req.href(req.path_info, action="edit")), ' or ', tag.a("the redirecting page", href=target + "?action=edit"), '.', class_="system-message") data = { 'title': "Redirect target redirects back to this page!", 'message': message, 'type': 'TracError', } req.send_error(data['title'], status=409, env=self.env, data=data) raise RequestDone # Add back link information for internal links: if target and target[0] == '/': redirectfrom = "redirectedfrom=" + req.path_info[6:] # anchor should be the last in url # according to http://trac.edgewall.org/ticket/8072 tgt, query, anchor = self.split_link(target) if not query: query = "?" + redirectfrom else: query += "&" + redirectfrom target = tgt + query + anchor req.redirect(target) raise RequestDone raise TracError("Invalid redirect target!")
def _reminder_tags(self, req, data): if 'ticket' not in data or not data['ticket'].id: return None ticket = data['ticket'] if ticket['status'] == 'closed': return None li_tags = [ tag.li(self._format_reminder(req, ticket, *args)) for args in self._get_reminders(ticket.id) ] if li_tags: list_tags = tag.ul(li_tags, class_="reminders") else: list_tags = [] add_form = self._reminder_add_form(req) if not list_tags and not add_form: return None return \ tag.div( tag.h2("Reminders", class_="foldable"), tag.div( list_tags, add_form, ), id="reminders", )
def render_timeline_event(self, context, field, event): #self.log.debug("Monit: render_timeline_event() called") evt, srv, monit = event[3] if field == 'url': return context.href.monit('event', evt['id']) elif field == 'title': return tag(tag.em('New ', srv_types.get(evt['type'], ''), ' event')) elif field == 'description': if srv and monit: markup = tag.div('Event on ', tag.b(monit['localhostname']), ' for service ', tag.b(srv['name']), '(type %s) ' % srv_types.get(evt['type'], ''), tag.em(evt['message'])) self.log.debug("Monit markup for Timeline -> %s" % str(markup)) elif srv: markup = tag.div('Event on ', tag.b('unknown'), ' for service ', tag.b(srv['name']), '(type %s) ' % srv_types.get(evt['type'], ''), tag.em(evt['message'])) else: markup = tag.div('Event on ', tag.b('unknown'), ' for service ', tag.b('unknown'), '(type unknown)', tag.em(evt['message'])) self.log.debug("Monit markup for Timeline -> %s" % str(markup)) return markup
def filter_stream(self, req, method, filename, stream, data): """ Wrap the banner and mainnav in a single banner_wrapper div """ add_stylesheet(req, 'http://fonts.googleapis.com/css?family=Ubuntu') add_stylesheet(req, 'lightertheme/theme.css') stream |= Transformer("//div[@id='banner']").wrap( tag.div(class_="banner_wrapper banner_wrapper_first")) stream |= Transformer("//div[@id='mainnav']").wrap( tag.div(class_="banner_wrapper banner_wrapper_second")) stream |= Transformer( "//div[@class='banner_wrapper banner_wrapper_first']").append( tag.hr()) return stream filter = Transformer("//div[@id='banner']") stream |= filter.wrap(tag.div( id="banner_wrapper")).end().select("//div[@id='mainnav']").cut( buffer, accumulate=True).end().buffer().select( "//div[@id='banner_wrapper']").append( tag.hr()).append(buffer).end() return stream
def render_ticket_action_control(self, req, ticket, action): config = self.parse_config() assert action in config control = [] hints = [] data = config[action] action_name = action # @@TODO: config'able label/name chrome = Chrome(self.env) from trac.ticket.web_ui import TicketModule prepared_fields = TicketModule(self.env)._prepare_fields(req, ticket) for field in data.get('fields', []): id = "action_%s_%s" % (action, field) operation = data.get('operations', {}).get(field, "change") assert operation in ["change", "unset"] if operation == "unset": hints.append("%s will be unset" % field) # @@TODO: i18n continue assert operation == "change" current_value = ticket._old.get(field, ticket[field]) or "" rendered_control = '' prepared_field = [pfield for pfield in prepared_fields if pfield['name'] == field] if len(prepared_field): prepared_field = prepared_field[0] # we can't use chrome.render_template here, or it will blow away # key scripts like jquery.js and trac.js in the eventual 'primary' template # that's rendered by process_request template = chrome.load_template("ticket_fields.html", method="xhtml") rendered_control = template.generate(ticket=ticket, field=prepared_field) if rendered_control: rendered_control = Markup(rendered_control) control.append(tag.label(field, rendered_control or tag.input( name=id, id=id, type='text', value=current_value))) current_status = ticket._old.get('status', ticket['status']) new_status = data['status'].get(current_status) or \ data['status']['*'] if new_status != '*': hints.append("Next status will be %s" % new_status) # @@TODO: i18n add_script(req, "workflow_ticketfields/workflow_ticketfields.js") return (action_name, tag.div(*[tag.div(element, style=("display: inline-block; " "margin-right: 1em")) for element in control], class_="workflow_ticket_fields", style="margin-left: 2em; display: none"), '. '.join(hints) + '.' if hints else '')
def render_col_tree(self, req, col_root, model): return tag.div( tag.div( tag.a( 'Collapse All', href = '?#' ), ' | ', tag.a( 'Expand All', href = '?#' ), id = 'sidetreecontrol', style = 'font-size:xx-small;'), tag.div( tag.a( 'Library', href = req.href.zotero('collection') ) ), self.render_child_col( req, col_root, model ), id="coltree", class_="treeview")
def render(self, ticketset): ''' Generate HTML List TODO: improve computation of ticket set ''' orderedtickets = {} field = 'due_close' weekdays = ['PLACEHOLDER', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'] r = '' div = tag.div() div(class_=self.cssclass + ' projectplanrender') # check for missing parameters missingparameter = False if self.rows == []: div( tag.div( 'Missing parameter "rows": use a semicolon-separated list to input the "' + self.rowtype + '".', class_='ppwarning')) missingparameter = True if self.rowtype == None or str(self.rowtype).strip() == '': div( tag.div( 'Missing parameter "rowtype": specifies the ticket attribute that should be showed.', class_='ppwarning')) missingparameter = True if self.segments == []: div( tag.div( 'Missing parameter: use a semicolon-separated list to input the "segments".', class_='ppwarning')) missingparameter = True if missingparameter: return div # init the matrix for segment in self.segments: orderedtickets[segment] = {} for o in self.rows: orderedtickets[segment][o] = [] # fill up matrix self.macroenv.tracenv.log.debug('number of tickets: ' + str(len(ticketset.getIDList()))) for tid in ticketset.getIDList(): try: ticket = ticketset.getTicket(tid) orderedtickets[ticket.getfield(field)][ticket.getfield( self.rowtype)].append(ticket) except Exception, e: self.macroenv.tracenv.log.debug('fill up matrix: #' + str(tid) + ' ' + repr(e)) pass
def expand_macro(self, formatter, names, content): if not content: edit = '' text = "''Gringlet Name Missing''" acl = '' elif not re.match(r'^[a-zA-Z0-9]+$', content): edit = '' text = tag.em( "Invalid Gringlet Name - only letters and numbers allowed") acl = '' else: db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute( 'SELECT text,acl FROM gringotts WHERE name=%s AND version=' '(SELECT MAX(version) FROM gringotts WHERE name=%s)', (content, content)) try: text, acl = cursor.fetchone() key = str(self.config.get('gringotts', 'key')) k = ezPyCrypto.key(key) text = wiki_to_html(k.decStringFromAscii(text), self.env, formatter.req) edit = 'Edit' except: edit = 'Create' text = tag.em("No Gringlet called \"%s\" found" % content) acl = '' if acl: if not validate_acl(formatter.req, acl): text = tag.em( "You do not have permission to view the \"%s\" Gringlet." % content) edit = '' control = None if edit: control = tag.div(tag.a(edit, href=(formatter.href.gringotts() + "/" + content + "?action=edit")), class_="gringottcontrol") # Use eight divs for flexible frame styling return tag.div(tag.div(tag.div(tag.div(tag.div(tag.div( tag.div(tag.div(tag.div(text, class_="gringottcontent") + control, class_="gringott"), class_="gringott"), class_="gringott"), class_="gringott"), class_="gringott"), class_="gringott"), class_="gringott"), class_="gringottframe")
def expand_macro(self, formatter, names, content): if not content: edit = '' text = "''Gringlet Name Missing''" acl = '' elif not re.match(r'^[a-zA-Z0-9]+$', content): edit = '' text = tag.em("Invalid Gringlet Name - only letters and numbers allowed") acl = '' else: db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute('SELECT text,acl FROM gringotts WHERE name=%s AND version=' '(SELECT MAX(version) FROM gringotts WHERE name=%s)', (content, content)) try: text,acl = cursor.fetchone() key = str(self.config.get('gringotts', 'key')) k = ezPyCrypto.key(key) text = wiki_to_html(k.decStringFromAscii(text), self.env, formatter.req) edit = 'Edit' except: edit = 'Create' text = tag.em("No Gringlet called \"%s\" found" % content) acl = '' if acl: if not validate_acl(formatter.req, acl): text = tag.em("You do not have permission to view the \"%s\" Gringlet." % content) edit = '' control = None if edit: control = tag.div(tag.a(edit, href=(formatter.href.gringotts() + "/" + content + "?action=edit")), class_="gringottcontrol") # Use eight divs for flexible frame styling return tag.div( tag.div( tag.div( tag.div( tag.div( tag.div( tag.div( tag.div( tag.div(text, class_="gringottcontent") + control, class_="gringott"), class_="gringott"), class_="gringott"), class_="gringott"), class_="gringott"), class_="gringott"), class_="gringott"), class_="gringottframe")
def expand_macro(self, formatter, name, content, args): title = 'Color Scheme' classes = 'colormacro' if args and 'title' in args: title = args['title'] if args and 'class' in args: classes += ' ' + args['class'] tbody = [] have_comment = False colors = self._parse_arguments(content) for color in colors: if len(color['title']) > 0: have_comment = True ## Create row tbody.append( [ tag.td()(tag.strong(color['title'])), tag.td( style='background-color:' + color['orig'] )( tag.div(style='color: black')(color['hex']), tag.div(style='color: white')(color['hex']) ), tag.td( style='background-color:' + color['orig'] )( tag.div(style='color: black')(color['rgbp']), tag.div(style='color: white')(color['rgbp']) ), ] ) ## end for loop if len(tbody) > 0: colcount = len(tbody[0]) if not have_comment: colcount -= 1 table = tag.table(class_=classes) table()(tag.thead()(tag.th(colspan='%d' % colcount)(title))) ## Attach row in table. if have_comment: table()(tag.tbody(class_='colorlist')([tag.tr(row) for row in tbody])) else: table()(tag.tbody(class_='colorlist')([tag.tr(row[1:]) for row in tbody])) return table; else: return tag.div(class_='colormacro')('Nothing to display')
def expand_macro(self, formatter, name, text, args): if not text: raw_actions = self.config.options('ticket-workflow') else: if args is None: text = '\n'.join([line.lstrip() for line in text.split(';')]) if '[ticket-workflow]' not in text: text = '[ticket-workflow]\n' + text parser = RawConfigParser() try: parser.readfp(StringIO(text)) except ParsingError as e: return system_message(_("Error parsing workflow."), unicode(e)) raw_actions = list(parser.items('ticket-workflow')) actions = parse_workflow_config(raw_actions) states = list( set([ state for action in actions.itervalues() for state in action['oldstates'] ] + [action['newstate'] for action in actions.itervalues()])) action_labels = [attrs['label'] for attrs in actions.values()] action_names = actions.keys() edges = [] for name, action in actions.items(): new_index = states.index(action['newstate']) name_index = action_names.index(name) for old_state in action['oldstates']: old_index = states.index(old_state) edges.append((old_index, new_index, name_index)) args = args or {} width = args.get('width', 800) height = args.get('height', 600) graph = { 'nodes': states, 'actions': action_labels, 'edges': edges, 'width': width, 'height': height } graph_id = '%012x' % id(graph) req = formatter.req add_script(req, 'common/js/excanvas.js', ie_if='IE') add_script(req, 'common/js/workflow_graph.js') add_script_data(req, {'graph_%s' % graph_id: graph}) return tag( tag.div('', class_='trac-workflow-graph trac-noscript', id='trac-workflow-graph-%s' % graph_id, style="display:inline-block;width:%spx;height:%spx" % (width, height)), tag.noscript( tag.div(_("Enable JavaScript to display the workflow graph."), class_='system-message')))
def _render(self, req, ticket, exists): if exists: message = self.changesets.format() return tag.div(tag.h2(_("Repository Changesets"), class_='foldable'), tag.div(message, id='changelog'), class_=self.collapsed and 'collapsed') else: message = _("(none)") return tag.div(tag.h2(_("Repository Changesets"), ' ', message, class_='foldable'))
def expand_macro(self, formatter, name, content): req = formatter.req query_string = TicketQueryMacro.parse_args(content)[0] kwargs = dict([item.split('=') for item in content.split(',')[1:]]) try: query = Query.from_string(self.env, query_string) except QuerySyntaxError as e: raise MacroError(e) try: tickets = query.execute(req) except QueryValueError as e: raise MacroError(e) # Formats above had their own permission checks, here we need to # do it explicitly: tickets = [t for t in tickets if 'TICKET_VIEW' in req.perm(self.realm, t['id'])] tickets = map(lambda x: Ticket(self.env, x['id']), tickets) schedule_info = {'test': TicketScheduleSystem(self.env).get_schedule(tickets)} add_script(req, 'ticketrelation/js/bundle.js') add_stylesheet(req, 'ticketrelation/css/schedule.css') random_id = str(random.randint(0, 10000)) config = { 'url': req.base_url, 'startDate': kwargs.get('startdate', None), 'finishDate': kwargs.get('finishdate', None), 'showUnavailable': kwargs.get('showunavailable', 1) } return tag.div(tag.div( tag.schedule(**{':schedule': 'schedule', ':config': 'config'}), class_='schedule_container', id='schedule_container_' + random_id), tag.script(""" $(window).load(function() { var data = %s; var config = %s; var app = new window.Vue({ el: '#schedule_container_%s', data: { schedule: data, config: config, } }); });""" % (json.dumps(schedule_info, cls=DateTimeEncoder), json.dumps(config, cls=DateTimeEncoder), random_id)) )
def filter_stream(self, req, method, filename, stream, data): if filename in ('browser.html', 'dir_entries.html'): if 'path' not in data: # Probably an upstream error return stream # provide a link to the svn repository at the top of the Browse Source listing if self.env.is_component_enabled('contextmenu.contextmenu.SubversionLink'): content = SubversionLink(self.env).get_content(req, data['path'], stream, data) if content: stream |= Transformer('//div[@id="content"]/h1').after(content) # No dir entries; we're showing a file if not data['dir']: return stream # FIXME: The idx is only good for finding rows, not generating element ids. # Xhr rows are only using dir_entries.html, not browser.html. # The xhr-added rows' ids are added using js (see expand_dir.js) add_stylesheet(req, 'contextmenu/contextmenu.css') add_script(req, 'contextmenu/contextmenu.js') if 'up' in data['chrome']['links']: # Start appending stuff on 2nd tbody row when we have a parent dir link row_index = 2 # Remove colspan and insert an empty cell for checkbox column stream |= Transformer('//table[@id="dirlist"]//td[@colspan="5"]').attr('colspan', None).before(tag.td()) else: # First row = //tr[1] row_index = 1 for idx, entry in enumerate(data['dir']['entries']): menu = tag.div(tag.span(Markup('▾'), style='color: #bbb'), tag.div(class_='ctx-foldable', style='display:none'), id='ctx%s' % idx, class_='context-menu') for provider in sorted(self.context_menu_providers, key=lambda x: x.get_order(req)): content = provider.get_content(req, entry, stream, data) if content: menu.children[1].append(tag.div(content)) ## XHR rows don't have a tbody in the stream if data['xhr']: path_prefix = '' else: path_prefix = '//table[@id="dirlist"]//tbody' # Add the menu stream |= Transformer('%s//tr[%d]//td[@class="name"]' % (path_prefix, idx + row_index)).prepend(menu) if provider.get_draw_separator(req): menu.children[1].append(tag.div(class_='separator')) # Add td+checkbox cb = tag.td(tag.input(type='checkbox', id="cb%s" % idx, class_='fileselect')) stream |= Transformer('%s//tr[%d]//td[@class="name"]' % (path_prefix, idx + row_index)).before(cb) stream |= Transformer('//th[1]').before(tag.th()) return stream
def format(self, entries, label): div = tag.div(class_="references") div.append(tag.h1(id='references')(label)) count = 0 for key, value in entries: count = count + 1 sortkey = tag.span(class_="key") sortkey.append("[" + str(count) + "]") element = tag.div(class_=value["type"]) element.append(sortkey) element.append(self.format_entry(key, value)) div.append(element) return div
def format(self, entries, label): div = tag.div(class_="references") div.append(tag.h1(id="references")(label)) count = 0 for key, value in entries: count = count + 1 sortkey = tag.span(class_="key") sortkey.append("[" + str(count) + "]") element = tag.div(class_=value["type"]) element.append(sortkey) element.append(self.format_entry(key, value)) div.append(element) return div
def get_html(self, macroenv, req, content): def get_time(starttime, macroenv): ''' computes the computing time of the macro returned as HTML construct to be embeeded in HTML output ''' duration = (datetime.now() - starttime).microseconds / 1000 macroenv.tracenv.log.debug('macro computation time: %s ms: %s ' % (duration, macroenv.macrokw)) return (tag.span('It took %s ms to generate this visualization. ' % (duration, ), class_='ppstat')) #macroenv = PPEnv( env, req, content ) macrostart = datetime.now() if content == None: content = '' ts = ppFilter(macroenv).get_tickets() if macroenv.get_args('ppforcereload') == '1': noteForceReload = tag.span('The visualization was recreated.', class_='ppforcereloadinfo') else: noteForceReload = tag.span() renderer = ppRender(macroenv) # show text in the headline moretitle = '' macroenv.tracenv.log.debug( 'macroenv label=%s (%s)' % (macroenv.get_args('label'), macroenv.tracreq.args)) if macroenv.macrokw.get('label', None) != None: # use parameter: label moretitle = macroenv.macrokw.get('label', '') else: moretitle = renderer.getHeadline() # get the pre-defined headline return tag.div( tag.h5(tag.a(name=macroenv.macroid)('%s' % (moretitle, ))), renderer.render(ts), tag.div( tag.div( get_time(macrostart, macroenv), noteForceReload, tag.span( tag.a('Force recreation of the visualization.', href='?ppforcereload=1', class_='ppforcereload')))), style=macroenv.macrokw.get('style', '') # CSS style )
def process_request(self, req): """Redirect to pre-selected target.""" if self.redirect_target or self._check_redirect(req): target = self.redirect_target # Check for self-redirect: if target and target == req.href(req.path_info): message = tag.div('Please ', tag.a( "change the redirect target", href = target + "?action=edit" ), ' to another page.', class_ = "system-message") data = { 'title':"Page redirects to itself!", 'message':message, 'type':'TracError', } req.send_error(data['title'], status=409, env=self.env, data=data) raise RequestDone # Check for redirect pair, i.e. A->B, B->A if target and target == req.href.wiki(req.args.get('redirectedfrom','')): message = tag.div('Please change the redirect target from either ', tag.a( "this page", href = req.href(req.path_info, action="edit")), ' or ', tag.a( "the redirecting page", href = target + "?action=edit" ), '.', class_ = "system-message") data = { 'title':"Redirect target redirects back to this page!", 'message':message, 'type':'TracError', } req.send_error(data['title'], status=409, env=self.env, data=data) raise RequestDone # Add back link information for internal links: if target and target[0] == '/': redirectfrom = "redirectedfrom=" + req.path_info[6:] # anchor should be the last in url # according to http://trac.edgewall.org/ticket/8072 tgt, query, anchor= self.split_link(target) if not query: query = "?" + redirectfrom else: query += "&" + redirectfrom target = tgt + query + anchor req.redirect(target) raise RequestDone raise TracError("Invalid redirect target!")
def expand_macro(self, formatter, name, content, args): title = 'Color Gradient' classes = 'colorgradient'; if args and 'title' in args: title = args['title'] if args and 'class' in args: classes += ' ' + args['class'] colors = self._parse_arguments(content) lastcolor = {} tbody = [] for color in colors: if 'orig' in lastcolor: tbody.append(self._create_gradient(lastcolor, color)) tbody.append([ tag.td( style='background-color:' + color['orig'] )( tag.div(style='color: black')(color['hex']), tag.div(style='color: white')(color['hex']) ), tag.td( style='background-color:' + color['orig'] )( tag.div(style='color: black')(color['rgbp']), tag.div(style='color: white')(color['rgbp']) ) ]) lastcolor = color ## end for loop if len(tbody) > 0: table = tag.table(class_=classes) table()(tag.thead()(tag.th(colspan="2")(title))) table()(tag.tbody(class_='colorgradient')([tag.tr()(td) for td in tbody])) return table; else: return tag.div(class_='colorgradient')('Nothing to display')
def gentd(week_idx, day_info): day = day_info['date'] tt = day_info['milestones'] + day_info['tickets'] if len(tt) < 6: ttshow = tt ttall = [] else: ttshow = tt[:4] ttall = tt tdclass = [] if day == today: tdclass.append('today') if day.weekday() in (5, 6): tdclass.append('weekend') formatted_day = format_date(day, format='long', locale=locale) td = tag.td(class_=' '.join(tdclass), data_for_start_date=day.strftime(start_date_format), data_for_due_date=day.strftime(due_date_format), data_fdate=formatted_day) label = [] if day == today: label.append(tag.span(_("Today"), class_='today')) label.append( tag.span(unicode(day.day), class_=('day normal', 'day')[day == today])) td(tag.div(label)) if ttshow: td(tag.ul([genli(t) for t in ttshow])) if ttall: id = 'calendar-more-%s' % str(day) td( tag.a(_("%d more tickets...") % (len(ttall) - 4), href='#' + id, class_='show-all-list'), tag.div(tag.h4(formatted_day), tag.ul([genli(t) for t in ttall]), class_='ticketcalendar-popup-list', id=id, data_title=format_date(day, locale=locale, format='full'))) return td
def expand_macro(self, formatter, name, text, args): if not text: raw_actions = self.config.options('ticket-workflow') else: if args is None: text = '\n'.join([line.lstrip() for line in text.split(';')]) if '[ticket-workflow]' not in text: text = '[ticket-workflow]\n' + text parser = RawConfigParser() try: parser.readfp(StringIO(text)) except ParsingError as e: return system_message(_("Error parsing workflow."), unicode(e)) raw_actions = list(parser.items('ticket-workflow')) actions = parse_workflow_config(raw_actions) states = list(set( [state for action in actions.itervalues() for state in action['oldstates']] + [action['newstate'] for action in actions.itervalues()])) action_labels = [attrs['label'] for attrs in actions.values()] action_names = actions.keys() edges = [] for name, action in actions.items(): new_index = states.index(action['newstate']) name_index = action_names.index(name) for old_state in action['oldstates']: old_index = states.index(old_state) edges.append((old_index, new_index, name_index)) args = args or {} width = args.get('width', 800) height = args.get('height', 600) graph = {'nodes': states, 'actions': action_labels, 'edges': edges, 'width': width, 'height': height} graph_id = '%012x' % id(graph) req = formatter.req add_script(req, 'common/js/excanvas.js', ie_if='IE') add_script(req, 'common/js/workflow_graph.js') add_script_data(req, {'graph_%s' % graph_id: graph}) return tag( tag.div('', class_='trac-workflow-graph trac-noscript', id='trac-workflow-graph-%s' % graph_id, style="display:inline-block;width:%spx;height:%spx" % (width, height)), tag.noscript( tag.div(_("Enable JavaScript to display the workflow graph."), class_='system-message')))
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): from trac.mimeview.api import Mimeview mime_map = Mimeview(self.env).mime_map mime_type_filter = '' args, kw = parse_args(content) if args: mime_type_filter = args.pop(0).strip().rstrip('*') mime_types = {} for key, mime_type in mime_map.iteritems(): if (not mime_type_filter or mime_type.startswith(mime_type_filter)) and key != mime_type: mime_types.setdefault(mime_type, []).append(key) return tag.div(class_='mimetypes')( tag.table(class_='wiki')( tag.thead(tag.tr( tag.th(_("MIME Types")), # always use plural tag.th(tag.a("WikiProcessors", href=formatter.context.href.wiki( 'WikiProcessors'))))), tag.tbody( tag.tr(tag.th(tag.tt(mime_type), style="text-align: left"), tag.td(tag.code( ' '.join(sorted(mime_types[mime_type]))))) for mime_type in sorted(mime_types.keys()))))
def expand_macro(self, formatter, name, content): req = formatter.req stats_provider, kwargs, is_preview_with_self = self._parse_macro_content(content, req) if is_preview_with_self: # previewing newticket, without a number but with a reference # to current ticket number; show a helpful message return tag.div('Progress meter will be inserted here in final ticket') # Create & execute the query string qstr = '&'.join(['%s=%s' % item for item in kwargs.iteritems()]) query = Query.from_string(self.env, qstr, max=0) try: constraints = query.constraints[0] except IndexError: constraints = query.constraints # Calculate stats qres = query.execute(req) tickets = apply_ticket_permissions(self.env, req, qres) stats = get_ticket_stats(stats_provider, tickets) stats_data = query_stats_data(req, stats, constraints) # ... and finally display them add_stylesheet(req, 'common/css/roadmap.css') chrome = Chrome(self.env) return chrome.render_template(req, 'progressmeter.html', stats_data, fragment=True)
def filter_stream(self, req, method, filename, stream, data): if req.path_info.startswith('/ticket'): button = tag.div( tag.input(type="submit", title=_("Translate to %s") % req.locale.get_display_name(), value=_("Translate"), forward=_("Translate"), backward=_("Untranslate"), working=_("Working"), name="translate", class_="translate")) button(class_="inlinebuttons") script = tag.script('') script(src='https://www.google.com/jsapi?key=' + self.googleApiKey) script(type='text/javascript') stream |= Transformer('//head').prepend(script) stream |= Transformer( '//div[@id="content"]/div[@id="ticket"]/div[@class="description"]/h3' ).after(button) stream |= Transformer( '//div[@id="content"]/div/div[@id="changelog"]/div[@class="change"]/h3' ).after(button) add_stylesheet(req, 'translate/translate.css') add_script_data(req, {'googleApiKey': self.googleApiKey}) add_script_data(req, {'sessionLanguage': req.locale.language}) add_script(req, 'translate/translate.js') return stream
def get_html(self, total, horas_semanas): valor_hora = self.data['valor_hora'] text = ['Horas trabajadas: %.2f' % total, 'Precio en dolares (U$S%s): %.2f' % (valor_hora, total * valor_hora)] text.extend(['Horas semana %s: %.2f' % (nro+1, horas) for nro, horas in horas_semanas.items()]) div = tag.div() ul = tag.ul() for li in text: ul.append(tag.li(li)) if 'date' in self.data: link = tag.a('@netlandish: Grinch report', href=self._get_grinch_report_url()) ul.append(link) div.append(ul) img = tag.img(src=self._get_google_chart(horas_semanas)) div.append(img) ul = tag.ul() for project, hours in self.hours.iteritems(): ul.append(tag.li('{0}: {1}'.format(project.title(), hours))) div.append(ul) return div
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 expand_macro(self, formatter, name, content): min_depth, max_depth = 1, 6 title = None inline = 0 if content: argv = [arg.strip() for arg in content.split(',')] if len(argv) > 0: depth = argv[0] if '-' in depth: min_depth, max_depth = [int(d) for d in depth.split('-', 1)] else: min_depth = max_depth = int(depth) if len(argv) > 1: title = argv[1].strip() if len(argv) > 2: inline = argv[2].strip().lower() == 'inline' # TODO: - integrate the rest of the OutlineFormatter directly here # - use formatter.wikidom instead of formatter.source out = StringIO() oformatter = OutlineFormatter(self.env, formatter.context) oformatter.format(formatter.source, out, max_depth, min_depth, shorten=not inline) outline = Markup(out.getvalue()) if title: outline = tag.h4(title) + outline if not inline: outline = tag.div(outline, class_='wiki-toc') return outline
def filter_stream(self, req, method, filename, stream, data): # check preconditions if filename != 'ticket.html': return stream transformer = Transformer() # build 'Hide these fields' Area hide_names = req.session.get('hidefieldchanges', []) hide_fields = [] for field in data['fields']: name = field['name'] checkbox = name in hide_names \ and tag.input(type='checkbox', checked=True, name=name) \ or tag.input(type='checkbox', name=name) hide_fields.append(tag.label(checkbox, field['label'])) hide_fields.append(tag.br) hide_fields.append(tag.input(name='submit', type='submit', value='Hide these fields')) transformer = transformer \ .select('//div[@id="changelog"]') \ .before(tag.form(tag.input(value='hide changes', id='hidechangesbutton', type='button', style_='float: right;'), tag.div(hide_fields, style='display: none', id='hidefields'), action='#', class_='inlinebuttons hidechanges')).end() # build 'show all changes' button # showallbutton = tag.input(value='show all', name='showall', class_='showallbutton', type='submit', style_='float: right;') # showallbutton = tag.form(showallbutton, action='#', method='get', class_='inlinebuttons hidechanges') # transformer = transformer.select('//div[@id="changelog"]').before(showallbutton).end() # build 'hide customfield' buttons hidebutton = tag.input(value='hide', name="hide", class_='hidebutton', style_='display: none', type='submit') hidebutton = tag.form(hidebutton, action='#', method='get', class_='inlinebuttons hidefieldchanges') transformer = transformer \ .select('//div[@id="changelog"]/div[@class="change"]/ul[@class="changes"]/li') \ .prepend(hidebutton).end() # return filtered stream return stream | transformer
def _clone_form(self, req, ticket, data): fields = {} for f in data.get('fields', []): name = f['name'] if name == 'summary': fields['summary'] = _("%(summary)s (cloned)", summary=ticket['summary']) elif name == 'description': fields['description'] = \ _("Cloned from #%(id)s:\n----\n%(description)s", id=ticket.id, description=ticket['description']) else: fields[name] = ticket[name] return tag.form(tag.div(tag.input( type="submit", name="clone", value=captioned_button(req, '+#', _("Clone")), title=_("Create a copy of this ticket")), [ tag.input(type="hidden", name='field_' + n, value=v) for n, v in fields.iteritems() ], tag.input(type="hidden", name='preview', value=''), class_="inlinebuttons"), method="post", action=req.href.newticket())
def expand_macro(self, formatter, name, args): curpage = formatter.resource.id # scoped TOC (e.g. TranslateRu/Guide or 0.X/Guide ...) prefix = '' guideprefix = GUIDE_NAME + '/' data = { 'guide': GUIDE_NAME, } idx = curpage.find('/') if idx > 0: prefix = curpage[:idx + 1] if prefix.endswith(guideprefix): prefix = prefix[:len(prefix) - len(guideprefix)] ws = WikiSystem(self.env) return tag.div( tag.h4(_('Table of Contents')), tag.ul([ tag.li(tag.a(title, href=formatter.href.wiki(prefix + ref % data), class_=(not ws.has_page(prefix + ref % data) and 'missing')), class_=(prefix + ref % data == curpage and 'active')) for ref, title in self.TOC ]), class_='wiki-toc')
def _process_edit(self, req, stream, method, tags): stage = 1 elm = tag.div([ tag.label('Tag under: (', tag.a('view all tags', href=req.href.tags()), ')', for_='tags'), tag.br(), tag.input(title='Comma separated list of tags', type='text', id='tags', size='30', name='tags', value=', '.join(tags)), ], class_='field') for kind, data, pos in stream: yield kind, data, pos if stage == 1 and \ kind is START and \ data[0].localname == 'input' and \ data[1].get('id') == 'comment': stage = 2 elif stage == 2 and \ kind is END and \ data.localname == 'div': for e in elm.generate(): yield e stage = None
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, formatter, cols, name_pat, size, header, limit): #noinspection PyArgumentList icon = Icons(self.env) icon_dir = icon.icon_location(size)[1] files = fnmatch.filter(os.listdir(icon_dir), '%s.png' % name_pat) icon_names = [os.path.splitext(p)[0] for p in files] if limit: displayed_icon_names = reduce_names(icon_names, limit) else: displayed_icon_names = icon_names icon_table = render_table(displayed_icon_names, cols, lambda name: icon._render_icon(formatter, name, size)) if not len(icon_names): message = 'No %s icon matches %s' % (SIZE_DESCR[size], name_pat) elif len(icon_names) == 1: message = 'Showing the only %s icon matching %s' % \ (SIZE_DESCR[size], name_pat) elif len(displayed_icon_names) == len(icon_names): message = 'Showing all %d %s icons matching %s' % \ (len(icon_names), SIZE_DESCR[size], name_pat) else: message = 'Showing %d of %d %s icons matching %s' % \ (len(displayed_icon_names), len(icon_names), SIZE_DESCR[size], name_pat) return tag.div(tag.p(tag.small(message)) if header else '', icon_table)
def expand_macro(self, formatter, name, content): add_stylesheet(formatter.req, 'notebox/css/notebox.css') args, kwargs = parse_args(content) width = len(args) > 2 and args[2] or '70%' return tag.div(format_to_html(self.env, formatter.context, args[1]), class_='notebox-%s' % (args[0],), style='width: %s' % (width,))
def expand_macro(self, formatter, name, arguments): self.mc.options(arguments) extras = self.mc.extras() extra = '' if 'extra' in extras: extra = extras['extra'] return tag.div( tag.h3('[[%s(%s)]]' % ( name, arguments )), tag.table( tag.tr( tag.th('Name'), tag.th('Value'), tag.th('Qualified'), tag.th('Default?'), tag.th('Macroarg?'), tag.th('Extra?'), tag.th('Known?'), tag.th('Default'), tag.th('Documentation') ), self._show_option('text', self.mo_text, TracMacroConfigExample.mo_text), self._show_option('bool', self.mo_bool, TracMacroConfigExample.mo_bool), self._show_option('int', self.mo_int, TracMacroConfigExample.mo_int), self._show_option('list', self.mo_list, TracMacroConfigExample.mo_list), self._show_option('nodtext', self.mo_nodtext, TracMacroConfigExample.mo_nodtext), self._show_option('nodbool', self.mo_nodbool, TracMacroConfigExample.mo_nodbool), self._show_option('nodint', self.mo_nodint, TracMacroConfigExample.mo_nodint), self._show_option('nodlist', self.mo_nodlist, TracMacroConfigExample.mo_nodlist), self._show_extra('extra', extra), border=1, cellpadding=1, cellspacing=0 ) )
def _format_reminder(self, req, ticket, id, time, author, origin, description, delete_button=True): now = to_datetime(None) time = to_datetime(time) if now >= time: when = tag(tag.strong("Right now"), " (pending)") else: when = tag("In ", tag.strong(pretty_timedelta(time)), " (", format_date(time), ")") if description: context = Context.from_request(req, ticket.resource) desc = tag.div(format_to_oneliner(self.env, context, description), class_="description") else: desc = tag() return tag( self._reminder_delete_form(req, id) if delete_button else None, when, " - added by ", tag.em(Chrome(self.env).authorinfo(req, author)), " ", tag.span(pretty_timedelta(origin), title=format_datetime( origin, req.session.get('datefmt', 'iso8601'), req.tz)), " ago.", desc)
def expand_macro(self, formatter, name, args): from trac.config import Option section_filter = key_filter = '' args, kw = parse_args(args) if args: section_filter = args.pop(0).strip() if args: key_filter = args.pop(0).strip() registry = Option.get_registry(self.compmgr) sections = {} for (section, key), option in registry.iteritems(): if section.startswith(section_filter): sections.setdefault(section, {})[key] = option return tag.div(class_='tracini')( (tag.h3(tag.code('[%s]' % section), id='%s-section' % section), tag.table(class_='wiki')( tag.tbody(tag.tr(tag.td(tag.tt(option.name)), tag.td(format_to_oneliner( self.env, formatter.context, to_unicode(option.__doc__)))) for option in sorted(sections[section].itervalues(), key=lambda o: o.name) if option.name.startswith(key_filter)))) for section in sorted(sections))
def filter_stream(self, req, method, filename, stream, data): notice = self.get_notice() if notice: stream |= Transformer(self.insert_after).after(tag.div(notice, id="project-notice")) return stream
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. """ # move these someplace sensible? form_id = "acctmgr_registerform" # id of the registration form msg = "Please enter the text below to prove you're not a machine." if filename == "register.html": word = random_word(self.dict_file) req.session['captcha'] = word req.session.save() if self.captcha_type == 'png': captcha = '<img src="%s"/>' % req.href('captcha.png') else: captcha = skimpyAPI.Pre(word).data() content = "<p>%s</p><p>%s</p>" % (msg, captcha) content += '<label>Confirm: <input type="text" name="captcha" class="textwidget" size="20"/></label>' stream |= Transformer('//form[@id="%s"]/fieldset[1]' % form_id).append(tag.div(Markup(content))) return stream
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 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 expand_macro(self, formatter, name, content): from trac.mimeview.api import Mimeview mime_map = Mimeview(self.env).mime_map mime_type_filter = '' args, kw = parse_args(content) if args: mime_type_filter = args.pop(0).strip().rstrip('*') mime_types = {} for key, mime_type in mime_map.iteritems(): if (not mime_type_filter or mime_type.startswith(mime_type_filter)) and key != mime_type: mime_types.setdefault(mime_type, []).append(key) return tag.div(class_='mimetypes')( tag.table(class_='wiki')( tag.thead(tag.tr( tag.th(_("MIME Types")), # always use plural tag.th(tag.a("WikiProcessors", href=formatter.context.href.wiki( 'WikiProcessors'))))), tag.tbody( tag.tr(tag.th(tag.code(mime_type), style="text-align: left"), tag.td(tag.code( ' '.join(sorted(mime_types[mime_type]))))) for mime_type in sorted(mime_types.keys()))))
def filter_stream(self, req, method, filename, stream, data): # Add delete buttons to the ticket form ticket = data.get('ticket') if filename == 'ticket.html' and 'TICKET_ADMIN' in req.perm(ticket.resource): # Add Delete button to ticket description if data['ticket'].values['description']: # Reply button and associated elements are present filter = Transformer("//div[@class='description']//div[@class='inlinebuttons']") stream |= filter.append(tag.input(type='submit', name='delete', title="Delete this ticket", value='Delete')) else: # Reply button and associated elements not present filter = Transformer("//div[@class='description']/h3") stream |= filter.after( \ tag.form(tag.div(tag.input(type='submit', name='delete', title="Delete this ticket", value='Delete'), class_='inlinebuttons' ), name='addreply', method='get', action='#comment') ) # Add Delete buttons to ticket comments stream |= Transformer("//div[@id='changelog']//div[@class='inlinebuttons']") \ .append(tag.input(type='submit', name='delete', title="Delete this comment", value='Delete')) return stream
def embed_player(self, formatter, url, query, style): query_dict = xform_query(query) set_default_parameters( query_dict, _EMBED_FLOWPLAYER_DEFAULT_PARAMETERS ) player_id = self._generate_player_id() swf = pathjoin(formatter.href.chrome(), EMBED_PATH_FLOWPLAYER['swf']) style.pop('width') # use adaptiveRatio for player-size style.pop('height') # use adaptiveRatio for player-size attrs = { 'id': player_id, 'data-swf': swf, 'style': xform_style(style), } return tag.div( tag.video([ tag.source(type=mimetypes.guess_type(url)[0], src=url), tag.script(""" $(function() { $('#%s').flowplayer(%s); }); """ % (player_id, to_json(query_dict)) ), ]), **attrs )
def _render(self, formatter, cols, name_pat, size, header, limit): #noinspection PyArgumentList icon = Icons(self.env) icon_dir = icon.icon_location(size)[1] files = fnmatch.filter(os.listdir(icon_dir), name_pat + '.png') icon_names = [os.path.splitext(p)[0] for p in files] if limit: displayed_icon_names = reduce_names(icon_names, limit) else: displayed_icon_names = icon_names icon_table = render_table(displayed_icon_names, cols, lambda name: icon._render_icon(formatter, name, size)) if not len(icon_names): message = 'No %s icon matches %s' % (SIZE_DESCR[size], name_pat) elif len(icon_names) == 1: message = 'Showing the only %s icon matching %s' % \ (SIZE_DESCR[size], name_pat) elif len(displayed_icon_names) == len(icon_names): message = 'Showing all %d %s icons matching %s' % \ (len(icon_names), SIZE_DESCR[size], name_pat) else: message = 'Showing %d of %d %s icons matching %s' % \ (len(displayed_icon_names), len(icon_names), SIZE_DESCR[size], name_pat) return tag.div(tag.p(tag.small(message)) if header else '', icon_table)