mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user.
- ref: #5586
This commit is contained in:
parent
8e01135d04
commit
e1a5fb601d
7 changed files with 63 additions and 20 deletions
|
|
@ -25,6 +25,10 @@ def includeme(config):
|
|||
name='hovercard_user',
|
||||
pattern='/_hovercard/user/{user_id}')
|
||||
|
||||
config.add_route(
|
||||
name='hovercard_username',
|
||||
pattern='/_hovercard/username/{username}')
|
||||
|
||||
config.add_route(
|
||||
name='hovercard_user_group',
|
||||
pattern='/_hovercard/user_group/{user_group_id}')
|
||||
|
|
|
|||
|
|
@ -63,6 +63,19 @@ class HoverCardsView(BaseAppView):
|
|||
c.user = User.get_or_404(user_id)
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@view_config(
|
||||
route_name='hovercard_username', request_method='GET', xhr=True,
|
||||
renderer='rhodecode:templates/hovercards/hovercard_user.mako')
|
||||
def hovercard_username(self):
|
||||
c = self.load_default_context()
|
||||
username = self.request.matchdict['username']
|
||||
c.user = User.get_by_username(username)
|
||||
if not c.user:
|
||||
raise HTTPNotFound()
|
||||
|
||||
return self._get_template_context(c)
|
||||
|
||||
@LoginRequired()
|
||||
@view_config(
|
||||
route_name='hovercard_user_group', request_method='GET', xhr=True,
|
||||
|
|
|
|||
|
|
@ -66,11 +66,12 @@ markdown_tags = [
|
|||
markdown_attrs = {
|
||||
"*": ["class", "style", "align"],
|
||||
"img": ["src", "alt", "title"],
|
||||
"a": ["href", "alt", "title", "name"],
|
||||
"a": ["href", "alt", "title", "name", "data-hovercard-alt", "data-hovercard-url"],
|
||||
"abbr": ["title"],
|
||||
"acronym": ["title"],
|
||||
"pre": ["lang"],
|
||||
"input": ["type", "disabled", "checked"]
|
||||
"input": ["type", "disabled", "checked"],
|
||||
"strong": ["title", "data-hovercard-alt", "data-hovercard-url"],
|
||||
}
|
||||
|
||||
standard_styles = [
|
||||
|
|
|
|||
|
|
@ -47,6 +47,14 @@ log = logging.getLogger(__name__)
|
|||
# default renderer used to generate automated comments
|
||||
DEFAULT_COMMENTS_RENDERER = 'rst'
|
||||
|
||||
try:
|
||||
from lxml.html import fromstring
|
||||
from lxml.html import tostring
|
||||
except ImportError:
|
||||
log.exception('Failed to import lxml')
|
||||
fromstring = None
|
||||
tostring = None
|
||||
|
||||
|
||||
class CustomHTMLTranslator(writers.html4css1.HTMLTranslator):
|
||||
"""
|
||||
|
|
@ -81,11 +89,7 @@ def relative_links(html_source, server_paths):
|
|||
if not html_source:
|
||||
return html_source
|
||||
|
||||
try:
|
||||
from lxml.html import fromstring
|
||||
from lxml.html import tostring
|
||||
except ImportError:
|
||||
log.exception('Failed to import lxml')
|
||||
if not fromstring and tostring:
|
||||
return html_source
|
||||
|
||||
try:
|
||||
|
|
@ -210,6 +214,8 @@ class MarkupRenderer(object):
|
|||
URL_PAT = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'
|
||||
r'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
|
||||
|
||||
MENTION_PAT = re.compile(MENTIONS_REGEX)
|
||||
|
||||
extensions = ['markdown.extensions.codehilite', 'markdown.extensions.extra',
|
||||
'markdown.extensions.def_list', 'markdown.extensions.sane_lists']
|
||||
|
||||
|
|
@ -347,6 +353,26 @@ class MarkupRenderer(object):
|
|||
|
||||
return cls.URL_PAT.sub(url_func, text)
|
||||
|
||||
@classmethod
|
||||
def convert_mentions(cls, text, mode):
|
||||
mention_pat = cls.MENTION_PAT
|
||||
|
||||
def wrapp(match_obj):
|
||||
uname = match_obj.groups()[0]
|
||||
hovercard_url = "pyroutes.url('hovercard_username', {'username': '%s'});" % uname
|
||||
|
||||
if mode == 'markdown':
|
||||
tmpl = '<strong class="tooltip-hovercard" data-hovercard-alt="{uname}" data-hovercard-url="{hovercard_url}">@{uname}</strong>'
|
||||
elif mode == 'rst':
|
||||
tmpl = ' **@{uname}** '
|
||||
else:
|
||||
raise ValueError('mode must be rst or markdown')
|
||||
|
||||
return tmpl.format(**{'uname': uname,
|
||||
'hovercard_url': hovercard_url})
|
||||
|
||||
return mention_pat.sub(wrapp, text).strip()
|
||||
|
||||
@classmethod
|
||||
def plain(cls, source, universal_newline=True, leading_newline=True):
|
||||
source = safe_unicode(source)
|
||||
|
|
@ -378,12 +404,7 @@ class MarkupRenderer(object):
|
|||
cls.extensions, cls.output_format)
|
||||
|
||||
if mentions:
|
||||
mention_pat = re.compile(MENTIONS_REGEX)
|
||||
|
||||
def wrapp(match_obj):
|
||||
uname = match_obj.groups()[0]
|
||||
return ' **@%(uname)s** ' % {'uname': uname}
|
||||
mention_hl = mention_pat.sub(wrapp, source).strip()
|
||||
mention_hl = cls.convert_mentions(source, mode='markdown')
|
||||
# we extracted mentions render with this using Mentions false
|
||||
return cls.markdown(mention_hl, safe=safe, flavored=flavored,
|
||||
mentions=False)
|
||||
|
|
@ -409,12 +430,7 @@ class MarkupRenderer(object):
|
|||
@classmethod
|
||||
def rst(cls, source, safe=True, mentions=False, clean_html=False):
|
||||
if mentions:
|
||||
mention_pat = re.compile(MENTIONS_REGEX)
|
||||
|
||||
def wrapp(match_obj):
|
||||
uname = match_obj.groups()[0]
|
||||
return ' **@%(uname)s** ' % {'uname': uname}
|
||||
mention_hl = mention_pat.sub(wrapp, source).strip()
|
||||
mention_hl = cls.convert_mentions(source, mode='rst')
|
||||
# we extracted mentions render with this using Mentions false
|
||||
return cls.rst(mention_hl, safe=safe, mentions=False)
|
||||
|
||||
|
|
@ -443,7 +459,7 @@ class MarkupRenderer(object):
|
|||
except Exception:
|
||||
log.exception('Error when rendering RST')
|
||||
if safe:
|
||||
log.debug('Fallbacking to render in plain mode')
|
||||
log.debug('Fallback to render in plain mode')
|
||||
return cls.plain(source)
|
||||
else:
|
||||
raise
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ body {
|
|||
border-left: @border-thickness solid @border-default-color;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input + .action-link, .action-link.first{
|
||||
border-left: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ function registerRCRoutes() {
|
|||
pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
|
||||
pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
|
||||
pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
|
||||
pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
|
||||
pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
|
||||
pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
|
||||
pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
|
||||
|
|
|
|||
|
|
@ -299,6 +299,10 @@ var tooltipActivate = function () {
|
|||
var altHovercard =$origin.data('hovercardAlt');
|
||||
|
||||
if (hovercardUrl !== undefined && hovercardUrl !== "") {
|
||||
if (hovercardUrl.substr(0,12) === 'pyroutes.url'){
|
||||
hovercardUrl = eval(hovercardUrl)
|
||||
}
|
||||
|
||||
var loaded = loadHoverCard(hovercardUrl, altHovercard, function (data) {
|
||||
instance.content(data);
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue