##// END OF EJS Templates
mentions: markdown renderer now wraps username in hovercard logic allowing checking the mentioned user....
marcink -
r4221:654aa611 stable
parent child Browse files
Show More
@@ -26,6 +26,10 b' def includeme(config):'
26 pattern='/_hovercard/user/{user_id}')
26 pattern='/_hovercard/user/{user_id}')
27
27
28 config.add_route(
28 config.add_route(
29 name='hovercard_username',
30 pattern='/_hovercard/username/{username}')
31
32 config.add_route(
29 name='hovercard_user_group',
33 name='hovercard_user_group',
30 pattern='/_hovercard/user_group/{user_group_id}')
34 pattern='/_hovercard/user_group/{user_group_id}')
31
35
@@ -65,6 +65,19 b' class HoverCardsView(BaseAppView):'
65
65
66 @LoginRequired()
66 @LoginRequired()
67 @view_config(
67 @view_config(
68 route_name='hovercard_username', request_method='GET', xhr=True,
69 renderer='rhodecode:templates/hovercards/hovercard_user.mako')
70 def hovercard_username(self):
71 c = self.load_default_context()
72 username = self.request.matchdict['username']
73 c.user = User.get_by_username(username)
74 if not c.user:
75 raise HTTPNotFound()
76
77 return self._get_template_context(c)
78
79 @LoginRequired()
80 @view_config(
68 route_name='hovercard_user_group', request_method='GET', xhr=True,
81 route_name='hovercard_user_group', request_method='GET', xhr=True,
69 renderer='rhodecode:templates/hovercards/hovercard_user_group.mako')
82 renderer='rhodecode:templates/hovercards/hovercard_user_group.mako')
70 def hovercard_user_group(self):
83 def hovercard_user_group(self):
@@ -66,11 +66,12 b' markdown_tags = ['
66 markdown_attrs = {
66 markdown_attrs = {
67 "*": ["class", "style", "align"],
67 "*": ["class", "style", "align"],
68 "img": ["src", "alt", "title"],
68 "img": ["src", "alt", "title"],
69 "a": ["href", "alt", "title", "name"],
69 "a": ["href", "alt", "title", "name", "data-hovercard-alt", "data-hovercard-url"],
70 "abbr": ["title"],
70 "abbr": ["title"],
71 "acronym": ["title"],
71 "acronym": ["title"],
72 "pre": ["lang"],
72 "pre": ["lang"],
73 "input": ["type", "disabled", "checked"]
73 "input": ["type", "disabled", "checked"],
74 "strong": ["title", "data-hovercard-alt", "data-hovercard-url"],
74 }
75 }
75
76
76 standard_styles = [
77 standard_styles = [
@@ -47,6 +47,14 b' log = logging.getLogger(__name__)'
47 # default renderer used to generate automated comments
47 # default renderer used to generate automated comments
48 DEFAULT_COMMENTS_RENDERER = 'rst'
48 DEFAULT_COMMENTS_RENDERER = 'rst'
49
49
50 try:
51 from lxml.html import fromstring
52 from lxml.html import tostring
53 except ImportError:
54 log.exception('Failed to import lxml')
55 fromstring = None
56 tostring = None
57
50
58
51 class CustomHTMLTranslator(writers.html4css1.HTMLTranslator):
59 class CustomHTMLTranslator(writers.html4css1.HTMLTranslator):
52 """
60 """
@@ -81,11 +89,7 b' def relative_links(html_source, server_p'
81 if not html_source:
89 if not html_source:
82 return html_source
90 return html_source
83
91
84 try:
92 if not fromstring and tostring:
85 from lxml.html import fromstring
86 from lxml.html import tostring
87 except ImportError:
88 log.exception('Failed to import lxml')
89 return html_source
93 return html_source
90
94
91 try:
95 try:
@@ -210,6 +214,8 b' class MarkupRenderer(object):'
210 URL_PAT = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'
214 URL_PAT = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'
211 r'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
215 r'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
212
216
217 MENTION_PAT = re.compile(MENTIONS_REGEX)
218
213 extensions = ['markdown.extensions.codehilite', 'markdown.extensions.extra',
219 extensions = ['markdown.extensions.codehilite', 'markdown.extensions.extra',
214 'markdown.extensions.def_list', 'markdown.extensions.sane_lists']
220 'markdown.extensions.def_list', 'markdown.extensions.sane_lists']
215
221
@@ -348,6 +354,26 b' class MarkupRenderer(object):'
348 return cls.URL_PAT.sub(url_func, text)
354 return cls.URL_PAT.sub(url_func, text)
349
355
350 @classmethod
356 @classmethod
357 def convert_mentions(cls, text, mode):
358 mention_pat = cls.MENTION_PAT
359
360 def wrapp(match_obj):
361 uname = match_obj.groups()[0]
362 hovercard_url = "pyroutes.url('hovercard_username', {'username': '%s'});" % uname
363
364 if mode == 'markdown':
365 tmpl = '<strong class="tooltip-hovercard" data-hovercard-alt="{uname}" data-hovercard-url="{hovercard_url}">@{uname}</strong>'
366 elif mode == 'rst':
367 tmpl = ' **@{uname}** '
368 else:
369 raise ValueError('mode must be rst or markdown')
370
371 return tmpl.format(**{'uname': uname,
372 'hovercard_url': hovercard_url})
373
374 return mention_pat.sub(wrapp, text).strip()
375
376 @classmethod
351 def plain(cls, source, universal_newline=True, leading_newline=True):
377 def plain(cls, source, universal_newline=True, leading_newline=True):
352 source = safe_unicode(source)
378 source = safe_unicode(source)
353 if universal_newline:
379 if universal_newline:
@@ -378,12 +404,7 b' class MarkupRenderer(object):'
378 cls.extensions, cls.output_format)
404 cls.extensions, cls.output_format)
379
405
380 if mentions:
406 if mentions:
381 mention_pat = re.compile(MENTIONS_REGEX)
407 mention_hl = cls.convert_mentions(source, mode='markdown')
382
383 def wrapp(match_obj):
384 uname = match_obj.groups()[0]
385 return ' **@%(uname)s** ' % {'uname': uname}
386 mention_hl = mention_pat.sub(wrapp, source).strip()
387 # we extracted mentions render with this using Mentions false
408 # we extracted mentions render with this using Mentions false
388 return cls.markdown(mention_hl, safe=safe, flavored=flavored,
409 return cls.markdown(mention_hl, safe=safe, flavored=flavored,
389 mentions=False)
410 mentions=False)
@@ -409,12 +430,7 b' class MarkupRenderer(object):'
409 @classmethod
430 @classmethod
410 def rst(cls, source, safe=True, mentions=False, clean_html=False):
431 def rst(cls, source, safe=True, mentions=False, clean_html=False):
411 if mentions:
432 if mentions:
412 mention_pat = re.compile(MENTIONS_REGEX)
433 mention_hl = cls.convert_mentions(source, mode='rst')
413
414 def wrapp(match_obj):
415 uname = match_obj.groups()[0]
416 return ' **@%(uname)s** ' % {'uname': uname}
417 mention_hl = mention_pat.sub(wrapp, source).strip()
418 # we extracted mentions render with this using Mentions false
434 # we extracted mentions render with this using Mentions false
419 return cls.rst(mention_hl, safe=safe, mentions=False)
435 return cls.rst(mention_hl, safe=safe, mentions=False)
420
436
@@ -443,7 +459,7 b' class MarkupRenderer(object):'
443 except Exception:
459 except Exception:
444 log.exception('Error when rendering RST')
460 log.exception('Error when rendering RST')
445 if safe:
461 if safe:
446 log.debug('Fallbacking to render in plain mode')
462 log.debug('Fallback to render in plain mode')
447 return cls.plain(source)
463 return cls.plain(source)
448 else:
464 else:
449 raise
465 raise
@@ -87,6 +87,10 b' body {'
87 border-left: @border-thickness solid @border-default-color;
87 border-left: @border-thickness solid @border-default-color;
88 }
88 }
89
89
90 .cursor-pointer {
91 cursor: pointer;
92 }
93
90 input + .action-link, .action-link.first{
94 input + .action-link, .action-link.first{
91 border-left: none;
95 border-left: none;
92 }
96 }
@@ -31,6 +31,7 b' function registerRCRoutes() {'
31 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
31 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
32 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
32 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
33 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
33 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
34 pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
34 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
35 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
35 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
36 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
36 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
37 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
@@ -299,6 +299,10 b' var tooltipActivate = function () {'
299 var altHovercard =$origin.data('hovercardAlt');
299 var altHovercard =$origin.data('hovercardAlt');
300
300
301 if (hovercardUrl !== undefined && hovercardUrl !== "") {
301 if (hovercardUrl !== undefined && hovercardUrl !== "") {
302 if (hovercardUrl.substr(0,12) === 'pyroutes.url'){
303 hovercardUrl = eval(hovercardUrl)
304 }
305
302 var loaded = loadHoverCard(hovercardUrl, altHovercard, function (data) {
306 var loaded = loadHoverCard(hovercardUrl, altHovercard, function (data) {
303 instance.content(data);
307 instance.content(data);
304 })
308 })
General Comments 0
You need to be logged in to leave comments. Login now