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('Fallback |
|
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