def expand_macro(self, formatter, name, content): intertracs = {} for key, value in self.intertrac_section.options(): idx = key.rfind('.') if idx > 0: # 0 itself doesn't help much: .xxx = ... prefix, attribute = key[:idx], key[idx+1:] intertrac = intertracs.setdefault(prefix, {}) intertrac[attribute] = value else: intertracs[key] = value # alias if 'trac' not in intertracs: intertracs['trac'] = {'title': _('The Trac Project'), 'url': 'http://trac.edgewall.org'} def generate_prefix(prefix): intertrac = intertracs[prefix] if isinstance(intertrac, basestring): yield tag.tr(tag.td(tag.strong(prefix)), tag.td(tag_("Alias for %(name)s", name=tag.strong(intertrac)))) else: url = intertrac.get('url', '') if url: title = intertrac.get('title', url) yield tag.tr(tag.td(tag.a(tag.strong(prefix), href=url + '/timeline')), tag.td(tag.a(title, href=url))) return tag.table(class_="wiki intertrac")( tag.tr(tag.th(tag.em(_("Prefix"))), tag.th(tag.em(_("Trac Site")))), [generate_prefix(p) for p in sorted(intertracs)])
def getbool(self, name, default=None): """Return the value as a boolean. Raise an `HTTPBadRequest` exception if an exception occurs while converting the value to a boolean. :param name: the name of the request parameter :keyword default: the value to return if the parameter is not specified. :since: 1.2 """ if name not in self: return default value = self[name] if isinstance(value, list): raise HTTPBadRequest( tag_("Invalid value for request argument " "%(name)s.", name=tag.em(name))) value = as_bool(value, None) if value is None: raise HTTPBadRequest( tag_("Invalid value for request argument " "%(name)s.", name=tag.em(name))) return value
def render_timeline_event(self, context, field, event): attachment, descr = event[3] if field == 'url': return self.get_resource_url(attachment, context.href) elif field == 'title': name = get_resource_name(self.env, attachment.parent) title = get_resource_summary(self.env, attachment.parent) return tag_("%(attachment)s attached to %(resource)s", attachment=tag.em(os.path.basename(attachment.id)), resource=tag.em(name, title=title)) elif field == 'description': return format_to(self.env, None, context.child(attachment.parent), descr)
def expand_macro(self, formatter, name, content): interwikis = [] for k in sorted(self.keys()): prefix, url, title = self[k] interwikis.append({ 'prefix': prefix, 'url': url, 'title': title, 'rc_url': self._expand_or_append(url, ['RecentChanges']), 'description': url if title == prefix else title}) return tag.table(tag.tr(tag.th(tag.em(_("Prefix"))), tag.th(tag.em(_("Site")))), [tag.tr(tag.td(tag.a(w['prefix'], href=w['rc_url'])), tag.td(tag.a(w['description'], href=w['url']))) for w in interwikis ], class_="wiki interwiki")
def _check_quickjump(self, req, noquickjump, kwd): """Look for search shortcuts""" # Source quickjump FIXME: delegate to ISearchSource.search_quickjump quickjump_href = None if kwd[0] == '/': quickjump_href = req.href.browser(kwd) name = kwd description = _('Browse repository path %(path)s', path=kwd) else: context = web_context(req, 'search') link = find_element(extract_link(self.env, context, kwd), 'href') if link is not None: quickjump_href = link.attrib.get('href') name = link.children description = link.attrib.get('title', '') if quickjump_href: # Only automatically redirect to local quickjump links if not quickjump_href.startswith(req.base_path or '/'): noquickjump = True if noquickjump: return {'href': quickjump_href, 'name': tag.em(name), 'description': description} else: help_url = req.href.wiki('TracSearch') + '#Quicksearches' search_url = req.href.search(q=kwd, noquickjump=1) # FIXME: use tag_ add_notice(req, Markup(_( 'You arrived here through the <a href="%(help_url)s">' 'quick-jump</a> search feature. To instead search for the ' 'term <strong>%(term)s</strong>, click <a ' 'href="%(search_url)s">here</a>.', help_url=escape(help_url), term=escape(kwd), search_url=escape(search_url)))) req.redirect(quickjump_href)
def render_timeline_event(self, context, field, event): milestone, description = event[3] if field == 'url': return context.href.milestone(milestone.id) elif field == 'title': return tag_("Milestone %(name)s completed", name=tag.em(milestone.id)) elif field == 'description': child_resource = context.child(resource=milestone) return format_to(self.env, None, child_resource, description)
def render_timeline_event(self, context, field, event): bp_resource, bp, bc = event[3] if bc: # A blog comment if field == 'url': return context.href.blog(bp.name) + '#comment-%d' % bc.number elif field == 'title': return tag('Blog: ', tag.em(bp.title), ' comment added') elif field == 'description': return format_to_oneliner( self.env, context(resource=bp_resource), bc.comment) else: # A blog post if field == 'url': return context.href.blog(bp.name) elif field == 'title': return tag('Blog: ', tag.em(bp.title), bp.version > 1 and ' edited' or ' created') elif field == 'description': return format_to_oneliner( self.env, context(resource=bp_resource), bp.version_comment)
def require(self, name): """Raise an `HTTPBadRequest` exception if the parameter is not in the request. :param name: the name of the request parameter :since: 1.2 """ if name not in self: raise HTTPBadRequest( tag_("Missing request argument. The %(name)s argument " "must be included in the request.", name=tag.em(name)))
def _render_source(self, context, lines, 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(lines, unicode): lines = lines.splitlines(True) # elif isinstance(lines, list): # pass # assume these are lines already 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(lines): 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 expand_macro(self, formatter, name, content): from trac.wiki.formatter import system_message content = content.strip() if content else '' name_filter = content.strip('*') def get_macro_descr(): for macro_provider in formatter.wiki.macro_providers: names = list(macro_provider.get_macros() or []) if name_filter and not any( name.startswith(name_filter) for name in names): continue try: name_descriptions = [ (name, macro_provider.get_macro_description(name)) for name in names ] except Exception as e: yield system_message( _("Error: Can't get description for macro %(name)s", name=names[0]), e), names else: for descr, pairs in groupby(name_descriptions, key=lambda p: p[1]): if descr: if isinstance(descr, (tuple, list)): descr = dgettext(descr[0], to_unicode(descr[1])) \ if descr[1] else '' else: descr = to_unicode(descr) or '' if content == '*': descr = format_to_oneliner(self.env, formatter.context, descr, shorten=True) else: descr = format_to_html(self.env, formatter.context, descr) yield descr, [name for name, descr in pairs] return tag.div(class_='trac-macrolist')( (tag.h3(tag.code('[[', names[0], ']]'), id='%s-macro' % names[0]), len(names) > 1 and tag.p( tag.strong(_("Aliases:")), [tag.code(' [[', alias, ']]') for alias in names[1:]]) or None, description or tag.em(_("Sorry, no documentation found"))) for description, names in sorted(get_macro_descr(), key=lambda item: item[1][0]))
def render_timeline_event(self, context, field, event): wiki_page, comment = event[3] if field == 'url': return context.href.wiki(wiki_page.id, version=wiki_page.version) elif field == 'title': name = tag.em(get_resource_name(self.env, wiki_page)) if wiki_page.version > 1: return tag_("%(page)s edited", page=name) else: return tag_("%(page)s created", page=name) elif field == 'description': markup = format_to(self.env, None, context.child(resource=wiki_page), comment) if wiki_page.version > 1: diff_href = context.href.wiki( wiki_page.id, version=wiki_page.version, action='diff') markup = tag(markup, " (", tag.a(_("diff"), href=diff_href), ")") return markup
def getint(self, name, default=None, min=None, max=None): """Return the value as an integer. Raise an `HTTPBadRequest` exception if an exception occurs while converting the value to an integer. :param name: the name of the request parameter :keyword default: the value to return if the parameter is not specified :keyword min: lower bound to which the value is limited :keyword max: upper bound to which the value is limited :since: 1.2 """ if name not in self: return default value = as_int(self[name], None, min, max) if value is None: raise HTTPBadRequest(tag_("Invalid value for request argument " "%(name)s.", name=tag.em(name))) return value
def render_property_diff(self, name, old_context, old_props, new_context, new_props, options): # Build 5 columns table showing modifications on merge sources # || source || added || removed || added (ni) || removed (ni) || # || source || removed || rm = RepositoryManager(self.env) repos = rm.get_repository(old_context.resource.parent.id) def parse_sources(props): sources = {} value = props[name] lines = value.splitlines() if name == 'svn:mergeinfo' \ else value.split() for line in lines: path, revs = line.split(':', 1) spath = _path_within_scope(repos.scope, path) if spath is not None: inheritable, non_inheritable = _partition_inheritable(revs) sources[spath] = (set(Ranges(inheritable)), set(Ranges(non_inheritable))) return sources old_sources = parse_sources(old_props) new_sources = parse_sources(new_props) # Go through new sources, detect modified ones or added ones blocked = name.endswith('blocked') added_label = [_("merged: "), _("blocked: ")][blocked] removed_label = [_("reverse-merged: "), _("un-blocked: ")][blocked] added_ni_label = _("marked as non-inheritable: ") removed_ni_label = _("unmarked as non-inheritable: ") sources = [] changed_revs = {} changed_nodes = [] for spath, (new_revs, new_revs_ni) in new_sources.iteritems(): new_spath = spath not in old_sources if new_spath: old_revs = old_revs_ni = set() else: old_revs, old_revs_ni = old_sources.pop(spath) added = new_revs - old_revs removed = old_revs - new_revs # unless new revisions differ from old revisions if not added and not removed: continue added_ni = new_revs_ni - old_revs_ni removed_ni = old_revs_ni - new_revs_ni revs = sorted(added | removed | added_ni | removed_ni) try: node = repos.get_node(spath, revs[-1]) changed_nodes.append((node, revs[0])) except NoSuchNode: pass sources.append( (spath, new_spath, added, removed, added_ni, removed_ni)) if changed_nodes: changed_revs = repos._get_changed_revs(changed_nodes) def revs_link(revs, context): if revs: revs = to_ranges(revs) return _get_revs_link(revs.replace(',', u',\u200b'), context, spath, revs) modified_sources = [] for spath, new_spath, added, removed, added_ni, removed_ni in sources: if spath in changed_revs: revs = set(changed_revs[spath]) added &= revs removed &= revs added_ni &= revs removed_ni &= revs if added or removed: if new_spath: status = _(" (added)") else: status = None modified_sources.append( (spath, [_get_source_link(spath, new_context), status], added and tag(added_label, revs_link(added, new_context)), removed and tag(removed_label, revs_link(removed, old_context)), added_ni and tag(added_ni_label, revs_link(added_ni, new_context)), removed_ni and tag(removed_ni_label, revs_link(removed_ni, old_context)))) # Go through remaining old sources, those were deleted removed_sources = [] for spath, old_revs in old_sources.iteritems(): removed_sources.append( (spath, _get_source_link(spath, old_context))) if modified_sources or removed_sources: modified_sources.sort() removed_sources.sort() changes = tag.table(tag.tbody([ tag.tr(tag.td(c) for c in cols[1:]) for cols in modified_sources ], [ tag.tr(tag.td(src), tag.td(_('removed'), colspan=4)) for spath, src in removed_sources ]), class_='props') else: changes = tag.em(_(' (with no actual effect on merging)')) return tag.li(tag_('Property %(prop)s changed', prop=tag.strong(name)), changes)
def test_str(self): self.assertEqual(b'<b>M<em>ess\xc3\xa4ge</em></b>', str(tag.b('M', tag.em('essäge'))))
def test_unicode(self): self.assertEqual('<b>M<em>essäge</em></b>', unicode(tag.b('M', tag.em('essäge'))))