diffs.mako
1404 lines
| 56.2 KiB
| application/x-mako
|
MakoHtmlLexer
r4543 | <%namespace name="base" file="/base/base.mako"/> | |||
r1325 | <%namespace name="commentblock" file="/changeset/changeset_file_comment.mako"/> | |||
r3131 | <%def name="diff_line_anchor(commit, filename, line, type)"><% | |||
return '%s_%s_%i' % (h.md5_safe(commit+filename), type, line) | ||||
r1282 | %></%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 | ||||
r3884 | # additional menu for PRs | |||
r4140 | pull_request_menu=None, | |||
# show/hide todo next to comments | ||||
show_todos=True, | ||||
r3884 | ||||
r1282 | )"> | |||
r3882 | ||||
<% | ||||
diffset_container_id = h.md5(diffset.target_ref) | ||||
collapse_all = len(diffset.files) > collapse_when_files_over | ||||
r4202 | active_pattern_entries = h.get_active_pattern_entries(getattr(c, 'repo_name', None)) | |||
r4485 | from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \ | |||
MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE | ||||
r3882 | %> | |||
r1282 | %if use_comments: | |||
r4202 | ||||
## Template for injecting comments | ||||
r1282 | <div id="cb-comments-inline-container-template" class="js-template"> | |||
r4202 | ${inline_comments_container([])} | |||
r1282 | </div> | |||
r4202 | ||||
r1282 | <div class="js-template" id="cb-comment-inline-form-template"> | |||
<div class="comment-inline-form ac"> | ||||
r4543 | %if not c.rhodecode_user.is_default: | |||
r1325 | ## render template for inline comments | |||
${commentblock.comment_form(form_type='inline')} | ||||
r1282 | %endif | |||
</div> | ||||
</div> | ||||
%endif | ||||
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'}"> | ||||
r3882 | ||||
<div style="height: 20px; line-height: 20px"> | ||||
## expand/collapse action | ||||
<div class="pull-left"> | ||||
<a class="${'collapsed' if collapse_all else ''}" href="#expand-files" onclick="toggleExpand(this, '${diffset_container_id}'); return false"> | ||||
% if collapse_all: | ||||
<i class="icon-plus-squared-alt icon-no-margin"></i>${_('Expand all files')} | ||||
% else: | ||||
<i class="icon-minus-squared-alt icon-no-margin"></i>${_('Collapse all files')} | ||||
% endif | ||||
</a> | ||||
</div> | ||||
## todos | ||||
r4140 | % if show_todos and getattr(c, 'at_version', None): | |||
r3884 | <div class="pull-right"> | |||
<i class="icon-flag-filled" style="color: #949494">TODOs:</i> | ||||
${_('not available in this view')} | ||||
</div> | ||||
r4140 | % elif show_todos: | |||
r3882 | <div class="pull-right"> | |||
<div class="comments-number" style="padding-left: 10px"> | ||||
% if hasattr(c, 'unresolved_comments') and hasattr(c, 'resolved_comments'): | ||||
<i class="icon-flag-filled" style="color: #949494">TODOs:</i> | ||||
% if c.unresolved_comments: | ||||
<a href="#show-todos" onclick="$('#todo-box').toggle(); return false"> | ||||
${_('{} unresolved').format(len(c.unresolved_comments))} | ||||
</a> | ||||
% else: | ||||
${_('0 unresolved')} | ||||
% endif | ||||
r3884 | ${_('{} Resolved').format(len(c.resolved_comments))} | |||
r3882 | % endif | |||
r1282 | </div> | |||
r3882 | </div> | |||
r3100 | % endif | |||
r1282 | ||||
r4481 | ## ## comments | |||
## <div class="pull-right"> | ||||
## <div class="comments-number" style="padding-left: 10px"> | ||||
## % if hasattr(c, 'comments') and hasattr(c, 'inline_cnt'): | ||||
## <i class="icon-comment" style="color: #949494">COMMENTS:</i> | ||||
## % if c.comments: | ||||
## <a href="#comments">${_ungettext("{} General", "{} General", len(c.comments)).format(len(c.comments))}</a>, | ||||
## % else: | ||||
## ${_('0 General')} | ||||
## % endif | ||||
## | ||||
## % if c.inline_cnt: | ||||
## <a href="#" onclick="return Rhodecode.comments.nextComment();" | ||||
## id="inline-comments-counter">${_ungettext("{} Inline", "{} Inline", c.inline_cnt).format(c.inline_cnt)} | ||||
## </a> | ||||
## % else: | ||||
## ${_('0 Inline')} | ||||
## % endif | ||||
## % endif | ||||
## | ||||
## % if pull_request_menu: | ||||
## <% | ||||
## outdated_comm_count_ver = pull_request_menu['outdated_comm_count_ver'] | ||||
## %> | ||||
## | ||||
## % if outdated_comm_count_ver: | ||||
## <a href="#" onclick="showOutdated(); Rhodecode.comments.nextOutdatedComment(); return false;"> | ||||
## (${_("{} Outdated").format(outdated_comm_count_ver)}) | ||||
## </a> | ||||
## <a href="#" class="showOutdatedComments" onclick="showOutdated(this); return false;"> | ${_('show outdated')}</a> | ||||
## <a href="#" class="hideOutdatedComments" style="display: none" onclick="hideOutdated(this); return false;"> | ${_('hide outdated')}</a> | ||||
## % else: | ||||
## (${_("{} Outdated").format(outdated_comm_count_ver)}) | ||||
## % endif | ||||
## | ||||
## % endif | ||||
## | ||||
## </div> | ||||
## </div> | ||||
r3882 | ||||
r1282 | </div> | |||
r3882 | % if diffset.limited_diff: | |||
<div class="diffset-heading ${(diffset.limited_diff and 'diffset-heading-warning' or '')}"> | ||||
<h2 class="clearinner"> | ||||
${_('The requested changes are 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> | ||||
</h2> | ||||
</div> | ||||
% endif | ||||
<div id="todo-box"> | ||||
% if hasattr(c, 'unresolved_comments') and c.unresolved_comments: | ||||
% for co in c.unresolved_comments: | ||||
<a class="permalink" href="#comment-${co.comment_id}" | ||||
onclick="Rhodecode.comments.scrollToComment($('#comment-${co.comment_id}'))"> | ||||
<i class="icon-flag-filled-red"></i> | ||||
${co.comment_id}</a>${('' if loop.last else ',')} | ||||
% endfor | ||||
% endif | ||||
</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): | |||
r4485 | %if filediff.source_file_path and filediff.target_file_path: | |||
%if filediff.source_file_path != filediff.target_file_path: | ||||
## file was renamed, or copied | ||||
%if RENAMED_FILENODE in filediff.patch['stats']['ops']: | ||||
<% | ||||
final_file_name = h.literal(u'{} <i class="icon-angle-left"></i> <del>{}</del>'.format(filediff.target_file_path, filediff.source_file_path)) | ||||
final_path = filediff.target_file_path | ||||
%> | ||||
%elif COPIED_FILENODE in filediff.patch['stats']['ops']: | ||||
<% | ||||
final_file_name = h.literal(u'{} <i class="icon-angle-left"></i> {}'.format(filediff.target_file_path, filediff.source_file_path)) | ||||
final_path = filediff.target_file_path | ||||
%> | ||||
%endif | ||||
%else: | ||||
## file was modified | ||||
<% | ||||
final_file_name = filediff.source_file_path | ||||
final_path = final_file_name | ||||
%> | ||||
%endif | ||||
%else: | ||||
%if filediff.source_file_path: | ||||
## file was deleted | ||||
<% | ||||
final_file_name = filediff.source_file_path | ||||
final_path = final_file_name | ||||
%> | ||||
%else: | ||||
## file was added | ||||
<% | ||||
final_file_name = filediff.target_file_path | ||||
final_path = final_file_name | ||||
%> | ||||
%endif | ||||
%endif | ||||
r1282 | <% | |||
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 | ||||
r3882 | <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filediff)}" type="checkbox" onchange="updateSticky();"> | |||
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"> | ||||
r4380 | <% | |||
file_comments = (get_inline_comments(inline_comments, filediff.patch['filename']) or {}).values() | ||||
r4553 | total_file_comments = [_c for _c in h.itertools.chain.from_iterable(file_comments) if not (_c.outdated or _c.draft)] | |||
r4380 | %> | |||
r3882 | <div class="filediff-collapse-indicator icon-"></div> | |||
r4485 | ||||
## Comments/Options PILL | ||||
<span class="pill-group pull-right"> | ||||
r4411 | <span class="pill" op="comments"> | |||
<i class="icon-comment"></i> ${len(total_file_comments)} | ||||
</span> | ||||
r4485 | ||||
<details class="details-reset details-inline-block"> | ||||
<summary class="noselect"> | ||||
<i class="pill icon-options cursor-pointer" op="options"></i> | ||||
</summary> | ||||
<details-menu class="details-dropdown"> | ||||
<div class="dropdown-item"> | ||||
<span>${final_path}</span> | ||||
<span class="pull-right icon-clipboard clipboard-action" data-clipboard-text="${final_path}" title="Copy file path"></span> | ||||
</div> | ||||
<div class="dropdown-divider"></div> | ||||
<div class="dropdown-item"> | ||||
<% permalink = request.current_route_url(_anchor='a_{}'.format(h.FID(filediff.raw_id, filediff.patch['filename']))) %> | ||||
<a href="${permalink}">¶ permalink</a> | ||||
<span class="pull-right icon-clipboard clipboard-action" data-clipboard-text="${permalink}" title="Copy permalink"></span> | ||||
</div> | ||||
</details-menu> | ||||
</details> | ||||
r4380 | </span> | |||
r4485 | ||||
${diff_ops(final_file_name, filediff)} | ||||
r4380 | ||||
r3081 | </label> | |||
r3126 | ||||
r3081 | ${diff_menu(filediff, use_comments=use_comments)} | |||
r4543 | <table id="file-${h.safeid(h.safe_unicode(filediff.patch['filename']))}" 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 | ||||
r4202 | ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], filediff.hunk_ops, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} | |||
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')}> | |||
r3370 | ${_('The requested commit or file 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: | ||||
r3370 | <tr class="cb-warning cb-collapser"> | |||
<td class="cb-text" ${(c.user_session_attrs["diffmode"] == 'unified' and 'colspan=4' or 'colspan=6')}> | ||||
${_('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'); updateSticky(); return false;">${_('Show them')} | ||||
</a> | ||||
<a href="#" class="cb-collapse" | ||||
onclick="$(this).closest('table').addClass('cb-collapsed'); updateSticky(); return false;">${_('Hide them')} | ||||
</a> | ||||
</td> | ||||
</tr> | ||||
r1282 | %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> | ||||
r4441 | ||||
r4202 | ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} | |||
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> | ||||
r4140 | ${_('Unmatched/outdated inline comments below')} | |||
r3080 | </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"> | ||||
r4202 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)} | |||
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> | ||||
r4140 | ${_('Unmatched/outdated inline comments below')} | |||
r3083 | </div> | |||
</td> | ||||
<td colspan="2"></td> | ||||
<td class="cb-line"> | ||||
r3080 | <div> | |||
r4140 | ${_('Unmatched/outdated comments below')} | |||
r3080 | </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'): | ||||
r4202 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)} | |||
r3080 | % 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'): | ||||
r4202 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries)} | |||
r3080 | % 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(): | ||||
r3937 | ||||
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 = '' | ||||
r3830 | fid = str(id(filename)) | |||
r2808 | %> | |||
<div class="filediffs filediff-outdated" style="${display_state}"> | ||||
r3882 | <input ${(collapse_all and 'checked' or '')} class="filediff-collapse-state collapse-${diffset_container_id}" id="filediff-collapse-${id(filename)}" type="checkbox" onchange="updateSticky();"> | |||
r3830 | <div class="filediff" data-f-path="${filename}" id="a_${h.FID(fid, filename)}"> | |||
r1282 | <label for="filediff-collapse-${id(filename)}" class="filediff-heading"> | |||
r3884 | <div class="filediff-collapse-indicator icon-"></div> | |||
r3830 | ||||
r1282 | <span class="pill"> | |||
## file was deleted | ||||
r3882 | ${filename} | |||
r1282 | </span> | |||
r3882 | <span class="pill-group pull-left" > | |||
r1282 | ## file op, doesn't need translation | |||
r4319 | <span class="pill" op="removed">unresolved comments</span> | |||
r1282 | </span> | |||
r3830 | <a class="pill filediff-anchor" href="#a_${h.FID(fid, filename)}">¶</a> | |||
r3882 | <span class="pill-group pull-right"> | |||
r4319 | <span class="pill" op="deleted"> | |||
% if comments_dict['stats'] >0: | ||||
-${comments_dict['stats']} | ||||
% else: | ||||
${comments_dict['stats']} | ||||
% endif | ||||
</span> | ||||
r1282 | </span> | |||
</label> | ||||
r3882 | <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')}> | |||
r4319 | <strong>${_('This file was removed from diff during updates to this pull-request.')}</strong><br/> | |||
${_('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"> | ||||
r4202 | ${inline_comments_container(comments_dict['comments'], active_pattern_entries=active_pattern_entries)} | |||
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"> | ||||
r4202 | ${inline_comments_container(comments_dict['comments'], active_pattern_entries=active_pattern_entries)} | |||
r1282 | </td> | |||
</tr> | ||||
%endif | ||||
</table> | ||||
</div> | ||||
</div> | ||||
% endfor | ||||
</div> | ||||
</div> | ||||
</%def> | ||||
r4485 | <%def name="diff_ops(file_name, filediff)"> | |||
<% | ||||
from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \ | ||||
MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE | ||||
%> | ||||
r1282 | <span class="pill"> | |||
r3882 | <i class="icon-file-text"></i> | |||
r4485 | ${file_name} | |||
r1282 | </span> | |||
r3116 | ||||
r3882 | <span class="pill-group pull-right"> | |||
r3116 | ||||
## 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"> | ||||
r3146 | ||||
%if filediff.diffset.source_ref: | ||||
## FILE BEFORE CHANGES | ||||
r1844 | %if filediff.operation in ['D', 'M']: | |||
r1282 | <a | |||
class="tooltip" | ||||
r3146 | href="${h.route_path('repo_files',repo_name=filediff.diffset.target_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" | ||||
r3146 | title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" | |||
r1282 | > | |||
${_('Show file before')} | ||||
</span> | | ||||
%endif | ||||
r3146 | ||||
## FILE AFTER CHANGES | ||||
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')} | ||||
r3134 | </a> | |||
r1282 | %else: | |||
<span | ||||
class="tooltip" | ||||
r3146 | title="${h.tooltip(_('File not present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" | |||
r1282 | > | |||
r3134 | ${_('Show file after')} | |||
</span> | ||||
r1282 | %endif | |||
r3134 | ||||
r3146 | % if use_comments: | |||
| | ||||
r4543 | <a href="#" onclick="Rhodecode.comments.toggleDiffComments(this);return toggleElement(this)" | |||
data-toggle-on="${_('Hide comments')}" | ||||
data-toggle-off="${_('Show comments')}"> | ||||
<span class="hide-comment-button">${_('Hide comments')}</span> | ||||
r3146 | </a> | |||
% endif | ||||
r3134 | ||||
r3146 | %endif | |||
r1282 | </div> | |||
</%def> | ||||
r4543 | <%def name="inline_comments_container(comments, active_pattern_entries=None, line_no='', f_path='')"> | |||
r4202 | ||||
r1282 | <div class="inline-comments"> | |||
%for comment in comments: | ||||
r4202 | ${commentblock.comment_block(comment, inline=True, active_pattern_entries=active_pattern_entries)} | |||
r1282 | %endfor | |||
r4543 | ||||
<% | ||||
extra_class = '' | ||||
extra_style = '' | ||||
r4554 | if comments and comments[-1].outdated_at_version(c.at_version_num): | |||
r4543 | extra_class = ' comment-outdated' | |||
extra_style = 'display: none;' | ||||
r1282 | ||||
r4543 | %> | |||
r4554 | ||||
r4543 | <div class="reply-thread-container-wrapper${extra_class}" style="${extra_style}"> | |||
<div class="reply-thread-container${extra_class}"> | ||||
<div class="reply-thread-gravatar"> | ||||
r4572 | % if c.rhodecode_user.username != h.DEFAULT_USER: | |||
r4543 | ${base.gravatar(c.rhodecode_user.email, 20, tooltip=True, user=c.rhodecode_user)} | |||
r4572 | % endif | |||
r4543 | </div> | |||
r4572 | ||||
r4543 | <div class="reply-thread-reply-button"> | |||
r4572 | % if c.rhodecode_user.username != h.DEFAULT_USER: | |||
r4543 | ## initial reply button, some JS logic can append here a FORM to leave a first comment. | |||
<button class="cb-comment-add-button" onclick="return Rhodecode.comments.createComment(this, '${f_path}', '${line_no}', null)">Reply...</button> | ||||
r4572 | % endif | |||
r4543 | </div> | |||
r4572 | ##% endif | |||
r4543 | <div class="reply-thread-last"></div> | |||
</div> | ||||
</div> | ||||
r1282 | </div> | |||
r4543 | ||||
r1282 | </%def> | |||
Bartłomiej Wołyńczyk
|
r2685 | <%! | ||
r4380 | ||||
def get_inline_comments(comments, filename): | ||||
if hasattr(filename, 'unicode_path'): | ||||
filename = filename.unicode_path | ||||
r4973 | if not isinstance(filename, str): | |||
r4380 | return None | |||
if comments and filename in comments: | ||||
return comments[filename] | ||||
return None | ||||
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 | ||||
r4973 | if not isinstance(filename, str): | |||
Bartłomiej Wołyńczyk
|
r2685 | return None | ||
r4380 | file_comments = get_inline_comments(comments, filename) | |||
if file_comments is None: | ||||
return None | ||||
r3080 | ||||
r4380 | line_key = '{}{}'.format(line_version, line_number) ## e.g o37, n12 | |||
if line_key in file_comments: | ||||
data = file_comments.pop(line_key) | ||||
return data | ||||
Bartłomiej Wołyńczyk
|
r2685 | %> | ||
r4202 | <%def name="render_hunk_lines_sideside(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)"> | |||
r4441 | ||||
<% chunk_count = 1 %> | ||||
%for loop_obj, item in h.looper(hunk.sideside): | ||||
r1282 | <% | |||
r4441 | line = item | |||
i = loop_obj.index | ||||
prev_line = loop_obj.previous | ||||
r1282 | old_line_anchor, new_line_anchor = None, None | |||
r3131 | ||||
r1282 | if line.original.lineno: | |||
r3131 | old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, line.original.lineno, 'o') | |||
r1282 | if line.modified.lineno: | |||
r3131 | new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, line.modified.lineno, 'n') | |||
r4441 | ||||
line_action = line.modified.action or line.original.action | ||||
prev_line_action = prev_line and (prev_line.modified.action or prev_line.original.action) | ||||
r1282 | %> | |||
<tr class="cb-line"> | ||||
<td class="cb-data ${action_class(line.original.action)}" | ||||
r2642 | data-line-no="${line.original.lineno}" | |||
r1282 | > | |||
r3080 | ||||
r4540 | <% line_old_comments, line_old_comments_no_drafts = None, None %> | |||
Bartłomiej Wołyńczyk
|
r2685 | %if line.original.get_comment_args: | ||
r4540 | <% | |||
line_old_comments = get_comments_for('side-by-side', inline_comments, *line.original.get_comment_args) | ||||
line_old_comments_no_drafts = [c for c in line_old_comments if not c.draft] if line_old_comments else [] | ||||
has_outdated = any([x.outdated for x in line_old_comments_no_drafts]) | ||||
%> | ||||
Bartłomiej Wołyńczyk
|
r2685 | %endif | ||
r4540 | %if line_old_comments_no_drafts: | |||
r2611 | % if has_outdated: | |||
r4543 | <i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |||
r2611 | % else: | |||
r4543 | <i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(line_old_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |||
r2611 | % endif | |||
r1282 | %endif | |||
</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> | ||||
r4543 | ||||
<% line_no = 'o{}'.format(line.original.lineno) %> | ||||
r1282 | <td class="cb-content ${action_class(line.original.action)}" | |||
r4543 | data-line-no="${line_no}" | |||
r1282 | > | |||
%if use_comments and line.original.lineno: | ||||
r4543 | ${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])} | |||
r1282 | %endif | |||
r3135 | <span class="cb-code"><span class="cb-action ${action_class(line.original.action)}"></span>${line.original.content or '' | n}</span> | |||
Bartłomiej Wołyńczyk
|
r2685 | |||
r3080 | %if use_comments and line.original.lineno and line_old_comments: | |||
r4543 | ${inline_comments_container(line_old_comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])} | |||
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 | |||
r4540 | <% line_new_comments, line_new_comments_no_drafts = None, None %> | |||
Bartłomiej Wołyńczyk
|
r2685 | %if line.modified.get_comment_args: | ||
r4540 | <% | |||
line_new_comments = get_comments_for('side-by-side', inline_comments, *line.modified.get_comment_args) | ||||
line_new_comments_no_drafts = [c for c in line_new_comments if not c.draft] if line_new_comments else [] | ||||
has_outdated = any([x.outdated for x in line_new_comments_no_drafts]) | ||||
%> | ||||
Bartłomiej Wołyńczyk
|
r2685 | %endif | ||
r4419 | ||||
r4540 | %if line_new_comments_no_drafts: | |||
r2611 | % if has_outdated: | |||
r4543 | <i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(line_new_comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |||
r2611 | % else: | |||
r4543 | <i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(line_new_comments_no_drafts))}" 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> | ||||
r4543 | ||||
<% line_no = 'n{}'.format(line.modified.lineno) %> | ||||
r1282 | <td class="cb-content ${action_class(line.modified.action)}" | |||
r4543 | data-line-no="${line_no}" | |||
r1282 | > | |||
%if use_comments and line.modified.lineno: | ||||
r4543 | ${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])} | |||
r1282 | %endif | |||
r3135 | <span class="cb-code"><span class="cb-action ${action_class(line.modified.action)}"></span>${line.modified.content or '' | n}</span> | |||
r4441 | % if line_action in ['+', '-'] and prev_line_action not in ['+', '-']: | |||
<div class="nav-chunk" style="visibility: hidden"> | ||||
<i class="icon-eye" title="viewing diff hunk-${hunk.index}-${chunk_count}"></i> | ||||
</div> | ||||
<% chunk_count +=1 %> | ||||
% endif | ||||
r4543 | %if use_comments and line.modified.lineno and line_new_comments: | |||
${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])} | ||||
%endif | ||||
r1282 | </td> | |||
</tr> | ||||
%endfor | ||||
</%def> | ||||
r4202 | <%def name="render_hunk_lines_unified(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)"> | |||
Bartłomiej Wołyńczyk
|
r2685 | %for old_line_no, new_line_no, action, content, comments_args in hunk.unified: | ||
r3131 | ||||
r1282 | <% | |||
old_line_anchor, new_line_anchor = None, None | ||||
if old_line_no: | ||||
r3131 | old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, old_line_no, 'o') | |||
r1282 | if new_line_no: | |||
r3131 | new_line_anchor = diff_line_anchor(filediff.raw_id, 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 | |||
r4540 | <% comments, comments_no_drafts = None, None %> | |||
%if comments_args: | ||||
<% | ||||
comments = get_comments_for('unified', inline_comments, *comments_args) | ||||
comments_no_drafts = [c for c in line_new_comments if not c.draft] if line_new_comments else [] | ||||
has_outdated = any([x.outdated for x in comments_no_drafts]) | ||||
%> | ||||
%endif | ||||
Bartłomiej Wołyńczyk
|
r2685 | |||
r4540 | % if comments_no_drafts: | |||
% if has_outdated: | ||||
r4543 | <i class="tooltip toggle-comment-action icon-comment-toggle" title="${_('Comments including outdated: {}. Click here to toggle them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |||
r4540 | % else: | |||
r4543 | <i class="tooltip toggle-comment-action icon-comment" title="${_('Comments: {}. Click to toggle them.').format(len(comments_no_drafts))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> | |||
r4540 | % endif | |||
r2611 | % 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> | ||||
r4543 | <% line_no = '{}{}'.format(new_line_no and 'n' or 'o', new_line_no or old_line_no) %> | |||
r1282 | <td class="cb-content ${action_class(action)}" | |||
r4543 | data-line-no="${line_no}" | |||
r1282 | > | |||
%if use_comments: | ||||
r4543 | ${render_add_comment_button(line_no=line_no, f_path=filediff.patch['filename'])} | |||
r1282 | %endif | |||
r3135 | <span class="cb-code"><span class="cb-action ${action_class(action)}"></span> ${content or '' | n}</span> | |||
r1282 | %if use_comments and comments: | |||
r4543 | ${inline_comments_container(comments, active_pattern_entries=active_pattern_entries, line_no=line_no, f_path=filediff.patch['filename'])} | |||
r1282 | %endif | |||
</td> | ||||
</tr> | ||||
%endfor | ||||
</%def> | ||||
r3081 | ||||
r4202 | <%def name="render_hunk_lines(filediff, diff_mode, hunk, use_comments, inline_comments, active_pattern_entries)"> | |||
r3081 | % if diff_mode == 'unified': | |||
r4202 | ${render_hunk_lines_unified(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} | |||
r3081 | % elif diff_mode == 'sideside': | |||
r4202 | ${render_hunk_lines_sideside(filediff, hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} | |||
r3081 | % else: | |||
<tr class="cb-line"> | ||||
<td>unknown diff mode</td> | ||||
</tr> | ||||
% endif | ||||
r3124 | </%def>file changes | |||
r3081 | ||||
r4543 | <%def name="render_add_comment_button(line_no='', f_path='')"> | |||
% if not c.rhodecode_user.is_default: | ||||
<button class="btn btn-small btn-primary cb-comment-box-opener" onclick="return Rhodecode.comments.createComment(this, '${f_path}', '${line_no}', null)"> | ||||
r1282 | <span><i class="icon-comment"></i></span> | |||
</button> | ||||
r4543 | % endif | |||
r1282 | </%def> | |||
r4446 | <%def name="render_diffset_menu(diffset, range_diff_on=None, commit=None, pull_request_menu=None)"> | |||
r3882 | <% diffset_container_id = h.md5(diffset.target_ref) %> | |||
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"> | |||
r4595 | ||||
<div class="btn-group" style="margin-right: 5px;"> | ||||
<a class="tooltip btn" onclick="scrollDown();return false" title="${_('Scroll to page bottom')}"> | ||||
<i class="icon-arrow_down"></i> | ||||
</a> | ||||
<a class="tooltip btn" onclick="scrollUp();return false" title="${_('Scroll to page top')}"> | ||||
<i class="icon-arrow_up"></i> | ||||
</a> | ||||
</div> | ||||
r3882 | <div class="btn-group"> | |||
<a class="btn tooltip toggle-wide-diff" href="#toggle-wide-diff" onclick="toggleWideDiff(this); return false" title="${h.tooltip(_('Toggle wide diff'))}"> | ||||
<i class="icon-wide-mode"></i> | ||||
</a> | ||||
r3134 | </div> | |||
r3882 | <div class="btn-group"> | |||
r3134 | ||||
r1282 | <a | |||
r3882 | class="btn ${(c.user_session_attrs["diffmode"] == 'sideside' and 'btn-active')} tooltip" | |||
title="${h.tooltip(_('View diff as side by side'))}" | ||||
r2307 | href="${h.current_route_path(request, diffmode='sideside')}"> | |||
r1282 | <span>${_('Side by Side')}</span> | |||
</a> | ||||
r3134 | ||||
r1282 | <a | |||
r3882 | class="btn ${(c.user_session_attrs["diffmode"] == 'unified' and 'btn-active')} tooltip" | |||
title="${h.tooltip(_('View diff as unified'))}" href="${h.current_route_path(request, diffmode='unified')}"> | ||||
r1282 | <span>${_('Unified')}</span> | |||
</a> | ||||
r3134 | ||||
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> | |||
r3882 | <div class="btn-group"> | |||
r4590 | <details class="details-reset details-inline-block"> | |||
<summary class="noselect btn"> | ||||
<i class="icon-options cursor-pointer" op="options"></i> | ||||
</summary> | ||||
<div> | ||||
<details-menu class="details-dropdown" style="top: 35px;"> | ||||
<div class="dropdown-item"> | ||||
<div style="padding: 2px 0px"> | ||||
% if request.GET.get('ignorews', '') == '1': | ||||
<a href="${h.current_route_path(request, ignorews=0)}">${_('Show whitespace changes')}</a> | ||||
% else: | ||||
<a href="${h.current_route_path(request, ignorews=1)}">${_('Hide whitespace changes')}</a> | ||||
% endif | ||||
</div> | ||||
</div> | ||||
<div class="dropdown-item"> | ||||
<div style="padding: 2px 0px"> | ||||
% if request.GET.get('fullcontext', '') == '1': | ||||
<a href="${h.current_route_path(request, fullcontext=0)}">${_('Hide full context diff')}</a> | ||||
% else: | ||||
<a href="${h.current_route_path(request, fullcontext=1)}">${_('Show full context diff')}</a> | ||||
% endif | ||||
</div> | ||||
</div> | ||||
</details-menu> | ||||
</div> | ||||
</details> | ||||
r3882 | ||||
</div> | ||||
r1282 | </div> | |||
r3126 | <div class="pull-left"> | |||
<div class="btn-group"> | ||||
r3100 | <div class="pull-left"> | |||
r3882 | ${h.hidden('file_filter_{}'.format(diffset_container_id))} | |||
r3100 | </div> | |||
r3882 | ||||
r3134 | </div> | |||
r3128 | </div> | |||
r1282 | </div> | |||
r4441 | <div class="fpath-placeholder pull-left"> | |||
r3126 | <i class="icon-file-text"></i> | |||
<strong class="fpath-placeholder-text"> | ||||
r3128 | Context file: | |||
r3126 | </strong> | |||
</div> | ||||
r4441 | <div class="pull-right noselect"> | |||
r4446 | %if commit: | |||
<span> | ||||
<code>${h.show_id(commit)}</code> | ||||
</span> | ||||
%elif pull_request_menu and pull_request_menu.get('pull_request'): | ||||
<span> | ||||
<code>!${pull_request_menu['pull_request'].pull_request_id}</code> | ||||
</span> | ||||
%endif | ||||
% if commit or pull_request_menu: | ||||
r4481 | <span class="tooltip" title="Navigate to previous or next change inside files." id="diff_nav">Loading diff...:</span> | |||
r4446 | <span class="cursor-pointer" onclick="scrollToPrevChunk(); return false"> | |||
<i class="icon-angle-up"></i> | ||||
</span> | ||||
<span class="cursor-pointer" onclick="scrollToNextChunk(); return false"> | ||||
<i class="icon-angle-down"></i> | ||||
</span> | ||||
% endif | ||||
r4441 | </div> | |||
r3126 | <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: | |||
r3882 | <% file_placeholder = h.literal(_ungettext('%(num)s file changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>', '%(num)s files changed: <span class="op-added">%(linesadd)s inserted</span>, <span class="op-deleted">%(linesdel)s deleted</span>', | |||
diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}) %> | ||||
r3100 | %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 | ||||
r3882 | <script type="text/javascript"> | |||
r3100 | 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); | ||||
}; | ||||
r3882 | var selectionFormatter = function(data, escapeMarkup) { | |||
var container = '<div class="filelist" style="padding-right:100px">{0}</div>'; | ||||
var tmpl = '<div><strong>{0}</strong></div>'.format(escapeMarkup(data['text'])); | ||||
var pill = '<div class="pill-group" style="position: absolute; top:7px; right: 0">' + | ||||
'<span class="pill" op="added">{0}</span>' + | ||||
'<span class="pill" op="deleted">{1}</span>' + | ||||
'</div>' | ||||
; | ||||
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); | ||||
}; | ||||
r3100 | var formatFileResult = function(result, container, query, escapeMarkup) { | |||
r3882 | return selectionFormatter(result, escapeMarkup); | |||
r3100 | }; | |||
r3163 | ||||
r3882 | var formatSelection = function (data, container) { | |||
return '${file_placeholder}' | ||||
}; | ||||
if (window.preloadFileFilterData === undefined) { | ||||
window.preloadFileFilterData = {} | ||||
} | ||||
preloadFileFilterData["${diffset_container_id}"] = { | ||||
r3100 | results: [ | |||
% for filediff in diffset.files: | ||||
r3124 | {id:"a_${h.FID(filediff.raw_id, filediff.patch['filename'])}", | |||
r3100 | text:"${filediff.patch['filename']}", | |||
r4974 | ops:${h.str_json(filediff.patch['stats'])|n}}${('' if loop.last else ',')} | |||
r3100 | % endfor | |||
] | ||||
}; | ||||
r3882 | var diffFileFilterId = "#file_filter_" + "${diffset_container_id}"; | |||
var diffFileFilter = $(diffFileFilterId).select2({ | ||||
'dropdownAutoWidth': true, | ||||
'width': 'auto', | ||||
containerCssClass: "drop-menu", | ||||
dropdownCssClass: "drop-menu-dropdown", | ||||
data: preloadFileFilterData["${diffset_container_id}"], | ||||
query: function(query) { | ||||
feedFilesOptions(query, preloadFileFilterData["${diffset_container_id}"]); | ||||
}, | ||||
initSelection: function(element, callback) { | ||||
callback({'init': true}); | ||||
}, | ||||
formatResult: formatFileResult, | ||||
formatSelection: formatSelection | ||||
}); | ||||
r3126 | ||||
r3882 | % if range_diff_on is True: | |||
diffFileFilter.select2("enable", false); | ||||
% endif | ||||
$(diffFileFilterId).on('select2-selecting', function (e) { | ||||
var idSelector = e.choice.id; | ||||
// expand the container if we quick-select the field | ||||
$('#'+idSelector).next().prop('checked', false); | ||||
// hide the mast as we later do preventDefault() | ||||
$("#select2-drop-mask").click(); | ||||
r3163 | ||||
r3882 | window.location.hash = '#'+idSelector; | |||
updateSticky(); | ||||
e.preventDefault(); | ||||
}); | ||||
r3126 | ||||
r4446 | diffNavText = 'diff navigation:' | |||
r4441 | getCurrentChunk = function () { | |||
var chunksAll = $('.nav-chunk').filter(function () { | ||||
return $(this).parents('.filediff').prev().get(0).checked !== true | ||||
}) | ||||
var chunkSelected = $('.nav-chunk.selected'); | ||||
var initial = false; | ||||
if (chunkSelected.length === 0) { | ||||
// no initial chunk selected, we pick first | ||||
chunkSelected = $(chunksAll.get(0)); | ||||
var initial = true; | ||||
} | ||||
return { | ||||
'all': chunksAll, | ||||
'selected': chunkSelected, | ||||
'initial': initial, | ||||
} | ||||
} | ||||
animateDiffNavText = function () { | ||||
var $diffNav = $('#diff_nav') | ||||
var callback = function () { | ||||
$diffNav.animate({'opacity': 1.00}, 200) | ||||
}; | ||||
$diffNav.animate({'opacity': 0.15}, 200, callback); | ||||
} | ||||
scrollToChunk = function (moveBy) { | ||||
var chunk = getCurrentChunk(); | ||||
var all = chunk.all | ||||
var selected = chunk.selected | ||||
var curPos = all.index(selected); | ||||
var newPos = curPos; | ||||
if (!chunk.initial) { | ||||
var newPos = curPos + moveBy; | ||||
} | ||||
var curElem = all.get(newPos); | ||||
if (curElem === undefined) { | ||||
// end or back | ||||
r4446 | $('#diff_nav').html('no next diff element:') | |||
r4441 | animateDiffNavText() | |||
return | ||||
} else if (newPos < 0) { | ||||
r4446 | $('#diff_nav').html('no previous diff element:') | |||
r4441 | animateDiffNavText() | |||
return | ||||
} else { | ||||
r4446 | $('#diff_nav').html(diffNavText) | |||
r4441 | } | |||
curElem = $(curElem) | ||||
var offset = 100; | ||||
$(window).scrollTop(curElem.position().top - offset); | ||||
//clear selection | ||||
all.removeClass('selected') | ||||
curElem.addClass('selected') | ||||
} | ||||
scrollToPrevChunk = function () { | ||||
scrollToChunk(-1) | ||||
} | ||||
scrollToNextChunk = function () { | ||||
scrollToChunk(1) | ||||
} | ||||
r3882 | </script> | |||
% endif | ||||
<script type="text/javascript"> | ||||
r4441 | $('#diff_nav').html('loading diff...') // wait until whole page is loaded | |||
r3882 | $(document).ready(function () { | |||
r3126 | ||||
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 | ||||
r3882 | $('.fpath-placeholder-text').html(contextPrefix + ' - ') | |||
r3126 | }); | |||
updateSticky = function () { | ||||
r3129 | sidebar.updateSticky(); | |||
Waypoint.refreshAll(); | ||||
r3126 | }; | |||
r3882 | var animateText = function (fPath, anchorId) { | |||
r3333 | fPath = Select2.util.escapeMarkup(fPath); | |||
r3882 | $('.fpath-placeholder-text').html(contextPrefix + '<a href="#a_' + anchorId + '">' + fPath + '</a>') | |||
}; | ||||
r3126 | ||||
## dynamic file waypoints | ||||
var setFPathInfo = function(fPath, anchorId){ | ||||
animateText(fPath, anchorId) | ||||
}; | ||||
var codeBlock = $('.filediff'); | ||||
r3882 | ||||
r3126 | // forward waypoint | |||
codeBlock.waypoint( | ||||
function(direction) { | ||||
if (direction === "down"){ | ||||
setFPathInfo($(this.element).data('fPath'), $(this.element).data('anchorId')) | ||||
} | ||||
}, { | ||||
r3882 | offset: function () { | |||
return 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 () { | ||||
r3882 | return -this.element.clientHeight + 90; | |||
r3126 | }, | |||
context: '.fpath-placeholder' | ||||
} | ||||
); | ||||
r3882 | toggleWideDiff = function (el) { | |||
updateSticky(); | ||||
var wide = Rhodecode.comments.toggleWideMode(this); | ||||
storeUserSessionAttr('rc_user_session_attr.wide_diff_mode', wide); | ||||
if (wide === true) { | ||||
$(el).addClass('btn-active'); | ||||
} else { | ||||
$(el).removeClass('btn-active'); | ||||
} | ||||
return null; | ||||
}; | ||||
toggleExpand = function (el, diffsetEl) { | ||||
var el = $(el); | ||||
if (el.hasClass('collapsed')) { | ||||
$('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', false); | ||||
el.removeClass('collapsed'); | ||||
el.html( | ||||
'<i class="icon-minus-squared-alt icon-no-margin"></i>' + | ||||
_gettext('Collapse all files')); | ||||
} | ||||
else { | ||||
$('.filediff-collapse-state.collapse-{0}'.format(diffsetEl)).prop('checked', true); | ||||
el.addClass('collapsed'); | ||||
el.html( | ||||
'<i class="icon-plus-squared-alt icon-no-margin"></i>' + | ||||
_gettext('Expand all files')); | ||||
} | ||||
updateSticky() | ||||
r4037 | }; | |||
r4126 | toggleCommitExpand = function (el) { | |||
var $el = $(el); | ||||
var commits = $el.data('toggleCommitsCnt'); | ||||
var collapseMsg = _ngettext('Collapse {0} commit', 'Collapse {0} commits', commits).format(commits); | ||||
var expandMsg = _ngettext('Expand {0} commit', 'Expand {0} commits', commits).format(commits); | ||||
if ($el.hasClass('collapsed')) { | ||||
$('.compare_select').show(); | ||||
$('.compare_select_hidden').hide(); | ||||
$el.removeClass('collapsed'); | ||||
$el.html( | ||||
'<i class="icon-minus-squared-alt icon-no-margin"></i>' + | ||||
collapseMsg); | ||||
} | ||||
else { | ||||
$('.compare_select').hide(); | ||||
$('.compare_select_hidden').show(); | ||||
$el.addClass('collapsed'); | ||||
$el.html( | ||||
'<i class="icon-plus-squared-alt icon-no-margin"></i>' + | ||||
expandMsg); | ||||
} | ||||
updateSticky(); | ||||
}; | ||||
r4037 | // get stored diff mode and pre-enable it | |||
if (templateContext.session_attrs.wide_diff_mode === "true") { | ||||
Rhodecode.comments.toggleWideMode(null); | ||||
$('.toggle-wide-diff').addClass('btn-active'); | ||||
updateSticky(); | ||||
r3882 | } | |||
r4441 | ||||
// DIFF NAV // | ||||
// element to detect scroll direction of | ||||
var $window = $(window); | ||||
// initialize last scroll position | ||||
var lastScrollY = $window.scrollTop(); | ||||
$window.on('resize scrollstop', {latency: 350}, function () { | ||||
var visibleChunks = $('.nav-chunk').withinviewport({top: 75}); | ||||
// get current scroll position | ||||
var currentScrollY = $window.scrollTop(); | ||||
// determine current scroll direction | ||||
if (currentScrollY > lastScrollY) { | ||||
var y = 'down' | ||||
} else if (currentScrollY !== lastScrollY) { | ||||
var y = 'up'; | ||||
} | ||||
var pos = -1; // by default we use last element in viewport | ||||
if (y === 'down') { | ||||
pos = -1; | ||||
} else if (y === 'up') { | ||||
pos = 0; | ||||
} | ||||
if (visibleChunks.length > 0) { | ||||
$('.nav-chunk').removeClass('selected'); | ||||
$(visibleChunks.get(pos)).addClass('selected'); | ||||
} | ||||
// update last scroll position to current position | ||||
lastScrollY = currentScrollY; | ||||
}); | ||||
r4446 | $('#diff_nav').html(diffNavText); | |||
r4441 | ||||
r3100 | }); | |||
</script> | ||||
r3135 | </%def> | |||