Show More
@@ -1,465 +1,469 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 |
|
2 | |||
3 | # Copyright (C) 2010-2016 RhodeCode GmbH |
|
3 | # Copyright (C) 2010-2016 RhodeCode GmbH | |
4 | # |
|
4 | # | |
5 | # This program is free software: you can redistribute it and/or modify |
|
5 | # This program is free software: you can redistribute it and/or modify | |
6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |
7 | # (only), as published by the Free Software Foundation. |
|
7 | # (only), as published by the Free Software Foundation. | |
8 | # |
|
8 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
12 | # GNU General Public License for more details. | |
13 | # |
|
13 | # | |
14 | # You should have received a copy of the GNU Affero General Public License |
|
14 | # You should have received a copy of the GNU Affero General Public License | |
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | # |
|
16 | # | |
17 | # This program is dual-licensed. If you wish to learn more about the |
|
17 | # This program is dual-licensed. If you wish to learn more about the | |
18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |
20 |
|
20 | |||
21 | """ |
|
21 | """ | |
22 | commit controller for RhodeCode showing changes between commits |
|
22 | commit controller for RhodeCode showing changes between commits | |
23 | """ |
|
23 | """ | |
24 |
|
24 | |||
25 | import logging |
|
25 | import logging | |
26 |
|
26 | |||
27 | from collections import defaultdict |
|
27 | from collections import defaultdict | |
28 | from webob.exc import HTTPForbidden, HTTPBadRequest, HTTPNotFound |
|
28 | from webob.exc import HTTPForbidden, HTTPBadRequest, HTTPNotFound | |
29 |
|
29 | |||
30 | from pylons import tmpl_context as c, request, response |
|
30 | from pylons import tmpl_context as c, request, response | |
31 | from pylons.i18n.translation import _ |
|
31 | from pylons.i18n.translation import _ | |
32 | from pylons.controllers.util import redirect |
|
32 | from pylons.controllers.util import redirect | |
33 |
|
33 | |||
34 | from rhodecode.lib import auth |
|
34 | from rhodecode.lib import auth | |
35 | from rhodecode.lib import diffs |
|
35 | from rhodecode.lib import diffs, codeblocks | |
36 | from rhodecode.lib.auth import ( |
|
36 | from rhodecode.lib.auth import ( | |
37 | LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous) |
|
37 | LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous) | |
38 | from rhodecode.lib.base import BaseRepoController, render |
|
38 | from rhodecode.lib.base import BaseRepoController, render | |
39 | from rhodecode.lib.compat import OrderedDict |
|
39 | from rhodecode.lib.compat import OrderedDict | |
40 | from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError |
|
40 | from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError | |
41 | import rhodecode.lib.helpers as h |
|
41 | import rhodecode.lib.helpers as h | |
42 | from rhodecode.lib.utils import action_logger, jsonify |
|
42 | from rhodecode.lib.utils import action_logger, jsonify | |
43 | from rhodecode.lib.utils2 import safe_unicode |
|
43 | from rhodecode.lib.utils2 import safe_unicode | |
44 | from rhodecode.lib.vcs.backends.base import EmptyCommit |
|
44 | from rhodecode.lib.vcs.backends.base import EmptyCommit | |
45 | from rhodecode.lib.vcs.exceptions import ( |
|
45 | from rhodecode.lib.vcs.exceptions import ( | |
46 | RepositoryError, CommitDoesNotExistError) |
|
46 | RepositoryError, CommitDoesNotExistError) | |
47 | from rhodecode.model.db import ChangesetComment, ChangesetStatus |
|
47 | from rhodecode.model.db import ChangesetComment, ChangesetStatus | |
48 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
48 | from rhodecode.model.changeset_status import ChangesetStatusModel | |
49 | from rhodecode.model.comment import ChangesetCommentsModel |
|
49 | from rhodecode.model.comment import ChangesetCommentsModel | |
50 | from rhodecode.model.meta import Session |
|
50 | from rhodecode.model.meta import Session | |
51 | from rhodecode.model.repo import RepoModel |
|
51 | from rhodecode.model.repo import RepoModel | |
52 |
|
52 | |||
53 |
|
53 | |||
54 | log = logging.getLogger(__name__) |
|
54 | log = logging.getLogger(__name__) | |
55 |
|
55 | |||
56 |
|
56 | |||
57 | def _update_with_GET(params, GET): |
|
57 | def _update_with_GET(params, GET): | |
58 | for k in ['diff1', 'diff2', 'diff']: |
|
58 | for k in ['diff1', 'diff2', 'diff']: | |
59 | params[k] += GET.getall(k) |
|
59 | params[k] += GET.getall(k) | |
60 |
|
60 | |||
61 |
|
61 | |||
62 | def get_ignore_ws(fid, GET): |
|
62 | def get_ignore_ws(fid, GET): | |
63 | ig_ws_global = GET.get('ignorews') |
|
63 | ig_ws_global = GET.get('ignorews') | |
64 | ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid)) |
|
64 | ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid)) | |
65 | if ig_ws: |
|
65 | if ig_ws: | |
66 | try: |
|
66 | try: | |
67 | return int(ig_ws[0].split(':')[-1]) |
|
67 | return int(ig_ws[0].split(':')[-1]) | |
68 | except Exception: |
|
68 | except Exception: | |
69 | pass |
|
69 | pass | |
70 | return ig_ws_global |
|
70 | return ig_ws_global | |
71 |
|
71 | |||
72 |
|
72 | |||
73 | def _ignorews_url(GET, fileid=None): |
|
73 | def _ignorews_url(GET, fileid=None): | |
74 | fileid = str(fileid) if fileid else None |
|
74 | fileid = str(fileid) if fileid else None | |
75 | params = defaultdict(list) |
|
75 | params = defaultdict(list) | |
76 | _update_with_GET(params, GET) |
|
76 | _update_with_GET(params, GET) | |
77 | label = _('Show whitespace') |
|
77 | label = _('Show whitespace') | |
78 | tooltiplbl = _('Show whitespace for all diffs') |
|
78 | tooltiplbl = _('Show whitespace for all diffs') | |
79 | ig_ws = get_ignore_ws(fileid, GET) |
|
79 | ig_ws = get_ignore_ws(fileid, GET) | |
80 | ln_ctx = get_line_ctx(fileid, GET) |
|
80 | ln_ctx = get_line_ctx(fileid, GET) | |
81 |
|
81 | |||
82 | if ig_ws is None: |
|
82 | if ig_ws is None: | |
83 | params['ignorews'] += [1] |
|
83 | params['ignorews'] += [1] | |
84 | label = _('Ignore whitespace') |
|
84 | label = _('Ignore whitespace') | |
85 | tooltiplbl = _('Ignore whitespace for all diffs') |
|
85 | tooltiplbl = _('Ignore whitespace for all diffs') | |
86 | ctx_key = 'context' |
|
86 | ctx_key = 'context' | |
87 | ctx_val = ln_ctx |
|
87 | ctx_val = ln_ctx | |
88 |
|
88 | |||
89 | # if we have passed in ln_ctx pass it along to our params |
|
89 | # if we have passed in ln_ctx pass it along to our params | |
90 | if ln_ctx: |
|
90 | if ln_ctx: | |
91 | params[ctx_key] += [ctx_val] |
|
91 | params[ctx_key] += [ctx_val] | |
92 |
|
92 | |||
93 | if fileid: |
|
93 | if fileid: | |
94 | params['anchor'] = 'a_' + fileid |
|
94 | params['anchor'] = 'a_' + fileid | |
95 | return h.link_to(label, h.url.current(**params), title=tooltiplbl, class_='tooltip') |
|
95 | return h.link_to(label, h.url.current(**params), title=tooltiplbl, class_='tooltip') | |
96 |
|
96 | |||
97 |
|
97 | |||
98 | def get_line_ctx(fid, GET): |
|
98 | def get_line_ctx(fid, GET): | |
99 | ln_ctx_global = GET.get('context') |
|
99 | ln_ctx_global = GET.get('context') | |
100 | if fid: |
|
100 | if fid: | |
101 | ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid)) |
|
101 | ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid)) | |
102 | else: |
|
102 | else: | |
103 | _ln_ctx = filter(lambda k: k.startswith('C'), GET) |
|
103 | _ln_ctx = filter(lambda k: k.startswith('C'), GET) | |
104 | ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx else ln_ctx_global |
|
104 | ln_ctx = GET.get(_ln_ctx[0]) if _ln_ctx else ln_ctx_global | |
105 | if ln_ctx: |
|
105 | if ln_ctx: | |
106 | ln_ctx = [ln_ctx] |
|
106 | ln_ctx = [ln_ctx] | |
107 |
|
107 | |||
108 | if ln_ctx: |
|
108 | if ln_ctx: | |
109 | retval = ln_ctx[0].split(':')[-1] |
|
109 | retval = ln_ctx[0].split(':')[-1] | |
110 | else: |
|
110 | else: | |
111 | retval = ln_ctx_global |
|
111 | retval = ln_ctx_global | |
112 |
|
112 | |||
113 | try: |
|
113 | try: | |
114 | return int(retval) |
|
114 | return int(retval) | |
115 | except Exception: |
|
115 | except Exception: | |
116 | return 3 |
|
116 | return 3 | |
117 |
|
117 | |||
118 |
|
118 | |||
119 | def _context_url(GET, fileid=None): |
|
119 | def _context_url(GET, fileid=None): | |
120 | """ |
|
120 | """ | |
121 | Generates a url for context lines. |
|
121 | Generates a url for context lines. | |
122 |
|
122 | |||
123 | :param fileid: |
|
123 | :param fileid: | |
124 | """ |
|
124 | """ | |
125 |
|
125 | |||
126 | fileid = str(fileid) if fileid else None |
|
126 | fileid = str(fileid) if fileid else None | |
127 | ig_ws = get_ignore_ws(fileid, GET) |
|
127 | ig_ws = get_ignore_ws(fileid, GET) | |
128 | ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2 |
|
128 | ln_ctx = (get_line_ctx(fileid, GET) or 3) * 2 | |
129 |
|
129 | |||
130 | params = defaultdict(list) |
|
130 | params = defaultdict(list) | |
131 | _update_with_GET(params, GET) |
|
131 | _update_with_GET(params, GET) | |
132 |
|
132 | |||
133 | if ln_ctx > 0: |
|
133 | if ln_ctx > 0: | |
134 | params['context'] += [ln_ctx] |
|
134 | params['context'] += [ln_ctx] | |
135 |
|
135 | |||
136 | if ig_ws: |
|
136 | if ig_ws: | |
137 | ig_ws_key = 'ignorews' |
|
137 | ig_ws_key = 'ignorews' | |
138 | ig_ws_val = 1 |
|
138 | ig_ws_val = 1 | |
139 | params[ig_ws_key] += [ig_ws_val] |
|
139 | params[ig_ws_key] += [ig_ws_val] | |
140 |
|
140 | |||
141 | lbl = _('Increase context') |
|
141 | lbl = _('Increase context') | |
142 | tooltiplbl = _('Increase context for all diffs') |
|
142 | tooltiplbl = _('Increase context for all diffs') | |
143 |
|
143 | |||
144 | if fileid: |
|
144 | if fileid: | |
145 | params['anchor'] = 'a_' + fileid |
|
145 | params['anchor'] = 'a_' + fileid | |
146 | return h.link_to(lbl, h.url.current(**params), title=tooltiplbl, class_='tooltip') |
|
146 | return h.link_to(lbl, h.url.current(**params), title=tooltiplbl, class_='tooltip') | |
147 |
|
147 | |||
148 |
|
148 | |||
149 | class ChangesetController(BaseRepoController): |
|
149 | class ChangesetController(BaseRepoController): | |
150 |
|
150 | |||
151 | def __before__(self): |
|
151 | def __before__(self): | |
152 | super(ChangesetController, self).__before__() |
|
152 | super(ChangesetController, self).__before__() | |
153 | c.affected_files_cut_off = 60 |
|
153 | c.affected_files_cut_off = 60 | |
154 |
|
154 | |||
155 | def _index(self, commit_id_range, method): |
|
155 | def _index(self, commit_id_range, method): | |
156 | c.ignorews_url = _ignorews_url |
|
156 | c.ignorews_url = _ignorews_url | |
157 | c.context_url = _context_url |
|
157 | c.context_url = _context_url | |
158 | c.fulldiff = fulldiff = request.GET.get('fulldiff') |
|
158 | c.fulldiff = fulldiff = request.GET.get('fulldiff') | |
159 | # get ranges of commit ids if preset |
|
159 | # get ranges of commit ids if preset | |
160 | commit_range = commit_id_range.split('...')[:2] |
|
160 | commit_range = commit_id_range.split('...')[:2] | |
161 | enable_comments = True |
|
161 | enable_comments = True | |
162 | try: |
|
162 | try: | |
163 | pre_load = ['affected_files', 'author', 'branch', 'date', |
|
163 | pre_load = ['affected_files', 'author', 'branch', 'date', | |
164 | 'message', 'parents'] |
|
164 | 'message', 'parents'] | |
165 |
|
165 | |||
166 | if len(commit_range) == 2: |
|
166 | if len(commit_range) == 2: | |
167 | enable_comments = False |
|
167 | enable_comments = False | |
168 | commits = c.rhodecode_repo.get_commits( |
|
168 | commits = c.rhodecode_repo.get_commits( | |
169 | start_id=commit_range[0], end_id=commit_range[1], |
|
169 | start_id=commit_range[0], end_id=commit_range[1], | |
170 | pre_load=pre_load) |
|
170 | pre_load=pre_load) | |
171 | commits = list(commits) |
|
171 | commits = list(commits) | |
172 | else: |
|
172 | else: | |
173 | commits = [c.rhodecode_repo.get_commit( |
|
173 | commits = [c.rhodecode_repo.get_commit( | |
174 | commit_id=commit_id_range, pre_load=pre_load)] |
|
174 | commit_id=commit_id_range, pre_load=pre_load)] | |
175 |
|
175 | |||
176 | c.commit_ranges = commits |
|
176 | c.commit_ranges = commits | |
177 | if not c.commit_ranges: |
|
177 | if not c.commit_ranges: | |
178 | raise RepositoryError( |
|
178 | raise RepositoryError( | |
179 | 'The commit range returned an empty result') |
|
179 | 'The commit range returned an empty result') | |
180 | except CommitDoesNotExistError: |
|
180 | except CommitDoesNotExistError: | |
181 | msg = _('No such commit exists for this repository') |
|
181 | msg = _('No such commit exists for this repository') | |
182 | h.flash(msg, category='error') |
|
182 | h.flash(msg, category='error') | |
183 | raise HTTPNotFound() |
|
183 | raise HTTPNotFound() | |
184 | except Exception: |
|
184 | except Exception: | |
185 | log.exception("General failure") |
|
185 | log.exception("General failure") | |
186 | raise HTTPNotFound() |
|
186 | raise HTTPNotFound() | |
187 |
|
187 | |||
188 | c.changes = OrderedDict() |
|
188 | c.changes = OrderedDict() | |
189 | c.lines_added = 0 |
|
189 | c.lines_added = 0 | |
190 | c.lines_deleted = 0 |
|
190 | c.lines_deleted = 0 | |
191 |
|
191 | |||
192 | c.commit_statuses = ChangesetStatus.STATUSES |
|
192 | c.commit_statuses = ChangesetStatus.STATUSES | |
193 | c.comments = [] |
|
193 | c.comments = [] | |
194 | c.statuses = [] |
|
194 | c.statuses = [] | |
195 | c.inline_comments = [] |
|
195 | c.inline_comments = [] | |
196 | c.inline_cnt = 0 |
|
196 | c.inline_cnt = 0 | |
197 | c.files = [] |
|
197 | c.files = [] | |
198 |
|
198 | |||
199 | # Iterate over ranges (default commit view is always one commit) |
|
199 | # Iterate over ranges (default commit view is always one commit) | |
200 | for commit in c.commit_ranges: |
|
200 | for commit in c.commit_ranges: | |
201 | if method == 'show': |
|
201 | if method == 'show': | |
202 | c.statuses.extend([ChangesetStatusModel().get_status( |
|
202 | c.statuses.extend([ChangesetStatusModel().get_status( | |
203 | c.rhodecode_db_repo.repo_id, commit.raw_id)]) |
|
203 | c.rhodecode_db_repo.repo_id, commit.raw_id)]) | |
204 |
|
204 | |||
205 | c.comments.extend(ChangesetCommentsModel().get_comments( |
|
205 | c.comments.extend(ChangesetCommentsModel().get_comments( | |
206 | c.rhodecode_db_repo.repo_id, |
|
206 | c.rhodecode_db_repo.repo_id, | |
207 | revision=commit.raw_id)) |
|
207 | revision=commit.raw_id)) | |
208 |
|
208 | |||
209 | # comments from PR |
|
209 | # comments from PR | |
210 | st = ChangesetStatusModel().get_statuses( |
|
210 | st = ChangesetStatusModel().get_statuses( | |
211 | c.rhodecode_db_repo.repo_id, commit.raw_id, |
|
211 | c.rhodecode_db_repo.repo_id, commit.raw_id, | |
212 | with_revisions=True) |
|
212 | with_revisions=True) | |
213 |
|
213 | |||
214 | # from associated statuses, check the pull requests, and |
|
214 | # from associated statuses, check the pull requests, and | |
215 | # show comments from them |
|
215 | # show comments from them | |
216 |
|
216 | |||
217 | prs = set(x.pull_request for x in |
|
217 | prs = set(x.pull_request for x in | |
218 | filter(lambda x: x.pull_request is not None, st)) |
|
218 | filter(lambda x: x.pull_request is not None, st)) | |
219 | for pr in prs: |
|
219 | for pr in prs: | |
220 | c.comments.extend(pr.comments) |
|
220 | c.comments.extend(pr.comments) | |
221 |
|
221 | |||
222 | inlines = ChangesetCommentsModel().get_inline_comments( |
|
222 | inlines = ChangesetCommentsModel().get_inline_comments( | |
223 | c.rhodecode_db_repo.repo_id, revision=commit.raw_id) |
|
223 | c.rhodecode_db_repo.repo_id, revision=commit.raw_id) | |
224 | c.inline_comments.extend(inlines.iteritems()) |
|
224 | c.inline_comments.extend(inlines.iteritems()) | |
225 |
|
225 | |||
226 | c.changes[commit.raw_id] = [] |
|
226 | c.changes[commit.raw_id] = [] | |
227 |
|
227 | |||
228 | commit2 = commit |
|
228 | commit2 = commit | |
229 | commit1 = commit.parents[0] if commit.parents else EmptyCommit() |
|
229 | commit1 = commit.parents[0] if commit.parents else EmptyCommit() | |
230 |
|
230 | |||
231 | # fetch global flags of ignore ws or context lines |
|
231 | # fetch global flags of ignore ws or context lines | |
232 | context_lcl = get_line_ctx('', request.GET) |
|
232 | context_lcl = get_line_ctx('', request.GET) | |
233 | ign_whitespace_lcl = get_ignore_ws('', request.GET) |
|
233 | ign_whitespace_lcl = get_ignore_ws('', request.GET) | |
234 |
|
234 | |||
235 | _diff = c.rhodecode_repo.get_diff( |
|
235 | _diff = c.rhodecode_repo.get_diff( | |
236 | commit1, commit2, |
|
236 | commit1, commit2, | |
237 | ignore_whitespace=ign_whitespace_lcl, context=context_lcl) |
|
237 | ignore_whitespace=ign_whitespace_lcl, context=context_lcl) | |
238 |
|
238 | |||
239 | # diff_limit will cut off the whole diff if the limit is applied |
|
239 | # diff_limit will cut off the whole diff if the limit is applied | |
240 | # otherwise it will just hide the big files from the front-end |
|
240 | # otherwise it will just hide the big files from the front-end | |
241 | diff_limit = self.cut_off_limit_diff |
|
241 | diff_limit = self.cut_off_limit_diff | |
242 | file_limit = self.cut_off_limit_file |
|
242 | file_limit = self.cut_off_limit_file | |
243 |
|
243 | |||
244 | diff_processor = diffs.DiffProcessor( |
|
244 | diff_processor = diffs.DiffProcessor( | |
245 |
_diff, format=' |
|
245 | _diff, format='newdiff', diff_limit=diff_limit, | |
246 | file_limit=file_limit, show_full_diff=fulldiff) |
|
246 | file_limit=file_limit, show_full_diff=fulldiff) | |
247 | commit_changes = OrderedDict() |
|
247 | commit_changes = OrderedDict() | |
248 | if method == 'show': |
|
248 | if method == 'show': | |
249 | _parsed = diff_processor.prepare() |
|
249 | _parsed = diff_processor.prepare() | |
250 | c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer) |
|
250 | c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer) | |
251 | for f in _parsed: |
|
251 | ||
252 | c.files.append(f) |
|
252 | _parsed = diff_processor.prepare() | |
253 | st = f['stats'] |
|
253 | ||
254 | c.lines_added += st['added'] |
|
254 | def _node_getter(commit): | |
255 | c.lines_deleted += st['deleted'] |
|
255 | def get_node(fname): | |
256 | fid = h.FID(commit.raw_id, f['filename']) |
|
256 | try: | |
257 | diff = diff_processor.as_html(enable_comments=enable_comments, |
|
257 | return commit.get_node(fname) | |
258 | parsed_lines=[f]) |
|
258 | except NodeDoesNotExistError: | |
259 | commit_changes[fid] = [ |
|
259 | return None | |
260 | commit1.raw_id, commit2.raw_id, |
|
260 | return get_node | |
261 | f['operation'], f['filename'], diff, st, f] |
|
261 | ||
|
262 | diffset = codeblocks.DiffSet( | |||
|
263 | source_node_getter=_node_getter(commit1), | |||
|
264 | target_node_getter=_node_getter(commit2), | |||
|
265 | ).render_patchset(_parsed, commit1.raw_id, commit2.raw_id) | |||
|
266 | c.changes[commit.raw_id] = diffset | |||
262 | else: |
|
267 | else: | |
263 | # downloads/raw we only need RAW diff nothing else |
|
268 | # downloads/raw we only need RAW diff nothing else | |
264 | diff = diff_processor.as_raw() |
|
269 | diff = diff_processor.as_raw() | |
265 |
c |
|
270 | c.changes[commit.raw_id] = [None, None, None, None, diff, None, None] | |
266 | c.changes[commit.raw_id] = commit_changes |
|
|||
267 |
|
271 | |||
268 | # sort comments by how they were generated |
|
272 | # sort comments by how they were generated | |
269 | c.comments = sorted(c.comments, key=lambda x: x.comment_id) |
|
273 | c.comments = sorted(c.comments, key=lambda x: x.comment_id) | |
270 |
|
274 | |||
271 | # count inline comments |
|
275 | # count inline comments | |
272 | for __, lines in c.inline_comments: |
|
276 | for __, lines in c.inline_comments: | |
273 | for comments in lines.values(): |
|
277 | for comments in lines.values(): | |
274 | c.inline_cnt += len(comments) |
|
278 | c.inline_cnt += len(comments) | |
275 |
|
279 | |||
276 | if len(c.commit_ranges) == 1: |
|
280 | if len(c.commit_ranges) == 1: | |
277 | c.commit = c.commit_ranges[0] |
|
281 | c.commit = c.commit_ranges[0] | |
278 | c.parent_tmpl = ''.join( |
|
282 | c.parent_tmpl = ''.join( | |
279 | '# Parent %s\n' % x.raw_id for x in c.commit.parents) |
|
283 | '# Parent %s\n' % x.raw_id for x in c.commit.parents) | |
280 | if method == 'download': |
|
284 | if method == 'download': | |
281 | response.content_type = 'text/plain' |
|
285 | response.content_type = 'text/plain' | |
282 | response.content_disposition = ( |
|
286 | response.content_disposition = ( | |
283 | 'attachment; filename=%s.diff' % commit_id_range[:12]) |
|
287 | 'attachment; filename=%s.diff' % commit_id_range[:12]) | |
284 | return diff |
|
288 | return diff | |
285 | elif method == 'patch': |
|
289 | elif method == 'patch': | |
286 | response.content_type = 'text/plain' |
|
290 | response.content_type = 'text/plain' | |
287 | c.diff = safe_unicode(diff) |
|
291 | c.diff = safe_unicode(diff) | |
288 | return render('changeset/patch_changeset.html') |
|
292 | return render('changeset/patch_changeset.html') | |
289 | elif method == 'raw': |
|
293 | elif method == 'raw': | |
290 | response.content_type = 'text/plain' |
|
294 | response.content_type = 'text/plain' | |
291 | return diff |
|
295 | return diff | |
292 | elif method == 'show': |
|
296 | elif method == 'show': | |
293 | if len(c.commit_ranges) == 1: |
|
297 | if len(c.commit_ranges) == 1: | |
294 | return render('changeset/changeset.html') |
|
298 | return render('changeset/changeset.html') | |
295 | else: |
|
299 | else: | |
296 | c.ancestor = None |
|
300 | c.ancestor = None | |
297 | c.target_repo = c.rhodecode_db_repo |
|
301 | c.target_repo = c.rhodecode_db_repo | |
298 | return render('changeset/changeset_range.html') |
|
302 | return render('changeset/changeset_range.html') | |
299 |
|
303 | |||
300 | @LoginRequired() |
|
304 | @LoginRequired() | |
301 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
305 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
302 | 'repository.admin') |
|
306 | 'repository.admin') | |
303 | def index(self, revision, method='show'): |
|
307 | def index(self, revision, method='show'): | |
304 | return self._index(revision, method=method) |
|
308 | return self._index(revision, method=method) | |
305 |
|
309 | |||
306 | @LoginRequired() |
|
310 | @LoginRequired() | |
307 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
311 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
308 | 'repository.admin') |
|
312 | 'repository.admin') | |
309 | def changeset_raw(self, revision): |
|
313 | def changeset_raw(self, revision): | |
310 | return self._index(revision, method='raw') |
|
314 | return self._index(revision, method='raw') | |
311 |
|
315 | |||
312 | @LoginRequired() |
|
316 | @LoginRequired() | |
313 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
317 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
314 | 'repository.admin') |
|
318 | 'repository.admin') | |
315 | def changeset_patch(self, revision): |
|
319 | def changeset_patch(self, revision): | |
316 | return self._index(revision, method='patch') |
|
320 | return self._index(revision, method='patch') | |
317 |
|
321 | |||
318 | @LoginRequired() |
|
322 | @LoginRequired() | |
319 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
323 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
320 | 'repository.admin') |
|
324 | 'repository.admin') | |
321 | def changeset_download(self, revision): |
|
325 | def changeset_download(self, revision): | |
322 | return self._index(revision, method='download') |
|
326 | return self._index(revision, method='download') | |
323 |
|
327 | |||
324 | @LoginRequired() |
|
328 | @LoginRequired() | |
325 | @NotAnonymous() |
|
329 | @NotAnonymous() | |
326 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
330 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
327 | 'repository.admin') |
|
331 | 'repository.admin') | |
328 | @auth.CSRFRequired() |
|
332 | @auth.CSRFRequired() | |
329 | @jsonify |
|
333 | @jsonify | |
330 | def comment(self, repo_name, revision): |
|
334 | def comment(self, repo_name, revision): | |
331 | commit_id = revision |
|
335 | commit_id = revision | |
332 | status = request.POST.get('changeset_status', None) |
|
336 | status = request.POST.get('changeset_status', None) | |
333 | text = request.POST.get('text') |
|
337 | text = request.POST.get('text') | |
334 | if status: |
|
338 | if status: | |
335 | text = text or (_('Status change %(transition_icon)s %(status)s') |
|
339 | text = text or (_('Status change %(transition_icon)s %(status)s') | |
336 | % {'transition_icon': '>', |
|
340 | % {'transition_icon': '>', | |
337 | 'status': ChangesetStatus.get_status_lbl(status)}) |
|
341 | 'status': ChangesetStatus.get_status_lbl(status)}) | |
338 |
|
342 | |||
339 | multi_commit_ids = filter( |
|
343 | multi_commit_ids = filter( | |
340 | lambda s: s not in ['', None], |
|
344 | lambda s: s not in ['', None], | |
341 | request.POST.get('commit_ids', '').split(','),) |
|
345 | request.POST.get('commit_ids', '').split(','),) | |
342 |
|
346 | |||
343 | commit_ids = multi_commit_ids or [commit_id] |
|
347 | commit_ids = multi_commit_ids or [commit_id] | |
344 | comment = None |
|
348 | comment = None | |
345 | for current_id in filter(None, commit_ids): |
|
349 | for current_id in filter(None, commit_ids): | |
346 | c.co = comment = ChangesetCommentsModel().create( |
|
350 | c.co = comment = ChangesetCommentsModel().create( | |
347 | text=text, |
|
351 | text=text, | |
348 | repo=c.rhodecode_db_repo.repo_id, |
|
352 | repo=c.rhodecode_db_repo.repo_id, | |
349 | user=c.rhodecode_user.user_id, |
|
353 | user=c.rhodecode_user.user_id, | |
350 | revision=current_id, |
|
354 | revision=current_id, | |
351 | f_path=request.POST.get('f_path'), |
|
355 | f_path=request.POST.get('f_path'), | |
352 | line_no=request.POST.get('line'), |
|
356 | line_no=request.POST.get('line'), | |
353 | status_change=(ChangesetStatus.get_status_lbl(status) |
|
357 | status_change=(ChangesetStatus.get_status_lbl(status) | |
354 | if status else None), |
|
358 | if status else None), | |
355 | status_change_type=status |
|
359 | status_change_type=status | |
356 | ) |
|
360 | ) | |
357 | # get status if set ! |
|
361 | # get status if set ! | |
358 | if status: |
|
362 | if status: | |
359 | # if latest status was from pull request and it's closed |
|
363 | # if latest status was from pull request and it's closed | |
360 | # disallow changing status ! |
|
364 | # disallow changing status ! | |
361 | # dont_allow_on_closed_pull_request = True ! |
|
365 | # dont_allow_on_closed_pull_request = True ! | |
362 |
|
366 | |||
363 | try: |
|
367 | try: | |
364 | ChangesetStatusModel().set_status( |
|
368 | ChangesetStatusModel().set_status( | |
365 | c.rhodecode_db_repo.repo_id, |
|
369 | c.rhodecode_db_repo.repo_id, | |
366 | status, |
|
370 | status, | |
367 | c.rhodecode_user.user_id, |
|
371 | c.rhodecode_user.user_id, | |
368 | comment, |
|
372 | comment, | |
369 | revision=current_id, |
|
373 | revision=current_id, | |
370 | dont_allow_on_closed_pull_request=True |
|
374 | dont_allow_on_closed_pull_request=True | |
371 | ) |
|
375 | ) | |
372 | except StatusChangeOnClosedPullRequestError: |
|
376 | except StatusChangeOnClosedPullRequestError: | |
373 | msg = _('Changing the status of a commit associated with ' |
|
377 | msg = _('Changing the status of a commit associated with ' | |
374 | 'a closed pull request is not allowed') |
|
378 | 'a closed pull request is not allowed') | |
375 | log.exception(msg) |
|
379 | log.exception(msg) | |
376 | h.flash(msg, category='warning') |
|
380 | h.flash(msg, category='warning') | |
377 | return redirect(h.url( |
|
381 | return redirect(h.url( | |
378 | 'changeset_home', repo_name=repo_name, |
|
382 | 'changeset_home', repo_name=repo_name, | |
379 | revision=current_id)) |
|
383 | revision=current_id)) | |
380 |
|
384 | |||
381 | # finalize, commit and redirect |
|
385 | # finalize, commit and redirect | |
382 | Session().commit() |
|
386 | Session().commit() | |
383 |
|
387 | |||
384 | data = { |
|
388 | data = { | |
385 | 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), |
|
389 | 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), | |
386 | } |
|
390 | } | |
387 | if comment: |
|
391 | if comment: | |
388 | data.update(comment.get_dict()) |
|
392 | data.update(comment.get_dict()) | |
389 | data.update({'rendered_text': |
|
393 | data.update({'rendered_text': | |
390 | render('changeset/changeset_comment_block.html')}) |
|
394 | render('changeset/changeset_comment_block.html')}) | |
391 |
|
395 | |||
392 | return data |
|
396 | return data | |
393 |
|
397 | |||
394 | @LoginRequired() |
|
398 | @LoginRequired() | |
395 | @NotAnonymous() |
|
399 | @NotAnonymous() | |
396 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
400 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
397 | 'repository.admin') |
|
401 | 'repository.admin') | |
398 | @auth.CSRFRequired() |
|
402 | @auth.CSRFRequired() | |
399 | def preview_comment(self): |
|
403 | def preview_comment(self): | |
400 | # Technically a CSRF token is not needed as no state changes with this |
|
404 | # Technically a CSRF token is not needed as no state changes with this | |
401 | # call. However, as this is a POST is better to have it, so automated |
|
405 | # call. However, as this is a POST is better to have it, so automated | |
402 | # tools don't flag it as potential CSRF. |
|
406 | # tools don't flag it as potential CSRF. | |
403 | # Post is required because the payload could be bigger than the maximum |
|
407 | # Post is required because the payload could be bigger than the maximum | |
404 | # allowed by GET. |
|
408 | # allowed by GET. | |
405 | if not request.environ.get('HTTP_X_PARTIAL_XHR'): |
|
409 | if not request.environ.get('HTTP_X_PARTIAL_XHR'): | |
406 | raise HTTPBadRequest() |
|
410 | raise HTTPBadRequest() | |
407 | text = request.POST.get('text') |
|
411 | text = request.POST.get('text') | |
408 | renderer = request.POST.get('renderer') or 'rst' |
|
412 | renderer = request.POST.get('renderer') or 'rst' | |
409 | if text: |
|
413 | if text: | |
410 | return h.render(text, renderer=renderer, mentions=True) |
|
414 | return h.render(text, renderer=renderer, mentions=True) | |
411 | return '' |
|
415 | return '' | |
412 |
|
416 | |||
413 | @LoginRequired() |
|
417 | @LoginRequired() | |
414 | @NotAnonymous() |
|
418 | @NotAnonymous() | |
415 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
419 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
416 | 'repository.admin') |
|
420 | 'repository.admin') | |
417 | @auth.CSRFRequired() |
|
421 | @auth.CSRFRequired() | |
418 | @jsonify |
|
422 | @jsonify | |
419 | def delete_comment(self, repo_name, comment_id): |
|
423 | def delete_comment(self, repo_name, comment_id): | |
420 | comment = ChangesetComment.get(comment_id) |
|
424 | comment = ChangesetComment.get(comment_id) | |
421 | owner = (comment.author.user_id == c.rhodecode_user.user_id) |
|
425 | owner = (comment.author.user_id == c.rhodecode_user.user_id) | |
422 | is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) |
|
426 | is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) | |
423 | if h.HasPermissionAny('hg.admin')() or is_repo_admin or owner: |
|
427 | if h.HasPermissionAny('hg.admin')() or is_repo_admin or owner: | |
424 | ChangesetCommentsModel().delete(comment=comment) |
|
428 | ChangesetCommentsModel().delete(comment=comment) | |
425 | Session().commit() |
|
429 | Session().commit() | |
426 | return True |
|
430 | return True | |
427 | else: |
|
431 | else: | |
428 | raise HTTPForbidden() |
|
432 | raise HTTPForbidden() | |
429 |
|
433 | |||
430 | @LoginRequired() |
|
434 | @LoginRequired() | |
431 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
435 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
432 | 'repository.admin') |
|
436 | 'repository.admin') | |
433 | @jsonify |
|
437 | @jsonify | |
434 | def changeset_info(self, repo_name, revision): |
|
438 | def changeset_info(self, repo_name, revision): | |
435 | if request.is_xhr: |
|
439 | if request.is_xhr: | |
436 | try: |
|
440 | try: | |
437 | return c.rhodecode_repo.get_commit(commit_id=revision) |
|
441 | return c.rhodecode_repo.get_commit(commit_id=revision) | |
438 | except CommitDoesNotExistError as e: |
|
442 | except CommitDoesNotExistError as e: | |
439 | return EmptyCommit(message=str(e)) |
|
443 | return EmptyCommit(message=str(e)) | |
440 | else: |
|
444 | else: | |
441 | raise HTTPBadRequest() |
|
445 | raise HTTPBadRequest() | |
442 |
|
446 | |||
443 | @LoginRequired() |
|
447 | @LoginRequired() | |
444 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
448 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
445 | 'repository.admin') |
|
449 | 'repository.admin') | |
446 | @jsonify |
|
450 | @jsonify | |
447 | def changeset_children(self, repo_name, revision): |
|
451 | def changeset_children(self, repo_name, revision): | |
448 | if request.is_xhr: |
|
452 | if request.is_xhr: | |
449 | commit = c.rhodecode_repo.get_commit(commit_id=revision) |
|
453 | commit = c.rhodecode_repo.get_commit(commit_id=revision) | |
450 | result = {"results": commit.children} |
|
454 | result = {"results": commit.children} | |
451 | return result |
|
455 | return result | |
452 | else: |
|
456 | else: | |
453 | raise HTTPBadRequest() |
|
457 | raise HTTPBadRequest() | |
454 |
|
458 | |||
455 | @LoginRequired() |
|
459 | @LoginRequired() | |
456 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
460 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
457 | 'repository.admin') |
|
461 | 'repository.admin') | |
458 | @jsonify |
|
462 | @jsonify | |
459 | def changeset_parents(self, repo_name, revision): |
|
463 | def changeset_parents(self, repo_name, revision): | |
460 | if request.is_xhr: |
|
464 | if request.is_xhr: | |
461 | commit = c.rhodecode_repo.get_commit(commit_id=revision) |
|
465 | commit = c.rhodecode_repo.get_commit(commit_id=revision) | |
462 | result = {"results": commit.parents} |
|
466 | result = {"results": commit.parents} | |
463 | return result |
|
467 | return result | |
464 | else: |
|
468 | else: | |
465 | raise HTTPBadRequest() |
|
469 | raise HTTPBadRequest() |
@@ -1,395 +1,317 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
2 |
|
2 | |||
3 | <%inherit file="/base/base.html"/> |
|
3 | <%inherit file="/base/base.html"/> | |
4 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> |
|
4 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> | |
5 |
|
5 | |||
6 | <%def name="title()"> |
|
6 | <%def name="title()"> | |
7 | ${_('%s Commit') % c.repo_name} - ${h.show_id(c.commit)} |
|
7 | ${_('%s Commit') % c.repo_name} - ${h.show_id(c.commit)} | |
8 | %if c.rhodecode_name: |
|
8 | %if c.rhodecode_name: | |
9 | · ${h.branding(c.rhodecode_name)} |
|
9 | · ${h.branding(c.rhodecode_name)} | |
10 | %endif |
|
10 | %endif | |
11 | </%def> |
|
11 | </%def> | |
12 |
|
12 | |||
13 | <%def name="menu_bar_nav()"> |
|
13 | <%def name="menu_bar_nav()"> | |
14 | ${self.menu_items(active='repositories')} |
|
14 | ${self.menu_items(active='repositories')} | |
15 | </%def> |
|
15 | </%def> | |
16 |
|
16 | |||
17 | <%def name="menu_bar_subnav()"> |
|
17 | <%def name="menu_bar_subnav()"> | |
18 | ${self.repo_menu(active='changelog')} |
|
18 | ${self.repo_menu(active='changelog')} | |
19 | </%def> |
|
19 | </%def> | |
20 |
|
20 | |||
21 | <%def name="main()"> |
|
21 | <%def name="main()"> | |
22 | <script> |
|
22 | <script> | |
23 | // TODO: marcink switch this to pyroutes |
|
23 | // TODO: marcink switch this to pyroutes | |
24 | AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}"; |
|
24 | AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}"; | |
25 | templateContext.commit_data.commit_id = "${c.commit.raw_id}"; |
|
25 | templateContext.commit_data.commit_id = "${c.commit.raw_id}"; | |
26 | </script> |
|
26 | </script> | |
27 | <div class="box"> |
|
27 | <div class="box"> | |
28 | <div class="title"> |
|
28 | <div class="title"> | |
29 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
29 | ${self.repo_page_title(c.rhodecode_db_repo)} | |
30 | </div> |
|
30 | </div> | |
31 |
|
31 | |||
32 | <div id="changeset_compare_view_content" class="summary changeset"> |
|
32 | <div id="changeset_compare_view_content" class="summary changeset"> | |
33 | <div class="summary-detail"> |
|
33 | <div class="summary-detail"> | |
34 | <div class="summary-detail-header"> |
|
34 | <div class="summary-detail-header"> | |
35 | <span class="breadcrumbs files_location"> |
|
35 | <span class="breadcrumbs files_location"> | |
36 | <h4>${_('Commit')} |
|
36 | <h4>${_('Commit')} | |
37 | <code> |
|
37 | <code> | |
38 | ${h.show_id(c.commit)} |
|
38 | ${h.show_id(c.commit)} | |
39 | </code> |
|
39 | </code> | |
40 | </h4> |
|
40 | </h4> | |
41 | </span> |
|
41 | </span> | |
42 | <span id="parent_link"> |
|
42 | <span id="parent_link"> | |
43 | <a href="#" title="${_('Parent Commit')}">${_('Parent')}</a> |
|
43 | <a href="#" title="${_('Parent Commit')}">${_('Parent')}</a> | |
44 | </span> |
|
44 | </span> | |
45 |
| |
|
45 | | | |
46 | <span id="child_link"> |
|
46 | <span id="child_link"> | |
47 | <a href="#" title="${_('Child Commit')}">${_('Child')}</a> |
|
47 | <a href="#" title="${_('Child Commit')}">${_('Child')}</a> | |
48 | </span> |
|
48 | </span> | |
49 | </div> |
|
49 | </div> | |
50 |
|
50 | |||
51 | <div class="fieldset"> |
|
51 | <div class="fieldset"> | |
52 | <div class="left-label"> |
|
52 | <div class="left-label"> | |
53 | ${_('Description')}: |
|
53 | ${_('Description')}: | |
54 | </div> |
|
54 | </div> | |
55 | <div class="right-content"> |
|
55 | <div class="right-content"> | |
56 | <div id="trimmed_message_box" class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div> |
|
56 | <div id="trimmed_message_box" class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div> | |
57 | <div id="message_expand" style="display:none;"> |
|
57 | <div id="message_expand" style="display:none;"> | |
58 | ${_('Expand')} |
|
58 | ${_('Expand')} | |
59 | </div> |
|
59 | </div> | |
60 | </div> |
|
60 | </div> | |
61 | </div> |
|
61 | </div> | |
62 |
|
62 | |||
63 | %if c.statuses: |
|
63 | %if c.statuses: | |
64 | <div class="fieldset"> |
|
64 | <div class="fieldset"> | |
65 | <div class="left-label"> |
|
65 | <div class="left-label"> | |
66 | ${_('Commit status')}: |
|
66 | ${_('Commit status')}: | |
67 | </div> |
|
67 | </div> | |
68 | <div class="right-content"> |
|
68 | <div class="right-content"> | |
69 | <div class="changeset-status-ico"> |
|
69 | <div class="changeset-status-ico"> | |
70 | <div class="${'flag_status %s' % c.statuses[0]} pull-left"></div> |
|
70 | <div class="${'flag_status %s' % c.statuses[0]} pull-left"></div> | |
71 | </div> |
|
71 | </div> | |
72 | <div title="${_('Commit status')}" class="changeset-status-lbl">[${h.commit_status_lbl(c.statuses[0])}]</div> |
|
72 | <div title="${_('Commit status')}" class="changeset-status-lbl">[${h.commit_status_lbl(c.statuses[0])}]</div> | |
73 | </div> |
|
73 | </div> | |
74 | </div> |
|
74 | </div> | |
75 | %endif |
|
75 | %endif | |
76 |
|
76 | |||
77 | <div class="fieldset"> |
|
77 | <div class="fieldset"> | |
78 | <div class="left-label"> |
|
78 | <div class="left-label"> | |
79 | ${_('References')}: |
|
79 | ${_('References')}: | |
80 | </div> |
|
80 | </div> | |
81 | <div class="right-content"> |
|
81 | <div class="right-content"> | |
82 | <div class="tags"> |
|
82 | <div class="tags"> | |
83 |
|
83 | |||
84 | %if c.commit.merge: |
|
84 | %if c.commit.merge: | |
85 | <span class="mergetag tag"> |
|
85 | <span class="mergetag tag"> | |
86 | <i class="icon-merge"></i>${_('merge')} |
|
86 | <i class="icon-merge"></i>${_('merge')} | |
87 | </span> |
|
87 | </span> | |
88 | %endif |
|
88 | %endif | |
89 |
|
89 | |||
90 | %if h.is_hg(c.rhodecode_repo): |
|
90 | %if h.is_hg(c.rhodecode_repo): | |
91 | %for book in c.commit.bookmarks: |
|
91 | %for book in c.commit.bookmarks: | |
92 | <span class="booktag tag" title="${_('Bookmark %s') % book}"> |
|
92 | <span class="booktag tag" title="${_('Bookmark %s') % book}"> | |
93 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a> |
|
93 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a> | |
94 | </span> |
|
94 | </span> | |
95 | %endfor |
|
95 | %endfor | |
96 | %endif |
|
96 | %endif | |
97 |
|
97 | |||
98 | %for tag in c.commit.tags: |
|
98 | %for tag in c.commit.tags: | |
99 | <span class="tagtag tag" title="${_('Tag %s') % tag}"> |
|
99 | <span class="tagtag tag" title="${_('Tag %s') % tag}"> | |
100 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-tag"></i>${tag}</a> |
|
100 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-tag"></i>${tag}</a> | |
101 | </span> |
|
101 | </span> | |
102 | %endfor |
|
102 | %endfor | |
103 |
|
103 | |||
104 | %if c.commit.branch: |
|
104 | %if c.commit.branch: | |
105 | <span class="branchtag tag" title="${_('Branch %s') % c.commit.branch}"> |
|
105 | <span class="branchtag tag" title="${_('Branch %s') % c.commit.branch}"> | |
106 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-code-fork"></i>${h.shorter(c.commit.branch)}</a> |
|
106 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-code-fork"></i>${h.shorter(c.commit.branch)}</a> | |
107 | </span> |
|
107 | </span> | |
108 | %endif |
|
108 | %endif | |
109 | </div> |
|
109 | </div> | |
110 | </div> |
|
110 | </div> | |
111 | </div> |
|
111 | </div> | |
112 |
|
112 | |||
113 | <div class="fieldset"> |
|
113 | <div class="fieldset"> | |
114 | <div class="left-label"> |
|
114 | <div class="left-label"> | |
115 | ${_('Diffs')}: |
|
115 | ${_('Diffs')}: | |
116 | </div> |
|
116 | </div> | |
117 | <div class="right-content"> |
|
117 | <div class="right-content"> | |
118 | <div class="diff-actions"> |
|
118 | <div class="diff-actions"> | |
119 | <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> |
|
119 | <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> | |
120 | ${_('Raw Diff')} |
|
120 | ${_('Raw Diff')} | |
121 | </a> |
|
121 | </a> | |
122 |
| |
|
122 | | | |
123 | <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> |
|
123 | <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> | |
124 | ${_('Patch Diff')} |
|
124 | ${_('Patch Diff')} | |
125 | </a> |
|
125 | </a> | |
126 |
| |
|
126 | | | |
127 | <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision=c.commit.raw_id,diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"> |
|
127 | <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision=c.commit.raw_id,diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"> | |
128 | ${_('Download Diff')} |
|
128 | ${_('Download Diff')} | |
129 | </a> |
|
129 | </a> | |
130 |
| |
|
130 | | | |
131 | ${c.ignorews_url(request.GET)} |
|
131 | ${c.ignorews_url(request.GET)} | |
132 |
| |
|
132 | | | |
133 | ${c.context_url(request.GET)} |
|
133 | ${c.context_url(request.GET)} | |
134 | </div> |
|
134 | </div> | |
135 | </div> |
|
135 | </div> | |
136 | </div> |
|
136 | </div> | |
137 |
|
137 | |||
138 | <div class="fieldset"> |
|
138 | <div class="fieldset"> | |
139 | <div class="left-label"> |
|
139 | <div class="left-label"> | |
140 | ${_('Comments')}: |
|
140 | ${_('Comments')}: | |
141 | </div> |
|
141 | </div> | |
142 | <div class="right-content"> |
|
142 | <div class="right-content"> | |
143 | <div class="comments-number"> |
|
143 | <div class="comments-number"> | |
144 | %if c.comments: |
|
144 | %if c.comments: | |
145 | <a href="#comments">${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}</a>, |
|
145 | <a href="#comments">${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}</a>, | |
146 | %else: |
|
146 | %else: | |
147 | ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)} |
|
147 | ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)} | |
148 | %endif |
|
148 | %endif | |
149 | %if c.inline_cnt: |
|
149 | %if c.inline_cnt: | |
150 | ## this is replaced with a proper link to first comment via JS linkifyComments() func |
|
150 | ## this is replaced with a proper link to first comment via JS linkifyComments() func | |
151 | <a href="#inline-comments" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a> |
|
151 | <a href="#inline-comments" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a> | |
152 | %else: |
|
152 | %else: | |
153 | ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} |
|
153 | ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} | |
154 | %endif |
|
154 | %endif | |
155 | </div> |
|
155 | </div> | |
156 | </div> |
|
156 | </div> | |
157 | </div> |
|
157 | </div> | |
158 |
|
158 | |||
159 | </div> <!-- end summary-detail --> |
|
159 | </div> <!-- end summary-detail --> | |
160 |
|
160 | |||
161 | <div id="commit-stats" class="sidebar-right"> |
|
161 | <div id="commit-stats" class="sidebar-right"> | |
162 | <div class="summary-detail-header"> |
|
162 | <div class="summary-detail-header"> | |
163 | <h4 class="item"> |
|
163 | <h4 class="item"> | |
164 | ${_('Author')} |
|
164 | ${_('Author')} | |
165 | </h4> |
|
165 | </h4> | |
166 | </div> |
|
166 | </div> | |
167 | <div class="sidebar-right-content"> |
|
167 | <div class="sidebar-right-content"> | |
168 | ${self.gravatar_with_user(c.commit.author)} |
|
168 | ${self.gravatar_with_user(c.commit.author)} | |
169 | <div class="user-inline-data">- ${h.age_component(c.commit.date)}</div> |
|
169 | <div class="user-inline-data">- ${h.age_component(c.commit.date)}</div> | |
170 | </div> |
|
170 | </div> | |
171 | </div><!-- end sidebar --> |
|
171 | </div><!-- end sidebar --> | |
172 | </div> <!-- end summary --> |
|
172 | </div> <!-- end summary --> | |
173 |
<div class="cs_files |
|
173 | <div class="cs_files"> | |
174 | <span class="cs_files_expand"> |
|
174 | ${cbdiffs.render_diffset_menu()} | |
175 | <span id="files_link"><a href="#" title="${_('Browse files at current commit')}">${_('Browse files')}</a></span> | |
|
|||
176 |
|
||||
177 | <span id="expand_all_files">${_('Expand All')}</span> | <span id="collapse_all_files">${_('Collapse All')}</span> |
|
|||
178 | </span> |
|
|||
179 | <h2> |
|
|||
180 | ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)} |
|
|||
181 | </h2> |
|
|||
182 | </div> |
|
|||
183 | </div> |
|
|||
184 |
|
||||
185 | <div class="cs_files"> |
|
|||
186 |
|
||||
187 | %if not c.files: |
|
|||
188 | <p class="empty_data">${_('No files')}</p> |
|
|||
189 | %endif |
|
|||
190 |
|
175 | |||
191 | <table class="compare_view_files commit_diff"> |
|
176 | <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/> | |
192 | %for FID, (cs1, cs2, change, path, diff, stats, file) in c.changes[c.commit.raw_id].iteritems(): |
|
177 | ${cbdiffs.render_diffset(c.changes[c.commit.raw_id], commit=c.commit)} | |
193 | <tr class="cs_${change} collapse_file" fid="${FID}"> |
|
178 | </div> | |
194 | <td class="cs_icon_td"> |
|
|||
195 | <span class="collapse_file_icon" fid="${FID}"></span> |
|
|||
196 | </td> |
|
|||
197 | <td class="cs_icon_td"> |
|
|||
198 | <div class="flag_status not_reviewed hidden"></div> |
|
|||
199 | </td> |
|
|||
200 | <td class="cs_${change}" id="a_${FID}"> |
|
|||
201 | <div class="node"> |
|
|||
202 | <a href="#a_${FID}"> |
|
|||
203 | <i class="icon-file-${change.lower()}"></i> |
|
|||
204 | ${h.safe_unicode(path)} |
|
|||
205 | </a> |
|
|||
206 | </div> |
|
|||
207 | </td> |
|
|||
208 | <td> |
|
|||
209 | <div class="changes pull-right">${h.fancy_file_stats(stats)}</div> |
|
|||
210 | <div class="comment-bubble pull-right" data-path="${path}"> |
|
|||
211 | <i class="icon-comment"></i> |
|
|||
212 | </div> |
|
|||
213 | </td> |
|
|||
214 | </tr> |
|
|||
215 | <tr fid="${FID}" id="diff_${FID}" class="diff_links"> |
|
|||
216 | <td></td> |
|
|||
217 | <td></td> |
|
|||
218 | <td class="cs_${change}"> |
|
|||
219 | ${diff_block.diff_menu(c.repo_name, h.safe_unicode(path), cs1, cs2, change, file)} |
|
|||
220 | </td> |
|
|||
221 | <td class="td-actions rc-form"> |
|
|||
222 | ${c.ignorews_url(request.GET, h.FID(cs2,path))} | |
|
|||
223 | ${c.context_url(request.GET, h.FID(cs2,path))} | |
|
|||
224 | <div data-comment-id="${h.FID(cs2,path)}" class="btn-link show-inline-comments comments-visible"> |
|
|||
225 | <span class="comments-show">${_('Show comments')}</span> |
|
|||
226 | <span class="comments-hide">${_('Hide comments')}</span> |
|
|||
227 | </div> |
|
|||
228 | </td> |
|
|||
229 | </tr> |
|
|||
230 | <tr id="tr_${FID}"> |
|
|||
231 | <td></td> |
|
|||
232 | <td></td> |
|
|||
233 | <td class="injected_diff" colspan="2"> |
|
|||
234 | <div class="diff-container" id="${'diff-container-%s' % (id(change))}"> |
|
|||
235 | <div id="${FID}" class="diffblock margined comm"> |
|
|||
236 | <div class="code-body"> |
|
|||
237 | <div class="full_f_path" path="${h.safe_unicode(path)}"></div> |
|
|||
238 | ${diff|n} |
|
|||
239 | % if file and file["is_limited_diff"]: |
|
|||
240 | % if file["exceeds_limit"]: |
|
|||
241 | ${diff_block.file_message()} |
|
|||
242 | % else: |
|
|||
243 | <h5>${_('Diff was truncated. File content available only in full diff.')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a></h5> |
|
|||
244 | % endif |
|
|||
245 | % endif |
|
|||
246 | </div> |
|
|||
247 | </div> |
|
|||
248 | </div> |
|
|||
249 | </td> |
|
|||
250 | </tr> |
|
|||
251 | %endfor |
|
|||
252 | </table> |
|
|||
253 | </div> |
|
179 | </div> | |
254 |
|
180 | |||
255 | % if c.limited_diff: |
|
|||
256 | ${diff_block.changeset_message()} |
|
|||
257 | % endif |
|
|||
258 |
|
||||
259 | ## template for inline comment form |
|
181 | ## template for inline comment form | |
260 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
182 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> | |
261 | ${comment.comment_inline_form()} |
|
183 | ${comment.comment_inline_form()} | |
262 |
|
184 | |||
263 | ## render comments and inlines |
|
185 | ## render comments and inlines | |
264 | ${comment.generate_comments()} |
|
186 | ${comment.generate_comments()} | |
265 |
|
187 | |||
266 | ## main comment form and it status |
|
188 | ## main comment form and it status | |
267 | ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id), |
|
189 | ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id), | |
268 | h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))} |
|
190 | h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))} | |
269 |
|
191 | |||
270 | ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS |
|
192 | ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS | |
271 | <script type="text/javascript"> |
|
193 | <script type="text/javascript"> | |
272 |
|
194 | |||
273 | $(document).ready(function() { |
|
195 | $(document).ready(function() { | |
274 |
|
196 | |||
275 | var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10); |
|
197 | var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10); | |
276 | if($('#trimmed_message_box').height() === boxmax){ |
|
198 | if($('#trimmed_message_box').height() === boxmax){ | |
277 | $('#message_expand').show(); |
|
199 | $('#message_expand').show(); | |
278 | } |
|
200 | } | |
279 |
|
201 | |||
280 | $('#message_expand').on('click', function(e){ |
|
202 | $('#message_expand').on('click', function(e){ | |
281 | $('#trimmed_message_box').css('max-height', 'none'); |
|
203 | $('#trimmed_message_box').css('max-height', 'none'); | |
282 | $(this).hide(); |
|
204 | $(this).hide(); | |
283 | }); |
|
205 | }); | |
284 |
|
206 | |||
285 | $('.show-inline-comments').on('click', function(e){ |
|
207 | $('.show-inline-comments').on('click', function(e){ | |
286 | var boxid = $(this).attr('data-comment-id'); |
|
208 | var boxid = $(this).attr('data-comment-id'); | |
287 | var button = $(this); |
|
209 | var button = $(this); | |
288 |
|
210 | |||
289 | if(button.hasClass("comments-visible")) { |
|
211 | if(button.hasClass("comments-visible")) { | |
290 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ |
|
212 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ | |
291 | $(this).hide(); |
|
213 | $(this).hide(); | |
292 | }) |
|
214 | }) | |
293 | button.removeClass("comments-visible"); |
|
215 | button.removeClass("comments-visible"); | |
294 | } else { |
|
216 | } else { | |
295 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ |
|
217 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ | |
296 | $(this).show(); |
|
218 | $(this).show(); | |
297 | }) |
|
219 | }) | |
298 | button.addClass("comments-visible"); |
|
220 | button.addClass("comments-visible"); | |
299 | } |
|
221 | } | |
300 | }); |
|
222 | }); | |
301 |
|
223 | |||
302 |
|
224 | |||
303 | // next links |
|
225 | // next links | |
304 | $('#child_link').on('click', function(e){ |
|
226 | $('#child_link').on('click', function(e){ | |
305 | // fetch via ajax what is going to be the next link, if we have |
|
227 | // fetch via ajax what is going to be the next link, if we have | |
306 | // >1 links show them to user to choose |
|
228 | // >1 links show them to user to choose | |
307 | if(!$('#child_link').hasClass('disabled')){ |
|
229 | if(!$('#child_link').hasClass('disabled')){ | |
308 | $.ajax({ |
|
230 | $.ajax({ | |
309 | url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}', |
|
231 | url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}', | |
310 | success: function(data) { |
|
232 | success: function(data) { | |
311 | if(data.results.length === 0){ |
|
233 | if(data.results.length === 0){ | |
312 | $('#child_link').html('${_('No Child Commits')}').addClass('disabled'); |
|
234 | $('#child_link').html('${_('No Child Commits')}').addClass('disabled'); | |
313 | } |
|
235 | } | |
314 | if(data.results.length === 1){ |
|
236 | if(data.results.length === 1){ | |
315 | var commit = data.results[0]; |
|
237 | var commit = data.results[0]; | |
316 | window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id}); |
|
238 | window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id}); | |
317 | } |
|
239 | } | |
318 | else if(data.results.length === 2){ |
|
240 | else if(data.results.length === 2){ | |
319 | $('#child_link').addClass('disabled'); |
|
241 | $('#child_link').addClass('disabled'); | |
320 | $('#child_link').addClass('double'); |
|
242 | $('#child_link').addClass('double'); | |
321 | var _html = ''; |
|
243 | var _html = ''; | |
322 | _html +='<a title="__title__" href="__url__">__rev__</a> ' |
|
244 | _html +='<a title="__title__" href="__url__">__rev__</a> ' | |
323 | .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6))) |
|
245 | .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6))) | |
324 | .replace('__title__', data.results[0].message) |
|
246 | .replace('__title__', data.results[0].message) | |
325 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id})); |
|
247 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id})); | |
326 | _html +=' | ' |
|
248 | _html +=' | ' | |
327 | _html +='<a title="__title__" href="__url__">__rev__</a> ' |
|
249 | _html +='<a title="__title__" href="__url__">__rev__</a> ' | |
328 | .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6))) |
|
250 | .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6))) | |
329 | .replace('__title__', data.results[1].message) |
|
251 | .replace('__title__', data.results[1].message) | |
330 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id})); |
|
252 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id})); | |
331 | $('#child_link').html(_html); |
|
253 | $('#child_link').html(_html); | |
332 | } |
|
254 | } | |
333 | } |
|
255 | } | |
334 | }); |
|
256 | }); | |
335 | e.preventDefault(); |
|
257 | e.preventDefault(); | |
336 | } |
|
258 | } | |
337 | }); |
|
259 | }); | |
338 |
|
260 | |||
339 | // prev links |
|
261 | // prev links | |
340 | $('#parent_link').on('click', function(e){ |
|
262 | $('#parent_link').on('click', function(e){ | |
341 | // fetch via ajax what is going to be the next link, if we have |
|
263 | // fetch via ajax what is going to be the next link, if we have | |
342 | // >1 links show them to user to choose |
|
264 | // >1 links show them to user to choose | |
343 | if(!$('#parent_link').hasClass('disabled')){ |
|
265 | if(!$('#parent_link').hasClass('disabled')){ | |
344 | $.ajax({ |
|
266 | $.ajax({ | |
345 | url: '${h.url('changeset_parents',repo_name=c.repo_name, revision=c.commit.raw_id)}', |
|
267 | url: '${h.url('changeset_parents',repo_name=c.repo_name, revision=c.commit.raw_id)}', | |
346 | success: function(data) { |
|
268 | success: function(data) { | |
347 | if(data.results.length === 0){ |
|
269 | if(data.results.length === 0){ | |
348 | $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled'); |
|
270 | $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled'); | |
349 | } |
|
271 | } | |
350 | if(data.results.length === 1){ |
|
272 | if(data.results.length === 1){ | |
351 | var commit = data.results[0]; |
|
273 | var commit = data.results[0]; | |
352 | window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id}); |
|
274 | window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id}); | |
353 | } |
|
275 | } | |
354 | else if(data.results.length === 2){ |
|
276 | else if(data.results.length === 2){ | |
355 | $('#parent_link').addClass('disabled'); |
|
277 | $('#parent_link').addClass('disabled'); | |
356 | $('#parent_link').addClass('double'); |
|
278 | $('#parent_link').addClass('double'); | |
357 | var _html = ''; |
|
279 | var _html = ''; | |
358 | _html +='<a title="__title__" href="__url__">Parent __rev__</a>' |
|
280 | _html +='<a title="__title__" href="__url__">Parent __rev__</a>' | |
359 | .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6))) |
|
281 | .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6))) | |
360 | .replace('__title__', data.results[0].message) |
|
282 | .replace('__title__', data.results[0].message) | |
361 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id})); |
|
283 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id})); | |
362 | _html +=' | ' |
|
284 | _html +=' | ' | |
363 | _html +='<a title="__title__" href="__url__">Parent __rev__</a>' |
|
285 | _html +='<a title="__title__" href="__url__">Parent __rev__</a>' | |
364 | .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6))) |
|
286 | .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6))) | |
365 | .replace('__title__', data.results[1].message) |
|
287 | .replace('__title__', data.results[1].message) | |
366 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id})); |
|
288 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id})); | |
367 | $('#parent_link').html(_html); |
|
289 | $('#parent_link').html(_html); | |
368 | } |
|
290 | } | |
369 | } |
|
291 | } | |
370 | }); |
|
292 | }); | |
371 | e.preventDefault(); |
|
293 | e.preventDefault(); | |
372 | } |
|
294 | } | |
373 | }); |
|
295 | }); | |
374 |
|
296 | |||
375 | if (location.hash) { |
|
297 | if (location.hash) { | |
376 | var result = splitDelimitedHash(location.hash); |
|
298 | var result = splitDelimitedHash(location.hash); | |
377 | var line = $('html').find(result.loc); |
|
299 | var line = $('html').find(result.loc); | |
378 | if (line.length > 0){ |
|
300 | if (line.length > 0){ | |
379 | offsetScroll(line, 70); |
|
301 | offsetScroll(line, 70); | |
380 | } |
|
302 | } | |
381 | } |
|
303 | } | |
382 |
|
304 | |||
383 | // browse tree @ revision |
|
305 | // browse tree @ revision | |
384 | $('#files_link').on('click', function(e){ |
|
306 | $('#files_link').on('click', function(e){ | |
385 | window.location = '${h.url('files_home',repo_name=c.repo_name, revision=c.commit.raw_id, f_path='')}'; |
|
307 | window.location = '${h.url('files_home',repo_name=c.repo_name, revision=c.commit.raw_id, f_path='')}'; | |
386 | e.preventDefault(); |
|
308 | e.preventDefault(); | |
387 | }); |
|
309 | }); | |
388 |
|
310 | |||
389 | // inject comments into their proper positions |
|
311 | // inject comments into their proper positions | |
390 | var file_comments = $('.inline-comment-placeholder'); |
|
312 | var file_comments = $('.inline-comment-placeholder'); | |
391 | renderInlineComments(file_comments, true); |
|
313 | renderInlineComments(file_comments, true); | |
392 | }) |
|
314 | }) | |
393 | </script> |
|
315 | </script> | |
394 |
|
316 | |||
395 | </%def> |
|
317 | </%def> |
@@ -1,126 +1,71 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
2 | <%inherit file="/base/base.html"/> |
|
2 | <%inherit file="/base/base.html"/> | |
3 |
|
3 | |||
4 | <%def name="title()"> |
|
4 | <%def name="title()"> | |
5 | ${_('%s Commits') % c.repo_name} - |
|
5 | ${_('%s Commits') % c.repo_name} - | |
6 | r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)} |
|
6 | r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)} | |
7 | ... |
|
7 | ... | |
8 | r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} |
|
8 | r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} | |
9 | ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} |
|
9 | ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} | |
10 | %if c.rhodecode_name: |
|
10 | %if c.rhodecode_name: | |
11 | · ${h.branding(c.rhodecode_name)} |
|
11 | · ${h.branding(c.rhodecode_name)} | |
12 | %endif |
|
12 | %endif | |
13 | </%def> |
|
13 | </%def> | |
14 |
|
14 | |||
15 | <%def name="breadcrumbs_links()"> |
|
15 | <%def name="breadcrumbs_links()"> | |
16 | ${_('Commits')} - |
|
16 | ${_('Commits')} - | |
17 | r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)} |
|
17 | r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)} | |
18 | ... |
|
18 | ... | |
19 | r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} |
|
19 | r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} | |
20 | ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} |
|
20 | ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} | |
21 | </%def> |
|
21 | </%def> | |
22 |
|
22 | |||
23 | <%def name="menu_bar_nav()"> |
|
23 | <%def name="menu_bar_nav()"> | |
24 | ${self.menu_items(active='repositories')} |
|
24 | ${self.menu_items(active='repositories')} | |
25 | </%def> |
|
25 | </%def> | |
26 |
|
26 | |||
27 | <%def name="menu_bar_subnav()"> |
|
27 | <%def name="menu_bar_subnav()"> | |
28 | ${self.repo_menu(active='changelog')} |
|
28 | ${self.repo_menu(active='changelog')} | |
29 | </%def> |
|
29 | </%def> | |
30 |
|
30 | |||
31 | <%def name="main()"> |
|
31 | <%def name="main()"> | |
32 | <div class="summary-header"> |
|
32 | <div class="summary-header"> | |
33 | <div class="title"> |
|
33 | <div class="title"> | |
34 | <div class="title-content"> |
|
34 | <div class="title-content"> | |
35 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
35 | ${self.repo_page_title(c.rhodecode_db_repo)} | |
36 | </div> |
|
36 | </div> | |
37 | </div> |
|
37 | </div> | |
38 | <div class="header-buttons"> |
|
38 | <div class="header-buttons"> | |
39 | <a href="${h.url('compare_url', repo_name=c.repo_name, source_ref_type='rev', source_ref=getattr(c.commit_ranges[0].parents[0] if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id'), target_ref_type='rev', target_ref=c.commit_ranges[-1].raw_id)}" |
|
39 | <a href="${h.url('compare_url', repo_name=c.repo_name, source_ref_type='rev', source_ref=getattr(c.commit_ranges[0].parents[0] if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id'), target_ref_type='rev', target_ref=c.commit_ranges[-1].raw_id)}" | |
40 | class="btn btn-default"> |
|
40 | class="btn btn-default"> | |
41 | ${_('Show combined compare')} |
|
41 | ${_('Show combined compare')} | |
42 | </a> |
|
42 | </a> | |
43 | </div> |
|
43 | </div> | |
44 | </div> |
|
44 | </div> | |
45 |
|
45 | |||
46 | <div class="summary-detail"> |
|
46 | <div class="summary-detail"> | |
47 | <div class="title"> |
|
47 | <div class="title"> | |
48 | <h2> |
|
48 | <h2> | |
49 | ${self.breadcrumbs_links()} |
|
49 | ${self.breadcrumbs_links()} | |
50 | </h2> |
|
50 | </h2> | |
51 | </div> |
|
51 | </div> | |
52 |
|
||||
53 | <div id="changeset_compare_view_content"> |
|
|||
54 | ##CS |
|
|||
55 | <%include file="../compare/compare_commits.html"/> |
|
|||
56 | ## FILES |
|
|||
57 | <div class="cs_files_title"> |
|
|||
58 | <span class="cs_files_expand"> |
|
|||
59 | <span id="expand_all_files">${_('Expand All')}</span> | <span id="collapse_all_files">${_('Collapse All')}</span> |
|
|||
60 | </span> |
|
|||
61 | <h2> |
|
|||
62 | ${diff_block.diff_summary_text(len(c.files), c.lines_added, c.lines_deleted, c.limited_diff)} |
|
|||
63 | </h2> |
|
|||
64 | </div> |
|
|||
65 | </div> |
|
|||
66 | </div> |
|
52 | </div> | |
67 |
|
53 | <div id="changeset_compare_view_content"> | ||
68 | <div class="cs_files"> |
|
54 | ##CS | |
69 | <table class="compare_view_files"> |
|
55 | <%include file="../compare/compare_commits.html"/> | |
|
56 | <div class="cs_files"> | |||
|
57 | ${cbdiffs.render_diffset_menu()} | |||
|
58 | <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/> | |||
70 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
59 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> | |
71 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> |
|
60 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> | |
72 |
%for c |
|
61 | %for commit in c.commit_ranges: | |
73 | <tr class="rctable"> |
|
62 | ${cbdifss.render_diffset( | |
74 | <td colspan="4"> |
|
63 | diffset=c.changes[commit.raw_id], | |
75 | <a class="tooltip revision" title="${h.tooltip(cs.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">${'r%s:%s' % (cs.revision,h.short_id(cs.raw_id))}</a> | |
|
64 | collapse_when_files_over=5, | |
76 | ${h.age_component(cs.date)} |
|
65 | commit=commit, | |
77 |
|
|
66 | )} | |
78 |
|
|
67 | %endfor | |
79 | %for FID, (cs1, cs2, change, path, diff, stats, file) in c.changes[cs.raw_id].iteritems(): |
|
68 | </table> | |
80 | <tr class="cs_${change} collapse_file" fid="${FID}"> |
|
69 | </div> | |
81 | <td class="cs_icon_td"> |
|
|||
82 | <span class="collapse_file_icon" fid="${FID}"></span> |
|
|||
83 | </td> |
|
|||
84 | <td class="cs_icon_td"> |
|
|||
85 | <div class="flag_status not_reviewed hidden"></div> |
|
|||
86 | </td> |
|
|||
87 | <td class="cs_${change}" id="a_${FID}"> |
|
|||
88 | <div class="node"> |
|
|||
89 | <a href="#a_${FID}"> |
|
|||
90 | <i class="icon-file-${change.lower()}"></i> |
|
|||
91 | ${h.safe_unicode(path)} |
|
|||
92 | </a> |
|
|||
93 | </div> |
|
|||
94 | </td> |
|
|||
95 | <td> |
|
|||
96 | <div class="changes">${h.fancy_file_stats(stats)}</div> |
|
|||
97 | </td> |
|
|||
98 | </tr> |
|
|||
99 | <tr fid="${FID}" id="diff_${FID}" class="diff_links"> |
|
|||
100 | <td></td> |
|
|||
101 | <td></td> |
|
|||
102 | <td class="cs_${change}"> |
|
|||
103 | ${diff_block.diff_menu(c.repo_name, h.safe_unicode(path), cs1, cs2, change, file)} |
|
|||
104 | </td> |
|
|||
105 | <td class="td-actions rc-form"></td> |
|
|||
106 | </tr> |
|
|||
107 | <tr id="tr_${FID}"> |
|
|||
108 | <td></td> |
|
|||
109 | <td></td> |
|
|||
110 | <td class="injected_diff" colspan="2"> |
|
|||
111 | <div id="diff-container-${FID}" class="diff-container"> |
|
|||
112 | <div id="${FID}" class="diffblock margined comm"> |
|
|||
113 | <div class="code-body"> |
|
|||
114 | ${diff|n} |
|
|||
115 | </div> |
|
|||
116 | </div> |
|
|||
117 | </div> |
|
|||
118 | </td> |
|
|||
119 | </tr> |
|
|||
120 | %endfor |
|
|||
121 | %endfor |
|
|||
122 | </table> |
|
|||
123 | </div> |
|
70 | </div> | |
124 | ## end summary detail |
|
71 | </%def> | |
125 |
|
||||
126 | </%def> No newline at end of file |
|
@@ -1,420 +1,420 b'' | |||||
1 | <%def name="diff_line_anchor(filename, line, type)"><% |
|
1 | <%def name="diff_line_anchor(filename, line, type)"><% | |
2 | return '%s_%s_%i' % (h.safeid(filename), type, line) |
|
2 | return '%s_%s_%i' % (h.safeid(filename), type, line) | |
3 | %></%def> |
|
3 | %></%def> | |
4 |
|
4 | |||
5 | <%def name="action_class(action)"><% |
|
5 | <%def name="action_class(action)"><% | |
6 | return { |
|
6 | return { | |
7 | '-': 'cb-deletion', |
|
7 | '-': 'cb-deletion', | |
8 | '+': 'cb-addition', |
|
8 | '+': 'cb-addition', | |
9 | ' ': 'cb-context', |
|
9 | ' ': 'cb-context', | |
10 | }.get(action, 'cb-empty') |
|
10 | }.get(action, 'cb-empty') | |
11 | %></%def> |
|
11 | %></%def> | |
12 |
|
12 | |||
13 | <%def name="op_class(op_id)"><% |
|
13 | <%def name="op_class(op_id)"><% | |
14 | return { |
|
14 | return { | |
15 | DEL_FILENODE: 'deletion', # file deleted |
|
15 | DEL_FILENODE: 'deletion', # file deleted | |
16 | BIN_FILENODE: 'warning' # binary diff hidden |
|
16 | BIN_FILENODE: 'warning' # binary diff hidden | |
17 | }.get(op_id, 'addition') |
|
17 | }.get(op_id, 'addition') | |
18 | %></%def> |
|
18 | %></%def> | |
19 |
|
19 | |||
20 | <%def name="link_for(**kw)"><% |
|
20 | <%def name="link_for(**kw)"><% | |
21 | new_args = request.GET.mixed() |
|
21 | new_args = request.GET.mixed() | |
22 | new_args.update(kw) |
|
22 | new_args.update(kw) | |
23 | return h.url('', **new_args) |
|
23 | return h.url('', **new_args) | |
24 | %></%def> |
|
24 | %></%def> | |
25 |
|
25 | |||
26 | <%def name="render_diffset(diffset, commit=None, |
|
26 | <%def name="render_diffset(diffset, commit=None, | |
27 |
|
27 | |||
28 | # collapse all file diff entries when there are more than this amount of files in the diff |
|
28 | # collapse all file diff entries when there are more than this amount of files in the diff | |
29 | collapse_when_files_over=20, |
|
29 | collapse_when_files_over=20, | |
30 |
|
30 | |||
31 | # collapse lines in the diff when more than this amount of lines changed in the file diff |
|
31 | # collapse lines in the diff when more than this amount of lines changed in the file diff | |
32 | lines_changed_limit=500, |
|
32 | lines_changed_limit=500, | |
33 |
|
33 | |||
34 | # add a ruler at to the output |
|
34 | # add a ruler at to the output | |
35 | ruler_at_chars=0, |
|
35 | ruler_at_chars=0, | |
36 |
|
36 | |||
37 | )"> |
|
37 | )"> | |
38 | <% |
|
38 | <% | |
39 | collapse_all = len(diffset.files) > collapse_when_files_over |
|
39 | collapse_all = len(diffset.files) > collapse_when_files_over | |
40 | %> |
|
40 | %> | |
41 |
|
41 | |||
42 | %if c.diffmode == 'sideside': |
|
42 | %if c.diffmode == 'sideside': | |
43 | <style> |
|
43 | <style> | |
44 | .wrapper { |
|
44 | .wrapper { | |
45 | max-width: 1600px !important; |
|
45 | max-width: 1600px !important; | |
46 | } |
|
46 | } | |
47 | </style> |
|
47 | </style> | |
48 | %endif |
|
48 | %endif | |
49 | %if ruler_at_chars: |
|
49 | %if ruler_at_chars: | |
50 | <style> |
|
50 | <style> | |
51 | .diff table.cb .cb-content:after { |
|
51 | .diff table.cb .cb-content:after { | |
52 | content: ""; |
|
52 | content: ""; | |
53 | border-left: 1px solid blue; |
|
53 | border-left: 1px solid blue; | |
54 | position: absolute; |
|
54 | position: absolute; | |
55 | top: 0; |
|
55 | top: 0; | |
56 | height: 18px; |
|
56 | height: 18px; | |
57 | opacity: .2; |
|
57 | opacity: .2; | |
58 | z-index: 10; |
|
58 | z-index: 10; | |
59 | ## +5 to account for diff action (+/-) |
|
59 | ## +5 to account for diff action (+/-) | |
60 | left: ${ruler_at_chars + 5}ch; |
|
60 | left: ${ruler_at_chars + 5}ch; | |
61 | </style> |
|
61 | </style> | |
62 | %endif |
|
62 | %endif | |
63 |
|
63 | |||
64 | <div class="diffset"> |
|
64 | <div class="diffset"> | |
65 | <div class="diffset-heading ${diffset.limited_diff and 'diffset-heading-warning' or ''}"> |
|
65 | <div class="diffset-heading ${diffset.limited_diff and 'diffset-heading-warning' or ''}"> | |
66 | %if commit: |
|
66 | %if commit: | |
67 | <div class="pull-right"> |
|
67 | <div class="pull-right"> | |
68 | <a class="btn tooltip" title="${_('Browse Files at revision {}').format(commit.raw_id)}" href="${h.url('files_home',repo_name=c.repo_name, revision=commit.raw_id, f_path='')}"> |
|
68 | <a class="btn tooltip" title="${_('Browse Files at revision {}').format(commit.raw_id)}" href="${h.url('files_home',repo_name=c.repo_name, revision=commit.raw_id, f_path='')}"> | |
69 | ${_('Browse Files')} |
|
69 | ${_('Browse Files')} | |
70 | </a> |
|
70 | </a> | |
71 | </div> |
|
71 | </div> | |
72 | %endif |
|
72 | %endif | |
73 | <h2 class="clearinner"> |
|
73 | <h2 class="clearinner"> | |
74 | %if commit: |
|
74 | %if commit: | |
75 | <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">${'r%s:%s' % (commit.revision,h.short_id(commit.raw_id))}</a> - |
|
75 | <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">${'r%s:%s' % (commit.revision,h.short_id(commit.raw_id))}</a> - | |
76 | ${h.age_component(commit.date)} - |
|
76 | ${h.age_component(commit.date)} - | |
77 | %endif |
|
77 | %endif | |
78 | %if diffset.limited_diff: |
|
78 | %if diffset.limited_diff: | |
79 | ${_('The requested commit is too big and content was truncated.')} |
|
79 | ${_('The requested commit is too big and content was truncated.')} | |
80 |
|
80 | |||
81 | ${ungettext('%(num)s file changed.', '%(num)s files changed.', diffset.changed_files) % {'num': diffset.changed_files}} |
|
81 | ${ungettext('%(num)s file changed.', '%(num)s files changed.', diffset.changed_files) % {'num': diffset.changed_files}} | |
82 | <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a> |
|
82 | <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a> | |
83 | %else: |
|
83 | %else: | |
84 | ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted', |
|
84 | ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted', | |
85 | '%(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}} |
|
85 | '%(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}} | |
86 | %endif |
|
86 | %endif | |
87 | </h2> |
|
87 | </h2> | |
88 | </div> |
|
88 | </div> | |
89 |
|
89 | |||
90 | %if not diffset.files: |
|
90 | %if not diffset.files: | |
91 | <p class="empty_data">${_('No files')}</p> |
|
91 | <p class="empty_data">${_('No files')}</p> | |
92 | %endif |
|
92 | %endif | |
93 |
|
93 | |||
94 | <div class="filediffs"> |
|
94 | <div class="filediffs"> | |
95 | %for i, filediff in enumerate(diffset.files): |
|
95 | %for i, filediff in enumerate(diffset.files): | |
96 | <% |
|
96 | <% | |
97 | lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted'] |
|
97 | lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted'] | |
98 | over_lines_changed_limit = lines_changed > lines_changed_limit |
|
98 | over_lines_changed_limit = lines_changed > lines_changed_limit | |
99 | %> |
|
99 | %> | |
100 | <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox"> |
|
100 | <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox"> | |
101 | <div |
|
101 | <div | |
102 | class="filediff" |
|
102 | class="filediff" | |
103 | data-f-path="${filediff['patch']['filename']}" |
|
103 | data-f-path="${filediff['patch']['filename']}" | |
104 | id="a_${h.FID(commit and commit.raw_id or '', filediff['patch']['filename'])}"> |
|
104 | id="a_${h.FID(commit and commit.raw_id or '', filediff['patch']['filename'])}"> | |
105 | <label for="filediff-collapse-${id(filediff)}" class="filediff-heading"> |
|
105 | <label for="filediff-collapse-${id(filediff)}" class="filediff-heading"> | |
106 | <div class="filediff-collapse-indicator"></div> |
|
106 | <div class="filediff-collapse-indicator"></div> | |
107 | ${diff_ops(filediff)} |
|
107 | ${diff_ops(filediff)} | |
108 | </label> |
|
108 | </label> | |
109 | ${diff_menu(filediff)} |
|
109 | ${diff_menu(filediff)} | |
110 | <table class="cb cb-diff-${c.diffmode} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}"> |
|
110 | <table class="cb cb-diff-${c.diffmode} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}"> | |
111 | %if not filediff.hunks: |
|
111 | %if not filediff.hunks: | |
112 | %for op_id, op_text in filediff['patch']['stats']['ops'].items(): |
|
112 | %for op_id, op_text in filediff['patch']['stats']['ops'].items(): | |
113 | <tr> |
|
113 | <tr> | |
114 | <td class="cb-text cb-${op_class(op_id)}" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}> |
|
114 | <td class="cb-text cb-${op_class(op_id)}" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}> | |
115 | %if op_id == DEL_FILENODE: |
|
115 | %if op_id == DEL_FILENODE: | |
116 | ${_('File was deleted')} |
|
116 | ${_('File was deleted')} | |
117 | %elif op_id == BIN_FILENODE: |
|
117 | %elif op_id == BIN_FILENODE: | |
118 | ${_('Binary file hidden')} |
|
118 | ${_('Binary file hidden')} | |
119 | %else: |
|
119 | %else: | |
120 | ${op_text} |
|
120 | ${op_text} | |
121 | %endif |
|
121 | %endif | |
122 | </td> |
|
122 | </td> | |
123 | </tr> |
|
123 | </tr> | |
124 | %endfor |
|
124 | %endfor | |
125 | %endif |
|
125 | %endif | |
126 | %if over_lines_changed_limit: |
|
126 | %if over_lines_changed_limit: | |
127 | <tr class="cb-warning cb-collapser"> |
|
127 | <tr class="cb-warning cb-collapser"> | |
128 | <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}> |
|
128 | <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}> | |
129 | ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)} |
|
129 | ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)} | |
130 | <a href="#" class="cb-expand" |
|
130 | <a href="#" class="cb-expand" | |
131 | onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')} |
|
131 | onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')} | |
132 | </a> |
|
132 | </a> | |
133 | <a href="#" class="cb-collapse" |
|
133 | <a href="#" class="cb-collapse" | |
134 | onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')} |
|
134 | onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')} | |
135 | </a> |
|
135 | </a> | |
136 | </td> |
|
136 | </td> | |
137 | </tr> |
|
137 | </tr> | |
138 | %endif |
|
138 | %endif | |
139 | %if filediff.patch['is_limited_diff']: |
|
139 | %if filediff.patch['is_limited_diff']: | |
140 | <tr class="cb-warning cb-collapser"> |
|
140 | <tr class="cb-warning cb-collapser"> | |
141 | <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}> |
|
141 | <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}> | |
142 | ${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a> |
|
142 | ${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a> | |
143 | </td> |
|
143 | </td> | |
144 | </tr> |
|
144 | </tr> | |
145 | %endif |
|
145 | %endif | |
146 | %for hunk in filediff.hunks: |
|
146 | %for hunk in filediff.hunks: | |
147 | <tr class="cb-hunk"> |
|
147 | <tr class="cb-hunk"> | |
148 | <td ${c.diffmode == 'unified' and 'colspan=2' or ''}> |
|
148 | <td ${c.diffmode == 'unified' and 'colspan=2' or ''}> | |
149 | ## TODO: dan: add ajax loading of more context here |
|
149 | ## TODO: dan: add ajax loading of more context here | |
150 | ## <a href="#"> |
|
150 | ## <a href="#"> | |
151 | <i class="icon-more"></i> |
|
151 | <i class="icon-more"></i> | |
152 | ## </a> |
|
152 | ## </a> | |
153 | </td> |
|
153 | </td> | |
154 | <td ${c.diffmode == 'sideside' and 'colspan=3' or ''}> |
|
154 | <td ${c.diffmode == 'sideside' and 'colspan=3' or ''}> | |
155 | @@ |
|
155 | @@ | |
156 | -${hunk.source_start},${hunk.source_length} |
|
156 | -${hunk.source_start},${hunk.source_length} | |
157 | +${hunk.target_start},${hunk.target_length} |
|
157 | +${hunk.target_start},${hunk.target_length} | |
158 | ${hunk.section_header} |
|
158 | ${hunk.section_header} | |
159 | </td> |
|
159 | </td> | |
160 | </tr> |
|
160 | </tr> | |
161 | %if c.diffmode == 'unified': |
|
161 | %if c.diffmode == 'unified': | |
162 | ${render_hunk_lines_unified(hunk)} |
|
162 | ${render_hunk_lines_unified(hunk)} | |
163 | %elif c.diffmode == 'sideside': |
|
163 | %elif c.diffmode == 'sideside': | |
164 | ${render_hunk_lines_sideside(hunk)} |
|
164 | ${render_hunk_lines_sideside(hunk)} | |
165 | %else: |
|
165 | %else: | |
166 | <tr class="cb-line"> |
|
166 | <tr class="cb-line"> | |
167 | <td>unknown diff mode</td> |
|
167 | <td>unknown diff mode</td> | |
168 | </tr> |
|
168 | </tr> | |
169 | %endif |
|
169 | %endif | |
170 | %endfor |
|
170 | %endfor | |
171 | </table> |
|
171 | </table> | |
172 | </div> |
|
172 | </div> | |
173 | %endfor |
|
173 | %endfor | |
174 | </div> |
|
174 | </div> | |
175 | </div> |
|
175 | </div> | |
176 | </%def> |
|
176 | </%def> | |
177 |
|
177 | |||
178 | <%def name="diff_ops(filediff)"> |
|
178 | <%def name="diff_ops(filediff)"> | |
179 | <% |
|
179 | <% | |
180 | stats = filediff['patch']['stats'] |
|
180 | stats = filediff['patch']['stats'] | |
181 | from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \ |
|
181 | from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \ | |
182 | MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE |
|
182 | MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE | |
183 | %> |
|
183 | %> | |
184 | <span class="pill"> |
|
184 | <span class="pill"> | |
185 | %if filediff.source_file_path and filediff.target_file_path: |
|
185 | %if filediff.source_file_path and filediff.target_file_path: | |
186 | %if filediff.source_file_path != filediff.target_file_path: # file was renamed |
|
186 | %if filediff.source_file_path != filediff.target_file_path: # file was renamed | |
187 | <strong>${filediff.target_file_path}</strong> β¬ <del>${filediff.source_file_path}</del> |
|
187 | <strong>${filediff.target_file_path}</strong> β¬ <del>${filediff.source_file_path}</del> | |
188 | %else: |
|
188 | %else: | |
189 | ## file was modified |
|
189 | ## file was modified | |
190 | <strong>${filediff.source_file_path}</strong> |
|
190 | <strong>${filediff.source_file_path}</strong> | |
191 | %endif |
|
191 | %endif | |
192 | %else: |
|
192 | %else: | |
193 | %if filediff.source_file_path: |
|
193 | %if filediff.source_file_path: | |
194 | ## file was deleted |
|
194 | ## file was deleted | |
195 | <strong>${filediff.source_file_path}</strong> |
|
195 | <strong>${filediff.source_file_path}</strong> | |
196 | %else: |
|
196 | %else: | |
197 | ## file was added |
|
197 | ## file was added | |
198 | <strong>${filediff.target_file_path}</strong> |
|
198 | <strong>${filediff.target_file_path}</strong> | |
199 | %endif |
|
199 | %endif | |
200 | %endif |
|
200 | %endif | |
201 | </span> |
|
201 | </span> | |
202 | <span class="pill-group" style="float: left"> |
|
202 | <span class="pill-group" style="float: left"> | |
203 | %if filediff.patch['is_limited_diff']: |
|
203 | %if filediff.patch['is_limited_diff']: | |
204 | <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span> |
|
204 | <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span> | |
205 | %endif |
|
205 | %endif | |
206 | %if RENAMED_FILENODE in stats['ops']: |
|
206 | %if RENAMED_FILENODE in stats['ops']: | |
207 | <span class="pill" op="renamed">renamed</span> |
|
207 | <span class="pill" op="renamed">renamed</span> | |
208 | %endif |
|
208 | %endif | |
209 |
|
209 | |||
210 | %if NEW_FILENODE in stats['ops']: |
|
210 | %if NEW_FILENODE in stats['ops']: | |
211 | <span class="pill" op="created">created</span> |
|
211 | <span class="pill" op="created">created</span> | |
212 | %if filediff['target_mode'].startswith('120'): |
|
212 | %if filediff['target_mode'].startswith('120'): | |
213 | <span class="pill" op="symlink">symlink</span> |
|
213 | <span class="pill" op="symlink">symlink</span> | |
214 | %else: |
|
214 | %else: | |
215 | <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span> |
|
215 | <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span> | |
216 | %endif |
|
216 | %endif | |
217 | %endif |
|
217 | %endif | |
218 |
|
218 | |||
219 | %if DEL_FILENODE in stats['ops']: |
|
219 | %if DEL_FILENODE in stats['ops']: | |
220 | <span class="pill" op="removed">removed</span> |
|
220 | <span class="pill" op="removed">removed</span> | |
221 | %endif |
|
221 | %endif | |
222 |
|
222 | |||
223 | %if CHMOD_FILENODE in stats['ops']: |
|
223 | %if CHMOD_FILENODE in stats['ops']: | |
224 | <span class="pill" op="mode"> |
|
224 | <span class="pill" op="mode"> | |
225 | ${nice_mode(filediff['source_mode'])} β‘ ${nice_mode(filediff['target_mode'])} |
|
225 | ${nice_mode(filediff['source_mode'])} β‘ ${nice_mode(filediff['target_mode'])} | |
226 | </span> |
|
226 | </span> | |
227 | %endif |
|
227 | %endif | |
228 | </span> |
|
228 | </span> | |
229 |
|
229 | |||
230 | <a class="pill filediff-anchor" href="#a_${h.FID(commit and commit.raw_id or '', filediff.patch['filename'])}">ΒΆ</a> |
|
230 | <a class="pill filediff-anchor" href="#a_${h.FID(commit and commit.raw_id or '', filediff.patch['filename'])}">ΒΆ</a> | |
231 |
|
231 | |||
232 | <span class="pill-group" style="float: right"> |
|
232 | <span class="pill-group" style="float: right"> | |
233 | %if BIN_FILENODE in stats['ops']: |
|
233 | %if BIN_FILENODE in stats['ops']: | |
234 | <span class="pill" op="binary">binary</span> |
|
234 | <span class="pill" op="binary">binary</span> | |
235 | %if MOD_FILENODE in stats['ops']: |
|
235 | %if MOD_FILENODE in stats['ops']: | |
236 | <span class="pill" op="modified">modified</span> |
|
236 | <span class="pill" op="modified">modified</span> | |
237 | %endif |
|
237 | %endif | |
238 | %endif |
|
238 | %endif | |
239 | %if stats['added']: |
|
239 | %if stats['added']: | |
240 | <span class="pill" op="added">+${stats['added']}</span> |
|
240 | <span class="pill" op="added">+${stats['added']}</span> | |
241 | %endif |
|
241 | %endif | |
242 | %if stats['deleted']: |
|
242 | %if stats['deleted']: | |
243 | <span class="pill" op="deleted">-${stats['deleted']}</span> |
|
243 | <span class="pill" op="deleted">-${stats['deleted']}</span> | |
244 | %endif |
|
244 | %endif | |
245 | </span> |
|
245 | </span> | |
246 |
|
246 | |||
247 | </%def> |
|
247 | </%def> | |
248 |
|
248 | |||
249 | <%def name="nice_mode(filemode)"> |
|
249 | <%def name="nice_mode(filemode)"> | |
250 | ${filemode.startswith('100') and filemode[3:] or filemode} |
|
250 | ${filemode.startswith('100') and filemode[3:] or filemode} | |
251 | </%def> |
|
251 | </%def> | |
252 |
|
252 | |||
253 | <%def name="diff_menu(filediff)"> |
|
253 | <%def name="diff_menu(filediff)"> | |
254 | <div class="filediff-menu"> |
|
254 | <div class="filediff-menu"> | |
255 | %if filediff.diffset.source_ref: |
|
255 | %if filediff.diffset.source_ref: | |
256 | %if filediff.patch['operation'] in ['D', 'M']: |
|
256 | %if filediff.patch['operation'] in ['D', 'M']: | |
257 | <a |
|
257 | <a | |
258 | class="tooltip" |
|
258 | class="tooltip" | |
259 | href="${h.url('files_home',repo_name=c.repo_name,f_path=filediff.source_file_path,revision=filediff.diffset.source_ref)}" |
|
259 | href="${h.url('files_home',repo_name=c.repo_name,f_path=filediff.source_file_path,revision=filediff.diffset.source_ref)}" | |
260 | title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" |
|
260 | title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" | |
261 | > |
|
261 | > | |
262 | ${_('Show file before')} |
|
262 | ${_('Show file before')} | |
263 | </a> |
|
263 | </a> | |
264 | %else: |
|
264 | %else: | |
265 | <span |
|
265 | <span | |
266 | class="tooltip" |
|
266 | class="tooltip" | |
267 | title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" |
|
267 | title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" | |
268 | > |
|
268 | > | |
269 | ${_('Show file before')} |
|
269 | ${_('Show file before')} | |
270 | </span> |
|
270 | </span> | |
271 | %endif |
|
271 | %endif | |
272 | %if filediff.patch['operation'] in ['A', 'M']: |
|
272 | %if filediff.patch['operation'] in ['A', 'M']: | |
273 | <a |
|
273 | <a | |
274 | class="tooltip" |
|
274 | class="tooltip" | |
275 | href="${h.url('files_home',repo_name=c.repo_name,f_path=filediff.target_file_path,revision=filediff.diffset.target_ref)}" |
|
275 | href="${h.url('files_home',repo_name=c.repo_name,f_path=filediff.target_file_path,revision=filediff.diffset.target_ref)}" | |
276 | title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" |
|
276 | title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" | |
277 | > |
|
277 | > | |
278 | ${_('Show file after')} |
|
278 | ${_('Show file after')} | |
279 | </a> |
|
279 | </a> | |
280 | %else: |
|
280 | %else: | |
281 | <span |
|
281 | <span | |
282 | class="tooltip" |
|
282 | class="tooltip" | |
283 | title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" |
|
283 | title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" | |
284 | > |
|
284 | > | |
285 | ${_('Show file after')} |
|
285 | ${_('Show file after')} | |
286 | </span> |
|
286 | </span> | |
287 | %endif |
|
287 | %endif | |
288 | <a |
|
288 | <a | |
289 | class="tooltip" |
|
289 | class="tooltip" | |
290 | title="${h.tooltip(_('Raw diff'))}" |
|
290 | title="${h.tooltip(_('Raw diff'))}" | |
291 | href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='raw')}" |
|
291 | href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='raw')}" | |
292 | > |
|
292 | > | |
293 | ${_('Raw diff')} |
|
293 | ${_('Raw diff')} | |
294 | </a> |
|
294 | </a> | |
295 | <a |
|
295 | <a | |
296 | class="tooltip" |
|
296 | class="tooltip" | |
297 | title="${h.tooltip(_('Download diff'))}" |
|
297 | title="${h.tooltip(_('Download diff'))}" | |
298 | href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='download')}" |
|
298 | href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='download')}" | |
299 | > |
|
299 | > | |
300 | ${_('Download diff')} |
|
300 | ${_('Download diff')} | |
301 | </a> |
|
301 | </a> | |
302 | %endif |
|
302 | %endif | |
303 | </div> |
|
303 | </div> | |
304 | </%def> |
|
304 | </%def> | |
305 |
|
305 | |||
306 |
|
306 | |||
307 | <%def name="render_hunk_lines_sideside(hunk)"> |
|
307 | <%def name="render_hunk_lines_sideside(hunk)"> | |
308 | %for i, line in enumerate(hunk.sideside): |
|
308 | %for i, line in enumerate(hunk.sideside): | |
309 | <% |
|
309 | <% | |
310 | old_line_anchor, new_line_anchor = None, None |
|
310 | old_line_anchor, new_line_anchor = None, None | |
311 | if line.original.lineno: |
|
311 | if line.original.lineno: | |
312 | old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, line.original.lineno, 'o') |
|
312 | old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, line.original.lineno, 'o') | |
313 | if line.modified.lineno: |
|
313 | if line.modified.lineno: | |
314 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n') |
|
314 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n') | |
315 | %> |
|
315 | %> | |
316 | <tr class="cb-line"> |
|
316 | <tr class="cb-line"> | |
317 | <td class="cb-lineno ${action_class(line.original.action)}" |
|
317 | <td class="cb-lineno ${action_class(line.original.action)}" | |
318 | data-line-number="${line.original.lineno}" |
|
318 | data-line-number="${line.original.lineno}" | |
319 | %if old_line_anchor: |
|
319 | %if old_line_anchor: | |
320 | id="${old_line_anchor}" |
|
320 | id="${old_line_anchor}" | |
321 | %endif |
|
321 | %endif | |
322 | > |
|
322 | > | |
323 | %if line.original.lineno: |
|
323 | %if line.original.lineno: | |
324 | <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a> |
|
324 | <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a> | |
325 | %endif |
|
325 | %endif | |
326 | </td> |
|
326 | </td> | |
327 | <td class="cb-content ${action_class(line.original.action)}" |
|
327 | <td class="cb-content ${action_class(line.original.action)}" | |
328 | data-line-number="o${line.original.lineno}" |
|
328 | data-line-number="o${line.original.lineno}" | |
329 | ><span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span> |
|
329 | ><span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span> | |
330 | </td> |
|
330 | </td> | |
331 | <td class="cb-lineno ${action_class(line.modified.action)}" |
|
331 | <td class="cb-lineno ${action_class(line.modified.action)}" | |
332 | data-line-number="${line.modified.lineno}" |
|
332 | data-line-number="${line.modified.lineno}" | |
333 | %if new_line_anchor: |
|
333 | %if new_line_anchor: | |
334 | id="${new_line_anchor}" |
|
334 | id="${new_line_anchor}" | |
335 | %endif |
|
335 | %endif | |
336 | > |
|
336 | > | |
337 | %if line.modified.lineno: |
|
337 | %if line.modified.lineno: | |
338 | <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a> |
|
338 | <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a> | |
339 | %endif |
|
339 | %endif | |
340 | </td> |
|
340 | </td> | |
341 | <td class="cb-content ${action_class(line.modified.action)}" |
|
341 | <td class="cb-content ${action_class(line.modified.action)}" | |
342 | data-line-number="n${line.modified.lineno}" |
|
342 | data-line-number="n${line.modified.lineno}" | |
343 | > |
|
343 | > | |
344 | <span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span> |
|
344 | <span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span> | |
345 | </td> |
|
345 | </td> | |
346 | </tr> |
|
346 | </tr> | |
347 | %endfor |
|
347 | %endfor | |
348 | </%def> |
|
348 | </%def> | |
349 |
|
349 | |||
350 |
|
350 | |||
351 | <%def name="render_hunk_lines_unified(hunk)"> |
|
351 | <%def name="render_hunk_lines_unified(hunk)"> | |
352 | %for old_line_no, new_line_no, action, content in hunk.unified: |
|
352 | %for old_line_no, new_line_no, action, content in hunk.unified: | |
353 | <% |
|
353 | <% | |
354 | old_line_anchor, new_line_anchor = None, None |
|
354 | old_line_anchor, new_line_anchor = None, None | |
355 | if old_line_no: |
|
355 | if old_line_no: | |
356 | old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, old_line_no, 'o') |
|
356 | old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, old_line_no, 'o') | |
357 | if new_line_no: |
|
357 | if new_line_no: | |
358 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n') |
|
358 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n') | |
359 | %> |
|
359 | %> | |
360 | <tr class="cb-line"> |
|
360 | <tr class="cb-line"> | |
361 | <td class="cb-lineno ${action_class(action)}" |
|
361 | <td class="cb-lineno ${action_class(action)}" | |
362 | data-line-number="${old_line_no}" |
|
362 | data-line-number="${old_line_no}" | |
363 | %if old_line_anchor: |
|
363 | %if old_line_anchor: | |
364 | id="${old_line_anchor}" |
|
364 | id="${old_line_anchor}" | |
365 | %endif |
|
365 | %endif | |
366 | > |
|
366 | > | |
367 | %if old_line_anchor: |
|
367 | %if old_line_anchor: | |
368 | <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a> |
|
368 | <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a> | |
369 | %endif |
|
369 | %endif | |
370 | </td> |
|
370 | </td> | |
371 | <td class="cb-lineno ${action_class(action)}" |
|
371 | <td class="cb-lineno ${action_class(action)}" | |
372 | data-line-number="${new_line_no}" |
|
372 | data-line-number="${new_line_no}" | |
373 | %if new_line_anchor: |
|
373 | %if new_line_anchor: | |
374 | id="${new_line_anchor}" |
|
374 | id="${new_line_anchor}" | |
375 | %endif |
|
375 | %endif | |
376 | > |
|
376 | > | |
377 | %if new_line_anchor: |
|
377 | %if new_line_anchor: | |
378 | <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a> |
|
378 | <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a> | |
379 | %endif |
|
379 | %endif | |
380 | </td> |
|
380 | </td> | |
381 | <td class="cb-content ${action_class(action)}" |
|
381 | <td class="cb-content ${action_class(action)}" | |
382 | data-line-number="${new_line_no and 'n' or 'o'}${new_line_no or old_line_no}" |
|
382 | data-line-number="${new_line_no and 'n' or 'o'}${new_line_no or old_line_no}" | |
383 | ><span class="cb-code">${action} ${content or '' | n}</span> |
|
383 | ><span class="cb-code">${action} ${content or '' | n}</span> | |
384 | </td> |
|
384 | </td> | |
385 | </tr> |
|
385 | </tr> | |
386 | %endfor |
|
386 | %endfor | |
387 | </%def> |
|
387 | </%def> | |
388 |
|
388 | |||
389 |
|
389 | |||
390 | <%def name="render_diffset_menu()"> |
|
390 | <%def name="render_diffset_menu()"> | |
391 | <div class="diffset-menu clearinner"> |
|
391 | <div class="diffset-menu clearinner"> | |
392 | <div class="pull-right"> |
|
392 | <div class="pull-right"> | |
393 | <div class="btn-group"> |
|
393 | <div class="btn-group"> | |
394 | <a |
|
394 | <a | |
395 | class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip" |
|
395 | class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip" | |
396 | title="${_('View side by side')}" |
|
396 | title="${_('View side by side')}" | |
397 | href="${h.url_replace(diffmode='sideside')}"> |
|
397 | href="${h.url_replace(diffmode='sideside')}"> | |
398 | <span>${_('Side by Side')}</span> |
|
398 | <span>${_('Side by Side')}</span> | |
399 | </a> |
|
399 | </a> | |
400 | <a |
|
400 | <a | |
401 | class="btn ${c.diffmode == 'unified' and 'btn-primary'} tooltip" |
|
401 | class="btn ${c.diffmode == 'unified' and 'btn-primary'} tooltip" | |
402 | title="${_('View unified')}" href="${h.url_replace(diffmode='unified')}"> |
|
402 | title="${_('View unified')}" href="${h.url_replace(diffmode='unified')}"> | |
403 | <span>${_('Unified')}</span> |
|
403 | <span>${_('Unified')}</span> | |
404 | </a> |
|
404 | </a> | |
405 | </div> |
|
405 | </div> | |
406 | </div> |
|
406 | </div> | |
407 | <div class="pull-left"> |
|
407 | <div class="pull-left"> | |
408 | <div class="btn-group"> |
|
408 | <div class="btn-group"> | |
409 | <a |
|
409 | <a | |
410 | class="btn" |
|
410 | class="btn" | |
411 | href="#" |
|
411 | href="#" | |
412 | onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All')}</a> |
|
412 | onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All')}</a> | |
413 | <a |
|
413 | <a | |
414 | class="btn" |
|
414 | class="btn" | |
415 | href="#" |
|
415 | href="#" | |
416 | onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All')}</a> |
|
416 | onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All')}</a> | |
417 | </div> |
|
417 | </div> | |
418 | </div> |
|
418 | </div> | |
419 | </div> |
|
419 | </div> | |
420 | </%def> No newline at end of file |
|
420 | </%def> |
General Comments 0
You need to be logged in to leave comments.
Login now