diffs.mako
968 lines
| 39.1 KiB
| application/x-mako
|
MakoHtmlLexer
r1325 | <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/> | ||
r1282 | <%def name="diff_line_anchor(filename, line, type)"><% | ||
return '%s_%s_%i' % (h.safeid(filename), type, line) | |||
%></%def> | |||
r1283 | <%def name="action_class(action)"> | ||
<% | |||
r1282 | return { | ||
'-': 'cb-deletion', | |||
'+': 'cb-addition', | |||
' ': 'cb-context', | |||
}.get(action, 'cb-empty') | |||
r1283 | %> | ||
</%def> | |||
r1282 | |||
r1283 | <%def name="op_class(op_id)"> | ||
<% | |||
r1282 | return { | ||
DEL_FILENODE: 'deletion', # file deleted | |||
BIN_FILENODE: 'warning' # binary diff hidden | |||
}.get(op_id, 'addition') | |||
r1283 | %> | ||
</%def> | |||
r1282 | |||
r2104 | |||
r1282 | |||
<%def name="render_diffset(diffset, commit=None, | |||
# collapse all file diff entries when there are more than this amount of files in the diff | |||
collapse_when_files_over=20, | |||
# collapse lines in the diff when more than this amount of lines changed in the file diff | |||
lines_changed_limit=500, | |||
# add a ruler at to the output | |||
ruler_at_chars=0, | |||
# show inline comments | |||
use_comments=False, | |||
# disable new comments | |||
disable_new_comments=False, | |||
# special file-comments that were deleted in previous versions | |||
# it's used for showing outdated comments for deleted files in a PR | |||
Bartłomiej Wołyńczyk
|
r2685 | deleted_files_comments=None, | |
# for cache purpose | |||
r3124 | inline_comments=None, | ||
r1282 | |||
)"> | |||
%if use_comments: | |||
<div id="cb-comments-inline-container-template" class="js-template"> | |||
Bartłomiej Wołyńczyk
|
r2685 | ${inline_comments_container([], inline_comments)} | |
r1282 | </div> | ||
<div class="js-template" id="cb-comment-inline-form-template"> | |||
<div class="comment-inline-form ac"> | |||
%if c.rhodecode_user.username != h.DEFAULT_USER: | |||
r1325 | ## render template for inline comments | ||
${commentblock.comment_form(form_type='inline')} | |||
r1282 | %else: | ||
${h.form('', class_='inline-form comment-form-login', method='get')} | |||
<div class="pull-left"> | |||
<div class="comment-help pull-right"> | |||
r2104 | ${_('You need to be logged in to leave comments.')} <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a> | ||
r1282 | </div> | ||
</div> | |||
<div class="comment-button pull-right"> | |||
<button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);"> | |||
${_('Cancel')} | |||
</button> | |||
</div> | |||
<div class="clearfix"></div> | |||
${h.end_form()} | |||
%endif | |||
</div> | |||
</div> | |||
%endif | |||
<% | |||
collapse_all = len(diffset.files) > collapse_when_files_over | |||
%> | |||
r3088 | %if c.user_session_attrs["diffmode"] == 'sideside': | ||
r1282 | <style> | ||
.wrapper { | |||
max-width: 1600px !important; | |||
} | |||
</style> | |||
%endif | |||
%if ruler_at_chars: | |||
<style> | |||
.diff table.cb .cb-content:after { | |||
content: ""; | |||
border-left: 1px solid blue; | |||
position: absolute; | |||
top: 0; | |||
height: 18px; | |||
opacity: .2; | |||
z-index: 10; | |||
//## +5 to account for diff action (+/-) | |||
left: ${ruler_at_chars + 5}ch; | |||
</style> | |||
%endif | |||
<div class="diffset ${disable_new_comments and 'diffset-comments-disabled'}"> | |||
<div class="diffset-heading ${diffset.limited_diff and 'diffset-heading-warning' or ''}"> | |||
%if commit: | |||
<div class="pull-right"> | |||
r1927 | <a class="btn tooltip" title="${h.tooltip(_('Browse Files at revision {}').format(commit.raw_id))}" href="${h.route_path('repo_files',repo_name=diffset.repo_name, commit_id=commit.raw_id, f_path='')}"> | ||
r1282 | ${_('Browse Files')} | ||
</a> | |||
</div> | |||
%endif | |||
<h2 class="clearinner"> | |||
r3100 | ## invidual commit | ||
% if commit: | |||
r3124 | <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.route_path('repo_commit',repo_name=diffset.repo_name,commit_id=commit.raw_id)}">${('r%s:%s' % (commit.idx,h.short_id(commit.raw_id)))}</a> - | ||
r3100 | ${h.age_component(commit.date)} | ||
% if diffset.limited_diff: | |||
- ${_('The requested commit is too big and content was truncated.')} | |||
${_ungettext('%(num)s file changed.', '%(num)s files changed.', diffset.changed_files) % {'num': diffset.changed_files}} | |||
<a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a> | |||
% elif hasattr(c, 'commit_ranges') and len(c.commit_ranges) > 1: | |||
## compare diff, has no file-selector and we want to show stats anyway | |||
${_ungettext('{num} file changed: {linesadd} inserted, ''{linesdel} deleted', | |||
'{num} files changed: {linesadd} inserted, {linesdel} deleted', diffset.changed_files) \ | |||
.format(num=diffset.changed_files, linesadd=diffset.lines_added, linesdel=diffset.lines_deleted)} | |||
% endif | |||
% else: | |||
## pull requests/compare | |||
${_('File Changes')} | |||
% endif | |||
r1282 | |||
</h2> | |||
</div> | |||
r2618 | %if diffset.has_hidden_changes: | ||
<p class="empty_data">${_('Some changes may be hidden')}</p> | |||
%elif not diffset.files: | |||
r1282 | <p class="empty_data">${_('No files')}</p> | ||
%endif | |||
<div class="filediffs"> | |||
r3126 | |||
r1374 | ## initial value could be marked as False later on | ||
<% over_lines_changed_limit = False %> | |||
r1282 | %for i, filediff in enumerate(diffset.files): | ||
<% | |||
r1844 | lines_changed = filediff.patch['stats']['added'] + filediff.patch['stats']['deleted'] | ||
r1282 | over_lines_changed_limit = lines_changed > lines_changed_limit | ||
%> | |||
r3126 | ## anchor with support of sticky header | ||
<div class="anchor" id="a_${h.FID(filediff.raw_id, filediff.patch['filename'])}"></div> | |||
r3081 | |||
r3126 | <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox" onchange="Waypoint.refreshAll();"> | ||
r1282 | <div | ||
class="filediff" | |||
r1844 | data-f-path="${filediff.patch['filename']}" | ||
r3126 | data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" | ||
r3081 | > | ||
<label for="filediff-collapse-${id(filediff)}" class="filediff-heading"> | |||
<div class="filediff-collapse-indicator"></div> | |||
${diff_ops(filediff)} | |||
</label> | |||
r3126 | |||
r3081 | ${diff_menu(filediff, use_comments=use_comments)} | ||
r3126 | <table data-f-path="${filediff.patch['filename']}" data-anchor-id="${h.FID(filediff.raw_id, filediff.patch['filename'])}" class="code-visible-block cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${(over_lines_changed_limit and 'cb-collapsed' or '')}"> | ||
r3081 | |||
## new/deleted/empty content case | |||
% if not filediff.hunks: | |||
## Comment container, on "fakes" hunk that contains all data to render comments | |||
r3088 | ${render_hunk_lines(c.user_session_attrs["diffmode"], filediff.hunk_ops, use_comments=use_comments, inline_comments=inline_comments)} | ||
r3081 | % endif | ||
r1844 | %if filediff.limited_diff: | ||
r1282 | <tr class="cb-warning cb-collapser"> | ||
r3088 | <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}> | ||
r2104 | ${_('The requested commit is too big and content was truncated.')} <a href="${h.current_route_path(request, fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a> | ||
r1282 | </td> | ||
</tr> | |||
%else: | |||
%if over_lines_changed_limit: | |||
<tr class="cb-warning cb-collapser"> | |||
r3088 | <td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}> | ||
r1282 | ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)} | ||
<a href="#" class="cb-expand" | |||
onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')} | |||
</a> | |||
<a href="#" class="cb-collapse" | |||
onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')} | |||
</a> | |||
</td> | |||
</tr> | |||
%endif | |||
%endif | |||
r3081 | % for hunk in filediff.hunks: | ||
<tr class="cb-hunk"> | |||
r3088 | <td ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=3' or '')}> | ||
r3081 | ## TODO: dan: add ajax loading of more context here | ||
## <a href="#"> | |||
<i class="icon-more"></i> | |||
## </a> | |||
</td> | |||
r3088 | <td ${(c.user_session_attrs["diffmode"] == 'sideside' and 'colspan=5' or '')}> | ||
r3081 | @@ | ||
-${hunk.source_start},${hunk.source_length} | |||
+${hunk.target_start},${hunk.target_length} | |||
${hunk.section_header} | |||
</td> | |||
</tr> | |||
r3088 | ${render_hunk_lines(c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments)} | ||
r3081 | % endfor | ||
r1282 | |||
r3080 | <% unmatched_comments = (inline_comments or {}).get(filediff.patch['filename'], {}) %> | ||
r1282 | ## outdated comments that do not fit into currently displayed lines | ||
r3080 | % for lineno, comments in unmatched_comments.items(): | ||
r1282 | |||
r3088 | %if c.user_session_attrs["diffmode"] == 'unified': | ||
r3080 | % if loop.index == 0: | ||
<tr class="cb-hunk"> | |||
<td colspan="3"></td> | |||
<td> | |||
<div> | |||
${_('Unmatched inline comments below')} | |||
</div> | |||
</td> | |||
</tr> | |||
% endif | |||
<tr class="cb-line"> | |||
<td class="cb-data cb-context"></td> | |||
<td class="cb-lineno cb-context"></td> | |||
<td class="cb-lineno cb-context"></td> | |||
<td class="cb-content cb-context"> | |||
Bartłomiej Wołyńczyk
|
r2685 | ${inline_comments_container(comments, inline_comments)} | |
r3080 | </td> | ||
</tr> | |||
r3088 | %elif c.user_session_attrs["diffmode"] == 'sideside': | ||
r3080 | % if loop.index == 0: | ||
r3083 | <tr class="cb-comment-info"> | ||
r3080 | <td colspan="2"></td> | ||
r3083 | <td class="cb-line"> | ||
<div> | |||
${_('Unmatched inline comments below')} | |||
</div> | |||
</td> | |||
<td colspan="2"></td> | |||
<td class="cb-line"> | |||
r3080 | <div> | ||
${_('Unmatched comments below')} | |||
</div> | |||
</td> | |||
</tr> | |||
% endif | |||
<tr class="cb-line"> | |||
<td class="cb-data cb-context"></td> | |||
<td class="cb-lineno cb-context"></td> | |||
<td class="cb-content cb-context"> | |||
% if lineno.startswith('o'): | |||
${inline_comments_container(comments, inline_comments)} | |||
% endif | |||
</td> | |||
r1282 | |||
r3080 | <td class="cb-data cb-context"></td> | ||
<td class="cb-lineno cb-context"></td> | |||
<td class="cb-content cb-context"> | |||
% if lineno.startswith('n'): | |||
${inline_comments_container(comments, inline_comments)} | |||
% endif | |||
</td> | |||
</tr> | |||
%endif | |||
r1282 | |||
% endfor | |||
</table> | |||
</div> | |||
%endfor | |||
## outdated comments that are made for a file that has been deleted | |||
% for filename, comments_dict in (deleted_files_comments or {}).items(): | |||
r2808 | <% | ||
display_state = 'display: none' | |||
open_comments_in_file = [x for x in comments_dict['comments'] if x.outdated is False] | |||
if open_comments_in_file: | |||
display_state = '' | |||
%> | |||
<div class="filediffs filediff-outdated" style="${display_state}"> | |||
r3126 | <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state" id="filediff-collapse-${id(filename)}" type="checkbox" onchange="Waypoint.refreshAll();"> | ||
r3124 | <div class="filediff" data-f-path="${filename}" id="a_${h.FID(filediff.raw_id, filename)}"> | ||
r1282 | <label for="filediff-collapse-${id(filename)}" class="filediff-heading"> | ||
<div class="filediff-collapse-indicator"></div> | |||
<span class="pill"> | |||
## file was deleted | |||
<strong>${filename}</strong> | |||
</span> | |||
<span class="pill-group" style="float: left"> | |||
## file op, doesn't need translation | |||
<span class="pill" op="removed">removed in this version</span> | |||
</span> | |||
r3124 | <a class="pill filediff-anchor" href="#a_${h.FID(filediff.raw_id, filename)}">¶</a> | ||
r1282 | <span class="pill-group" style="float: right"> | ||
<span class="pill" op="deleted">-${comments_dict['stats']}</span> | |||
</span> | |||
</label> | |||
r3088 | <table class="cb cb-diff-${c.user_session_attrs["diffmode"]} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}"> | ||
r1282 | <tr> | ||
r3088 | % if c.user_session_attrs["diffmode"] == 'unified': | ||
r1282 | <td></td> | ||
%endif | |||
<td></td> | |||
r3088 | <td class="cb-text cb-${op_class(BIN_FILENODE)}" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=5')}> | ||
r2808 | ${_('File was deleted in this version. There are still outdated/unresolved comments attached to it.')} | ||
r1282 | </td> | ||
</tr> | |||
r3088 | %if c.user_session_attrs["diffmode"] == 'unified': | ||
r1282 | <tr class="cb-line"> | ||
<td class="cb-data cb-context"></td> | |||
<td class="cb-lineno cb-context"></td> | |||
<td class="cb-lineno cb-context"></td> | |||
<td class="cb-content cb-context"> | |||
Bartłomiej Wołyńczyk
|
r2685 | ${inline_comments_container(comments_dict['comments'], inline_comments)} | |
r1282 | </td> | ||
</tr> | |||
r3088 | %elif c.user_session_attrs["diffmode"] == 'sideside': | ||
r1282 | <tr class="cb-line"> | ||
<td class="cb-data cb-context"></td> | |||
<td class="cb-lineno cb-context"></td> | |||
<td class="cb-content cb-context"></td> | |||
<td class="cb-data cb-context"></td> | |||
<td class="cb-lineno cb-context"></td> | |||
<td class="cb-content cb-context"> | |||
Bartłomiej Wołyńczyk
|
r2685 | ${inline_comments_container(comments_dict['comments'], inline_comments)} | |
r1282 | </td> | ||
</tr> | |||
%endif | |||
</table> | |||
</div> | |||
</div> | |||
% endfor | |||
</div> | |||
</div> | |||
</%def> | |||
<%def name="diff_ops(filediff)"> | |||
<% | |||
from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \ | |||
r1582 | MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE | ||
r1282 | %> | ||
<span class="pill"> | |||
%if filediff.source_file_path and filediff.target_file_path: | |||
r1283 | %if filediff.source_file_path != filediff.target_file_path: | ||
r1582 | ## file was renamed, or copied | ||
r1844 | %if RENAMED_FILENODE in filediff.patch['stats']['ops']: | ||
r1582 | <strong>${filediff.target_file_path}</strong> ⬅ <del>${filediff.source_file_path}</del> | ||
r2120 | <% final_path = filediff.target_file_path %> | ||
r1844 | %elif COPIED_FILENODE in filediff.patch['stats']['ops']: | ||
r1582 | <strong>${filediff.target_file_path}</strong> ⬅ ${filediff.source_file_path} | ||
r2120 | <% final_path = filediff.target_file_path %> | ||
r1582 | %endif | ||
r1282 | %else: | ||
## file was modified | |||
<strong>${filediff.source_file_path}</strong> | |||
r2120 | <% final_path = filediff.source_file_path %> | ||
r1282 | %endif | ||
%else: | |||
%if filediff.source_file_path: | |||
## file was deleted | |||
<strong>${filediff.source_file_path}</strong> | |||
r2120 | <% final_path = filediff.source_file_path %> | ||
r1282 | %else: | ||
## file was added | |||
<strong>${filediff.target_file_path}</strong> | |||
r2120 | <% final_path = filediff.target_file_path %> | ||
r1282 | %endif | ||
%endif | |||
r2120 | <i style="color: #aaa" class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="${_('Copy the full path')}" onclick="return false;"></i> | ||
r1282 | </span> | ||
r3116 | ## anchor link | ||
r3124 | <a class="pill filediff-anchor" href="#a_${h.FID(filediff.raw_id, filediff.patch['filename'])}">¶</a> | ||
r3116 | |||
<span class="pill-group" style="float: right"> | |||
## ops pills | |||
r1844 | %if filediff.limited_diff: | ||
r1282 | <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span> | ||
%endif | |||
r1582 | |||
r1844 | %if NEW_FILENODE in filediff.patch['stats']['ops']: | ||
r1282 | <span class="pill" op="created">created</span> | ||
%if filediff['target_mode'].startswith('120'): | |||
<span class="pill" op="symlink">symlink</span> | |||
%else: | |||
<span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span> | |||
%endif | |||
%endif | |||
r3116 | %if RENAMED_FILENODE in filediff.patch['stats']['ops']: | ||
<span class="pill" op="renamed">renamed</span> | |||
%endif | |||
%if COPIED_FILENODE in filediff.patch['stats']['ops']: | |||
<span class="pill" op="copied">copied</span> | |||
%endif | |||
r1844 | %if DEL_FILENODE in filediff.patch['stats']['ops']: | ||
r1282 | <span class="pill" op="removed">removed</span> | ||
%endif | |||
r1844 | %if CHMOD_FILENODE in filediff.patch['stats']['ops']: | ||
r1282 | <span class="pill" op="mode"> | ||
${nice_mode(filediff['source_mode'])} âž¡ ${nice_mode(filediff['target_mode'])} | |||
</span> | |||
%endif | |||
r1844 | %if BIN_FILENODE in filediff.patch['stats']['ops']: | ||
r1282 | <span class="pill" op="binary">binary</span> | ||
r1844 | %if MOD_FILENODE in filediff.patch['stats']['ops']: | ||
r3116 | <span class="pill" op="modified">modified</span> | ||
r1282 | %endif | ||
%endif | |||
r3116 | |||
<span class="pill" op="added">${('+' if filediff.patch['stats']['added'] else '')}${filediff.patch['stats']['added']}</span> | |||
<span class="pill" op="deleted">${((h.safe_int(filediff.patch['stats']['deleted']) or 0) * -1)}</span> | |||
r1282 | </span> | ||
</%def> | |||
<%def name="nice_mode(filemode)"> | |||
r3100 | ${(filemode.startswith('100') and filemode[3:] or filemode)} | ||
r1282 | </%def> | ||
<%def name="diff_menu(filediff, use_comments=False)"> | |||
<div class="filediff-menu"> | |||
%if filediff.diffset.source_ref: | |||
r1844 | %if filediff.operation in ['D', 'M']: | ||
r1282 | <a | ||
class="tooltip" | |||
r1927 | href="${h.route_path('repo_files',repo_name=filediff.diffset.repo_name,commit_id=filediff.diffset.source_ref,f_path=filediff.source_file_path)}" | ||
r1282 | title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" | ||
> | |||
${_('Show file before')} | |||
</a> | | |||
%else: | |||
<span | |||
class="tooltip" | |||
title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" | |||
> | |||
${_('Show file before')} | |||
</span> | | |||
%endif | |||
r1844 | %if filediff.operation in ['A', 'M']: | ||
r1282 | <a | ||
class="tooltip" | |||
r1927 | href="${h.route_path('repo_files',repo_name=filediff.diffset.source_repo_name,commit_id=filediff.diffset.target_ref,f_path=filediff.target_file_path)}" | ||
r1282 | title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" | ||
> | |||
${_('Show file after')} | |||
</a> | | |||
%else: | |||
<span | |||
class="tooltip" | |||
title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" | |||
> | |||
${_('Show file after')} | |||
</span> | | |||
%endif | |||
<a | |||
class="tooltip" | |||
title="${h.tooltip(_('Raw diff'))}" | |||
r1927 | href="${h.route_path('repo_files_diff',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path, _query=dict(diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='raw'))}" | ||
r1282 | > | ||
${_('Raw diff')} | |||
</a> | | |||
<a | |||
class="tooltip" | |||
title="${h.tooltip(_('Download diff'))}" | |||
r1927 | href="${h.route_path('repo_files_diff',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path, _query=dict(diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='download'))}" | ||
r1282 | > | ||
${_('Download diff')} | |||
</a> | |||
% if use_comments: | |||
| | |||
% endif | |||
## TODO: dan: refactor ignorews_url and context_url into the diff renderer same as diffmode=unified/sideside. Also use ajax to load more context (by clicking hunks) | |||
%if hasattr(c, 'ignorews_url'): | |||
r3124 | ${c.ignorews_url(request, h.FID(filediff.raw_id, filediff.patch['filename']))} | ||
r1282 | %endif | ||
%if hasattr(c, 'context_url'): | |||
r3124 | ${c.context_url(request, h.FID(filediff.raw_id, filediff.patch['filename']))} | ||
r1282 | %endif | ||
%if use_comments: | |||
<a href="#" onclick="return Rhodecode.comments.toggleComments(this);"> | |||
<span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span> | |||
</a> | |||
%endif | |||
%endif | |||
</div> | |||
</%def> | |||
Bartłomiej Wołyńczyk
|
r2685 | <%def name="inline_comments_container(comments, inline_comments)"> | |
r1282 | <div class="inline-comments"> | ||
%for comment in comments: | |||
Bartłomiej Wołyńczyk
|
r2685 | ${commentblock.comment_block(comment, inline=True)} | |
r1282 | %endfor | ||
% if comments and comments[-1].outdated: | |||
<span class="btn btn-secondary cb-comment-add-button comment-outdated}" | |||
style="display: none;}"> | |||
${_('Add another comment')} | |||
</span> | |||
% else: | |||
<span onclick="return Rhodecode.comments.createComment(this)" | |||
class="btn btn-secondary cb-comment-add-button"> | |||
${_('Add another comment')} | |||
</span> | |||
% endif | |||
</div> | |||
</%def> | |||
Bartłomiej Wołyńczyk
|
r2685 | <%! | |
r3080 | def get_comments_for(diff_type, comments, filename, line_version, line_number): | ||
Bartłomiej Wołyńczyk
|
r2685 | if hasattr(filename, 'unicode_path'): | |
filename = filename.unicode_path | |||
r1282 | |||
Bartłomiej Wołyńczyk
|
r2685 | if not isinstance(filename, basestring): | |
return None | |||
r3080 | line_key = '{}{}'.format(line_version, line_number) ## e.g o37, n12 | ||
Bartłomiej Wołyńczyk
|
r2685 | if comments and filename in comments: | |
file_comments = comments[filename] | |||
if line_key in file_comments: | |||
r3080 | data = file_comments.pop(line_key) | ||
return data | |||
Bartłomiej Wołyńczyk
|
r2685 | %> | |
<%def name="render_hunk_lines_sideside(hunk, use_comments=False, inline_comments=None)"> | |||
r1282 | %for i, line in enumerate(hunk.sideside): | ||
<% | |||
old_line_anchor, new_line_anchor = None, None | |||
if line.original.lineno: | |||
r1844 | old_line_anchor = diff_line_anchor(hunk.source_file_path, line.original.lineno, 'o') | ||
r1282 | if line.modified.lineno: | ||
r1844 | new_line_anchor = diff_line_anchor(hunk.target_file_path, line.modified.lineno, 'n') | ||
r1282 | %> | ||
<tr class="cb-line"> | |||
<td class="cb-data ${action_class(line.original.action)}" | |||
r2642 | data-line-no="${line.original.lineno}" | ||
r1282 | > | ||
<div> | |||
r3080 | |||
<% line_old_comments = None %> | |||
Bartłomiej Wołyńczyk
|
r2685 | %if line.original.get_comment_args: | |
r3080 | <% line_old_comments = get_comments_for('side-by-side', inline_comments, *line.original.get_comment_args) %> | ||
Bartłomiej Wołyńczyk
|
r2685 | %endif | |
r3080 | %if line_old_comments: | ||
<% has_outdated = any([x.outdated for x in line_old_comments]) %> | |||
r2611 | % if has_outdated: | ||
r3080 | <i title="${_('comments including outdated')}:${len(line_old_comments)}" class="icon-comment_toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | ||
r2611 | % else: | ||
r3080 | <i title="${_('comments')}: ${len(line_old_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | ||
r2611 | % endif | ||
r1282 | %endif | ||
</div> | |||
</td> | |||
<td class="cb-lineno ${action_class(line.original.action)}" | |||
r2642 | data-line-no="${line.original.lineno}" | ||
r1282 | %if old_line_anchor: | ||
id="${old_line_anchor}" | |||
%endif | |||
> | |||
%if line.original.lineno: | |||
<a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a> | |||
%endif | |||
</td> | |||
<td class="cb-content ${action_class(line.original.action)}" | |||
r2642 | data-line-no="o${line.original.lineno}" | ||
r1282 | > | ||
%if use_comments and line.original.lineno: | |||
${render_add_comment_button()} | |||
%endif | |||
<span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span> | |||
Bartłomiej Wołyńczyk
|
r2685 | ||
r3080 | %if use_comments and line.original.lineno and line_old_comments: | ||
${inline_comments_container(line_old_comments, inline_comments)} | |||
r1282 | %endif | ||
Bartłomiej Wołyńczyk
|
r2685 | ||
r1282 | </td> | ||
<td class="cb-data ${action_class(line.modified.action)}" | |||
r2642 | data-line-no="${line.modified.lineno}" | ||
r1282 | > | ||
<div> | |||
Bartłomiej Wołyńczyk
|
r2685 | ||
%if line.modified.get_comment_args: | |||
r3080 | <% line_new_comments = get_comments_for('side-by-side', inline_comments, *line.modified.get_comment_args) %> | ||
Bartłomiej Wołyńczyk
|
r2685 | %else: | |
r3080 | <% line_new_comments = None%> | ||
Bartłomiej Wołyńczyk
|
r2685 | %endif | |
r3080 | %if line_new_comments: | ||
<% has_outdated = any([x.outdated for x in line_new_comments]) %> | |||
r2611 | % if has_outdated: | ||
r3080 | <i title="${_('comments including outdated')}:${len(line_new_comments)}" class="icon-comment_toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | ||
r2611 | % else: | ||
r3080 | <i title="${_('comments')}: ${len(line_new_comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | ||
r2611 | % endif | ||
r1282 | %endif | ||
</div> | |||
</td> | |||
<td class="cb-lineno ${action_class(line.modified.action)}" | |||
r2642 | data-line-no="${line.modified.lineno}" | ||
r1282 | %if new_line_anchor: | ||
id="${new_line_anchor}" | |||
%endif | |||
> | |||
%if line.modified.lineno: | |||
<a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a> | |||
%endif | |||
</td> | |||
<td class="cb-content ${action_class(line.modified.action)}" | |||
r2642 | data-line-no="n${line.modified.lineno}" | ||
r1282 | > | ||
%if use_comments and line.modified.lineno: | |||
${render_add_comment_button()} | |||
%endif | |||
<span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span> | |||
r3080 | %if use_comments and line.modified.lineno and line_new_comments: | ||
${inline_comments_container(line_new_comments, inline_comments)} | |||
r1282 | %endif | ||
</td> | |||
</tr> | |||
%endfor | |||
</%def> | |||
Bartłomiej Wołyńczyk
|
r2685 | <%def name="render_hunk_lines_unified(hunk, use_comments=False, inline_comments=None)"> | |
%for old_line_no, new_line_no, action, content, comments_args in hunk.unified: | |||
r1282 | <% | ||
old_line_anchor, new_line_anchor = None, None | |||
if old_line_no: | |||
r1844 | old_line_anchor = diff_line_anchor(hunk.source_file_path, old_line_no, 'o') | ||
r1282 | if new_line_no: | ||
r1844 | new_line_anchor = diff_line_anchor(hunk.target_file_path, new_line_no, 'n') | ||
r1282 | %> | ||
<tr class="cb-line"> | |||
<td class="cb-data ${action_class(action)}"> | |||
<div> | |||
Bartłomiej Wołyńczyk
|
r2685 | ||
%if comments_args: | |||
r3080 | <% comments = get_comments_for('unified', inline_comments, *comments_args) %> | ||
Bartłomiej Wołyńczyk
|
r2685 | %else: | |
r3082 | <% comments = None %> | ||
Bartłomiej Wołyńczyk
|
r2685 | %endif | |
r2611 | % if comments: | ||
<% has_outdated = any([x.outdated for x in comments]) %> | |||
% if has_outdated: | |||
<i title="${_('comments including outdated')}:${len(comments)}" class="icon-comment_toggle" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |||
% else: | |||
<i title="${_('comments')}: ${len(comments)}" class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |||
% endif | |||
% endif | |||
r1282 | </div> | ||
</td> | |||
<td class="cb-lineno ${action_class(action)}" | |||
r2642 | data-line-no="${old_line_no}" | ||
r1282 | %if old_line_anchor: | ||
id="${old_line_anchor}" | |||
%endif | |||
> | |||
%if old_line_anchor: | |||
<a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a> | |||
%endif | |||
</td> | |||
<td class="cb-lineno ${action_class(action)}" | |||
r2642 | data-line-no="${new_line_no}" | ||
r1282 | %if new_line_anchor: | ||
id="${new_line_anchor}" | |||
%endif | |||
> | |||
%if new_line_anchor: | |||
<a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a> | |||
%endif | |||
</td> | |||
<td class="cb-content ${action_class(action)}" | |||
r3100 | data-line-no="${(new_line_no and 'n' or 'o')}${(new_line_no or old_line_no)}" | ||
r1282 | > | ||
%if use_comments: | |||
${render_add_comment_button()} | |||
%endif | |||
<span class="cb-code">${action} ${content or '' | n}</span> | |||
%if use_comments and comments: | |||
Bartłomiej Wołyńczyk
|
r2685 | ${inline_comments_container(comments, inline_comments)} | |
r1282 | %endif | ||
</td> | |||
</tr> | |||
%endfor | |||
</%def> | |||
r3081 | |||
<%def name="render_hunk_lines(diff_mode, hunk, use_comments, inline_comments)"> | |||
% if diff_mode == 'unified': | |||
${render_hunk_lines_unified(hunk, use_comments=use_comments, inline_comments=inline_comments)} | |||
% elif diff_mode == 'sideside': | |||
${render_hunk_lines_sideside(hunk, use_comments=use_comments, inline_comments=inline_comments)} | |||
% else: | |||
<tr class="cb-line"> | |||
<td>unknown diff mode</td> | |||
</tr> | |||
% endif | |||
r3124 | </%def>file changes | ||
r3081 | |||
r1282 | <%def name="render_add_comment_button()"> | ||
<button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this)"> | |||
<span><i class="icon-comment"></i></span> | |||
</button> | |||
</%def> | |||
r3124 | <%def name="render_diffset_menu(diffset=None, range_diff_on=None)"> | ||
r1282 | |||
r3126 | <div id="diff-file-sticky" class="diffset-menu clearinner"> | ||
## auto adjustable | |||
r3128 | <div class="sidebar__inner"> | ||
<div class="sidebar__bar"> | |||
r3126 | <div class="pull-right"> | ||
r1282 | <div class="btn-group"> | ||
<a | |||
r3088 | class="btn ${(c.user_session_attrs["diffmode"] == 'sideside' and 'btn-primary')} tooltip" | ||
r1843 | title="${h.tooltip(_('View side by side'))}" | ||
r2307 | href="${h.current_route_path(request, diffmode='sideside')}"> | ||
r1282 | <span>${_('Side by Side')}</span> | ||
</a> | |||
<a | |||
r3088 | class="btn ${(c.user_session_attrs["diffmode"] == 'unified' and 'btn-primary')} tooltip" | ||
r2307 | title="${h.tooltip(_('View unified'))}" href="${h.current_route_path(request, diffmode='unified')}"> | ||
r1282 | <span>${_('Unified')}</span> | ||
</a> | |||
r3124 | % if range_diff_on is True: | ||
<a | |||
title="${_('Turn off: Show the diff as commit range')}" | |||
class="btn btn-primary" | |||
href="${h.current_route_path(request, **{"range-diff":"0"})}"> | |||
<span>${_('Range Diff')}</span> | |||
</a> | |||
% elif range_diff_on is False: | |||
<a | |||
title="${_('Show the diff as commit range')}" | |||
class="btn" | |||
href="${h.current_route_path(request, **{"range-diff":"1"})}"> | |||
<span>${_('Range Diff')}</span> | |||
</a> | |||
% endif | |||
r1282 | </div> | ||
</div> | |||
r3126 | <div class="pull-left"> | ||
<div class="btn-group"> | |||
r3100 | <div class="pull-left"> | ||
${h.hidden('file_filter')} | |||
</div> | |||
r1282 | <a | ||
class="btn" | |||
href="#" | |||
r3126 | onclick="$('input[class=filediff-collapse-state]').prop('checked', false); Waypoint.refreshAll(); return false">${_('Expand All Files')}</a> | ||
<a | |||
class="btn" | |||
href="#" | |||
onclick="$('input[class=filediff-collapse-state]').prop('checked', true); Waypoint.refreshAll(); return false">${_('Collapse All Files')}</a> | |||
r1282 | <a | ||
class="btn" | |||
href="#" | |||
r3126 | onclick="updateSticky();return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode Diff')}</a> | ||
r3100 | |||
r1282 | </div> | ||
r3128 | </div> | ||
r1282 | </div> | ||
r3126 | <div class="fpath-placeholder"> | ||
<i class="icon-file-text"></i> | |||
<strong class="fpath-placeholder-text"> | |||
r3128 | Context file: | ||
r3126 | </strong> | ||
</div> | |||
<div class="sidebar_inner_shadow"></div> | |||
</div> | |||
r1282 | </div> | ||
r3100 | |||
% if diffset: | |||
%if diffset.limited_diff: | |||
r3126 | <% file_placeholder = _ungettext('%(num)s file changed', '%(num)s files changed', diffset.changed_files) % {'num': diffset.changed_files} %> | ||
r3100 | %else: | ||
<% file_placeholder = _ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted', '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}%> | |||
%endif | |||
r3126 | ## case on range-diff placeholder needs to be updated | ||
% if range_diff_on is True: | |||
<% file_placeholder = _('Disabled on range diff') %> | |||
% endif | |||
r3100 | |||
<script> | |||
var feedFilesOptions = function (query, initialData) { | |||
var data = {results: []}; | |||
var isQuery = typeof query.term !== 'undefined'; | |||
var section = _gettext('Changed files'); | |||
var filteredData = []; | |||
//filter results | |||
$.each(initialData.results, function (idx, value) { | |||
if (!isQuery || query.term.length === 0 || value.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) { | |||
filteredData.push({ | |||
'id': this.id, | |||
'text': this.text, | |||
"ops": this.ops, | |||
}) | |||
} | |||
}); | |||
data.results = filteredData; | |||
query.callback(data); | |||
}; | |||
var formatFileResult = function(result, container, query, escapeMarkup) { | |||
return function(data, escapeMarkup) { | |||
var container = '<div class="filelist" style="padding-right:100px">{0}</div>'; | |||
var tmpl = '<span style="margin-right:-50px"><strong>{0}</strong></span>'.format(escapeMarkup(data['text'])); | |||
var pill = '<span class="pill-group" style="float: right;margin-right: -100px">' + | |||
'<span class="pill" op="added">{0}</span>' + | |||
'<span class="pill" op="deleted">{1}</span>' + | |||
'</span>' | |||
; | |||
var added = data['ops']['added']; | |||
if (added === 0) { | |||
// don't show +0 | |||
added = 0; | |||
} else { | |||
added = '+' + added; | |||
} | |||
var deleted = -1*data['ops']['deleted']; | |||
tmpl += pill.format(added, deleted); | |||
return container.format(tmpl); | |||
}(result, escapeMarkup); | |||
}; | |||
var preloadData = { | |||
results: [ | |||
% for filediff in diffset.files: | |||
r3124 | {id:"a_${h.FID(filediff.raw_id, filediff.patch['filename'])}", | ||
r3100 | text:"${filediff.patch['filename']}", | ||
ops:${h.json.dumps(filediff.patch['stats'])|n}}${('' if loop.last else ',')} | |||
% endfor | |||
] | |||
}; | |||
r3126 | $(document).ready(function () { | ||
var fileFilter = $("#file_filter").select2({ | |||
'dropdownAutoWidth': true, | |||
'width': 'auto', | |||
'placeholder': "${file_placeholder}", | |||
containerCssClass: "drop-menu", | |||
dropdownCssClass: "drop-menu-dropdown", | |||
data: preloadData, | |||
query: function(query) { | |||
feedFilesOptions(query, preloadData); | |||
}, | |||
formatResult: formatFileResult | |||
}); | |||
% if range_diff_on is True: | |||
fileFilter.select2("enable", false); | |||
% endif | |||
$("#file_filter").on('click', function (e) { | |||
e.preventDefault(); | |||
var selected = $('#file_filter').select2('data'); | |||
var idSelector = "#"+selected.id; | |||
window.location.hash = idSelector; | |||
// expand the container if we quick-select the field | |||
$(idSelector).next().prop('checked', false); | |||
Waypoint.refreshAll() | |||
}); | |||
var contextPrefix = _gettext('Context file: '); | |||
## sticky sidebar | |||
var sidebarElement = document.getElementById('diff-file-sticky'); | |||
sidebar = new StickySidebar(sidebarElement, { | |||
topSpacing: 0, | |||
bottomSpacing: 0, | |||
innerWrapperSelector: '.sidebar__inner' | |||
}); | |||
sidebarElement.addEventListener('affixed.static.stickySidebar', function () { | |||
// reset our file so it's not holding new value | |||
$('.fpath-placeholder-text').html(contextPrefix) | |||
}); | |||
updateSticky = function () { | |||
sidebar.updateSticky() | |||
}; | |||
var animateText = $.debounce(100, function(fPath, anchorId) { | |||
// animate setting the text | |||
var callback = function () { | |||
$('.fpath-placeholder-text').animate({'opacity': 1.00}, 200) | |||
$('.fpath-placeholder-text').html(contextPrefix + '<a href="#a_' + anchorId + '">' + fPath + '</a>') | |||
}; | |||
$('.fpath-placeholder-text').animate({'opacity': 0.15}, 200, callback); | |||
}); | |||
## dynamic file waypoints | |||
var setFPathInfo = function(fPath, anchorId){ | |||
animateText(fPath, anchorId) | |||
}; | |||
var codeBlock = $('.filediff'); | |||
// forward waypoint | |||
codeBlock.waypoint( | |||
function(direction) { | |||
if (direction === "down"){ | |||
setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId')) | |||
} | |||
}, { | |||
r3128 | offset: 70, | ||
r3126 | context: '.fpath-placeholder' | ||
} | |||
); | |||
// backward waypoint | |||
codeBlock.waypoint( | |||
function(direction) { | |||
if (direction === "up"){ | |||
setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId')) | |||
} | |||
}, { | |||
offset: function () { | |||
r3128 | return -this.element.clientHeight + 90 | ||
r3126 | }, | ||
context: '.fpath-placeholder' | |||
} | |||
); | |||
r3100 | }); | ||
</script> | |||
% endif | |||
r3126 | </%def> |