##// END OF EJS Templates
files: bring back ability to specify numeric commit number in files selector
marcink -
r3667:a0a98ffc new-ui
parent child Browse files
Show More
@@ -1,393 +1,392 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 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 import logging
21 import logging
22 import string
22 import string
23 import rhodecode
23 import rhodecode
24
24
25 from pyramid.view import view_config
25 from pyramid.view import view_config
26
26
27 from rhodecode.lib.view_utils import get_format_ref_id
27 from rhodecode.lib.view_utils import get_format_ref_id
28 from rhodecode.apps._base import RepoAppView
28 from rhodecode.apps._base import RepoAppView
29 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
29 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
30 from rhodecode.lib import helpers as h, rc_cache
30 from rhodecode.lib import helpers as h, rc_cache
31 from rhodecode.lib.utils2 import safe_str, safe_int
31 from rhodecode.lib.utils2 import safe_str, safe_int
32 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
32 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
33 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
33 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
34 from rhodecode.lib.ext_json import json
34 from rhodecode.lib.ext_json import json
35 from rhodecode.lib.vcs.backends.base import EmptyCommit
35 from rhodecode.lib.vcs.backends.base import EmptyCommit
36 from rhodecode.lib.vcs.exceptions import (
36 from rhodecode.lib.vcs.exceptions import (
37 CommitError, EmptyRepositoryError, CommitDoesNotExistError)
37 CommitError, EmptyRepositoryError, CommitDoesNotExistError)
38 from rhodecode.model.db import Statistics, CacheKey, User
38 from rhodecode.model.db import Statistics, CacheKey, User
39 from rhodecode.model.meta import Session
39 from rhodecode.model.meta import Session
40 from rhodecode.model.repo import ReadmeFinder
40 from rhodecode.model.repo import ReadmeFinder
41 from rhodecode.model.scm import ScmModel
41 from rhodecode.model.scm import ScmModel
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45
45
46 class RepoSummaryView(RepoAppView):
46 class RepoSummaryView(RepoAppView):
47
47
48 def load_default_context(self):
48 def load_default_context(self):
49 c = self._get_local_tmpl_context(include_app_defaults=True)
49 c = self._get_local_tmpl_context(include_app_defaults=True)
50 c.rhodecode_repo = None
50 c.rhodecode_repo = None
51 if not c.repository_requirements_missing:
51 if not c.repository_requirements_missing:
52 c.rhodecode_repo = self.rhodecode_vcs_repo
52 c.rhodecode_repo = self.rhodecode_vcs_repo
53 return c
53 return c
54
54
55 def _get_readme_data(self, db_repo, renderer_type):
55 def _get_readme_data(self, db_repo, renderer_type):
56
56
57 log.debug('Looking for README file')
57 log.debug('Looking for README file')
58
58
59 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
59 cache_namespace_uid = 'cache_repo_instance.{}_{}'.format(
60 db_repo.repo_id, CacheKey.CACHE_TYPE_README)
60 db_repo.repo_id, CacheKey.CACHE_TYPE_README)
61 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
61 invalidation_namespace = CacheKey.REPO_INVALIDATION_NAMESPACE.format(
62 repo_id=self.db_repo.repo_id)
62 repo_id=self.db_repo.repo_id)
63 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
63 region = rc_cache.get_or_create_region('cache_repo_longterm', cache_namespace_uid)
64
64
65 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
65 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid)
66 def generate_repo_readme(repo_id, _repo_name, _renderer_type):
66 def generate_repo_readme(repo_id, _repo_name, _renderer_type):
67 readme_data = None
67 readme_data = None
68 readme_node = None
68 readme_node = None
69 readme_filename = None
69 readme_filename = None
70 commit = self._get_landing_commit_or_none(db_repo)
70 commit = self._get_landing_commit_or_none(db_repo)
71 if commit:
71 if commit:
72 log.debug("Searching for a README file.")
72 log.debug("Searching for a README file.")
73 readme_node = ReadmeFinder(_renderer_type).search(commit)
73 readme_node = ReadmeFinder(_renderer_type).search(commit)
74 if readme_node:
74 if readme_node:
75 relative_urls = {
75 relative_urls = {
76 'raw': h.route_path(
76 'raw': h.route_path(
77 'repo_file_raw', repo_name=_repo_name,
77 'repo_file_raw', repo_name=_repo_name,
78 commit_id=commit.raw_id, f_path=readme_node.path),
78 commit_id=commit.raw_id, f_path=readme_node.path),
79 'standard': h.route_path(
79 'standard': h.route_path(
80 'repo_files', repo_name=_repo_name,
80 'repo_files', repo_name=_repo_name,
81 commit_id=commit.raw_id, f_path=readme_node.path),
81 commit_id=commit.raw_id, f_path=readme_node.path),
82 }
82 }
83 readme_data = self._render_readme_or_none(
83 readme_data = self._render_readme_or_none(
84 commit, readme_node, relative_urls)
84 commit, readme_node, relative_urls)
85 readme_filename = readme_node.path
85 readme_filename = readme_node.path
86 return readme_data, readme_filename
86 return readme_data, readme_filename
87
87
88 inv_context_manager = rc_cache.InvalidationContext(
88 inv_context_manager = rc_cache.InvalidationContext(
89 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
89 uid=cache_namespace_uid, invalidation_namespace=invalidation_namespace)
90 with inv_context_manager as invalidation_context:
90 with inv_context_manager as invalidation_context:
91 args = (db_repo.repo_id, db_repo.repo_name, renderer_type,)
91 args = (db_repo.repo_id, db_repo.repo_name, renderer_type,)
92 # re-compute and store cache if we get invalidate signal
92 # re-compute and store cache if we get invalidate signal
93 if invalidation_context.should_invalidate():
93 if invalidation_context.should_invalidate():
94 instance = generate_repo_readme.refresh(*args)
94 instance = generate_repo_readme.refresh(*args)
95 else:
95 else:
96 instance = generate_repo_readme(*args)
96 instance = generate_repo_readme(*args)
97
97
98 log.debug(
98 log.debug(
99 'Repo readme generated and computed in %.3fs',
99 'Repo readme generated and computed in %.3fs',
100 inv_context_manager.compute_time)
100 inv_context_manager.compute_time)
101 return instance
101 return instance
102
102
103 def _get_landing_commit_or_none(self, db_repo):
103 def _get_landing_commit_or_none(self, db_repo):
104 log.debug("Getting the landing commit.")
104 log.debug("Getting the landing commit.")
105 try:
105 try:
106 commit = db_repo.get_landing_commit()
106 commit = db_repo.get_landing_commit()
107 if not isinstance(commit, EmptyCommit):
107 if not isinstance(commit, EmptyCommit):
108 return commit
108 return commit
109 else:
109 else:
110 log.debug("Repository is empty, no README to render.")
110 log.debug("Repository is empty, no README to render.")
111 except CommitError:
111 except CommitError:
112 log.exception(
112 log.exception(
113 "Problem getting commit when trying to render the README.")
113 "Problem getting commit when trying to render the README.")
114
114
115 def _render_readme_or_none(self, commit, readme_node, relative_urls):
115 def _render_readme_or_none(self, commit, readme_node, relative_urls):
116 log.debug(
116 log.debug(
117 'Found README file `%s` rendering...', readme_node.path)
117 'Found README file `%s` rendering...', readme_node.path)
118 renderer = MarkupRenderer()
118 renderer = MarkupRenderer()
119 try:
119 try:
120 html_source = renderer.render(
120 html_source = renderer.render(
121 readme_node.content, filename=readme_node.path)
121 readme_node.content, filename=readme_node.path)
122 if relative_urls:
122 if relative_urls:
123 return relative_links(html_source, relative_urls)
123 return relative_links(html_source, relative_urls)
124 return html_source
124 return html_source
125 except Exception:
125 except Exception:
126 log.exception(
126 log.exception(
127 "Exception while trying to render the README")
127 "Exception while trying to render the README")
128
128
129 def _load_commits_context(self, c):
129 def _load_commits_context(self, c):
130 p = safe_int(self.request.GET.get('page'), 1)
130 p = safe_int(self.request.GET.get('page'), 1)
131 size = safe_int(self.request.GET.get('size'), 10)
131 size = safe_int(self.request.GET.get('size'), 10)
132
132
133 def url_generator(**kw):
133 def url_generator(**kw):
134 query_params = {
134 query_params = {
135 'size': size
135 'size': size
136 }
136 }
137 query_params.update(kw)
137 query_params.update(kw)
138 return h.route_path(
138 return h.route_path(
139 'repo_summary_commits',
139 'repo_summary_commits',
140 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
140 repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
141
141
142 pre_load = ['author', 'branch', 'date', 'message']
142 pre_load = ['author', 'branch', 'date', 'message']
143 try:
143 try:
144 collection = self.rhodecode_vcs_repo.get_commits(
144 collection = self.rhodecode_vcs_repo.get_commits(
145 pre_load=pre_load, translate_tags=False)
145 pre_load=pre_load, translate_tags=False)
146 except EmptyRepositoryError:
146 except EmptyRepositoryError:
147 collection = self.rhodecode_vcs_repo
147 collection = self.rhodecode_vcs_repo
148
148
149 c.repo_commits = h.RepoPage(
149 c.repo_commits = h.RepoPage(
150 collection, page=p, items_per_page=size, url=url_generator)
150 collection, page=p, items_per_page=size, url=url_generator)
151 page_ids = [x.raw_id for x in c.repo_commits]
151 page_ids = [x.raw_id for x in c.repo_commits]
152 c.comments = self.db_repo.get_comments(page_ids)
152 c.comments = self.db_repo.get_comments(page_ids)
153 c.statuses = self.db_repo.statuses(page_ids)
153 c.statuses = self.db_repo.statuses(page_ids)
154
154
155 def _prepare_and_set_clone_url(self, c):
155 def _prepare_and_set_clone_url(self, c):
156 username = ''
156 username = ''
157 if self._rhodecode_user.username != User.DEFAULT_USER:
157 if self._rhodecode_user.username != User.DEFAULT_USER:
158 username = safe_str(self._rhodecode_user.username)
158 username = safe_str(self._rhodecode_user.username)
159
159
160 _def_clone_uri = _def_clone_uri_id = c.clone_uri_tmpl
160 _def_clone_uri = _def_clone_uri_id = c.clone_uri_tmpl
161 _def_clone_uri_ssh = c.clone_uri_ssh_tmpl
161 _def_clone_uri_ssh = c.clone_uri_ssh_tmpl
162
162
163 if '{repo}' in _def_clone_uri:
163 if '{repo}' in _def_clone_uri:
164 _def_clone_uri_id = _def_clone_uri.replace('{repo}', '_{repoid}')
164 _def_clone_uri_id = _def_clone_uri.replace('{repo}', '_{repoid}')
165 elif '{repoid}' in _def_clone_uri:
165 elif '{repoid}' in _def_clone_uri:
166 _def_clone_uri_id = _def_clone_uri.replace('_{repoid}', '{repo}')
166 _def_clone_uri_id = _def_clone_uri.replace('_{repoid}', '{repo}')
167
167
168 c.clone_repo_url = self.db_repo.clone_url(
168 c.clone_repo_url = self.db_repo.clone_url(
169 user=username, uri_tmpl=_def_clone_uri)
169 user=username, uri_tmpl=_def_clone_uri)
170 c.clone_repo_url_id = self.db_repo.clone_url(
170 c.clone_repo_url_id = self.db_repo.clone_url(
171 user=username, uri_tmpl=_def_clone_uri_id)
171 user=username, uri_tmpl=_def_clone_uri_id)
172 c.clone_repo_url_ssh = self.db_repo.clone_url(
172 c.clone_repo_url_ssh = self.db_repo.clone_url(
173 uri_tmpl=_def_clone_uri_ssh, ssh=True)
173 uri_tmpl=_def_clone_uri_ssh, ssh=True)
174
174
175 @LoginRequired()
175 @LoginRequired()
176 @HasRepoPermissionAnyDecorator(
176 @HasRepoPermissionAnyDecorator(
177 'repository.read', 'repository.write', 'repository.admin')
177 'repository.read', 'repository.write', 'repository.admin')
178 @view_config(
178 @view_config(
179 route_name='repo_summary_commits', request_method='GET',
179 route_name='repo_summary_commits', request_method='GET',
180 renderer='rhodecode:templates/summary/summary_commits.mako')
180 renderer='rhodecode:templates/summary/summary_commits.mako')
181 def summary_commits(self):
181 def summary_commits(self):
182 c = self.load_default_context()
182 c = self.load_default_context()
183 self._prepare_and_set_clone_url(c)
183 self._prepare_and_set_clone_url(c)
184 self._load_commits_context(c)
184 self._load_commits_context(c)
185 return self._get_template_context(c)
185 return self._get_template_context(c)
186
186
187 @LoginRequired()
187 @LoginRequired()
188 @HasRepoPermissionAnyDecorator(
188 @HasRepoPermissionAnyDecorator(
189 'repository.read', 'repository.write', 'repository.admin')
189 'repository.read', 'repository.write', 'repository.admin')
190 @view_config(
190 @view_config(
191 route_name='repo_summary', request_method='GET',
191 route_name='repo_summary', request_method='GET',
192 renderer='rhodecode:templates/summary/summary.mako')
192 renderer='rhodecode:templates/summary/summary.mako')
193 @view_config(
193 @view_config(
194 route_name='repo_summary_slash', request_method='GET',
194 route_name='repo_summary_slash', request_method='GET',
195 renderer='rhodecode:templates/summary/summary.mako')
195 renderer='rhodecode:templates/summary/summary.mako')
196 @view_config(
196 @view_config(
197 route_name='repo_summary_explicit', request_method='GET',
197 route_name='repo_summary_explicit', request_method='GET',
198 renderer='rhodecode:templates/summary/summary.mako')
198 renderer='rhodecode:templates/summary/summary.mako')
199 def summary(self):
199 def summary(self):
200 c = self.load_default_context()
200 c = self.load_default_context()
201
201
202 # Prepare the clone URL
202 # Prepare the clone URL
203 self._prepare_and_set_clone_url(c)
203 self._prepare_and_set_clone_url(c)
204
204
205 # If enabled, get statistics data
205 # If enabled, get statistics data
206
206
207 c.show_stats = bool(self.db_repo.enable_statistics)
207 c.show_stats = bool(self.db_repo.enable_statistics)
208
208
209 stats = Session().query(Statistics) \
209 stats = Session().query(Statistics) \
210 .filter(Statistics.repository == self.db_repo) \
210 .filter(Statistics.repository == self.db_repo) \
211 .scalar()
211 .scalar()
212
212
213 c.stats_percentage = 0
213 c.stats_percentage = 0
214
214
215 if stats and stats.languages:
215 if stats and stats.languages:
216 c.no_data = False is self.db_repo.enable_statistics
216 c.no_data = False is self.db_repo.enable_statistics
217 lang_stats_d = json.loads(stats.languages)
217 lang_stats_d = json.loads(stats.languages)
218
218
219 # Sort first by decreasing count and second by the file extension,
219 # Sort first by decreasing count and second by the file extension,
220 # so we have a consistent output.
220 # so we have a consistent output.
221 lang_stats_items = sorted(lang_stats_d.iteritems(),
221 lang_stats_items = sorted(lang_stats_d.iteritems(),
222 key=lambda k: (-k[1], k[0]))[:10]
222 key=lambda k: (-k[1], k[0]))[:10]
223 lang_stats = [(x, {"count": y,
223 lang_stats = [(x, {"count": y,
224 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
224 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
225 for x, y in lang_stats_items]
225 for x, y in lang_stats_items]
226
226
227 c.trending_languages = json.dumps(lang_stats)
227 c.trending_languages = json.dumps(lang_stats)
228 else:
228 else:
229 c.no_data = True
229 c.no_data = True
230 c.trending_languages = json.dumps({})
230 c.trending_languages = json.dumps({})
231
231
232 scm_model = ScmModel()
232 scm_model = ScmModel()
233 c.enable_downloads = self.db_repo.enable_downloads
233 c.enable_downloads = self.db_repo.enable_downloads
234 c.repository_followers = scm_model.get_followers(self.db_repo)
234 c.repository_followers = scm_model.get_followers(self.db_repo)
235 c.repository_forks = scm_model.get_forks(self.db_repo)
235 c.repository_forks = scm_model.get_forks(self.db_repo)
236 c.repository_is_user_following = scm_model.is_following_repo(
236 c.repository_is_user_following = scm_model.is_following_repo(
237 self.db_repo_name, self._rhodecode_user.user_id)
237 self.db_repo_name, self._rhodecode_user.user_id)
238
238
239 # first interaction with the VCS instance after here...
239 # first interaction with the VCS instance after here...
240 if c.repository_requirements_missing:
240 if c.repository_requirements_missing:
241 self.request.override_renderer = \
241 self.request.override_renderer = \
242 'rhodecode:templates/summary/missing_requirements.mako'
242 'rhodecode:templates/summary/missing_requirements.mako'
243 return self._get_template_context(c)
243 return self._get_template_context(c)
244
244
245 c.readme_data, c.readme_file = \
245 c.readme_data, c.readme_file = \
246 self._get_readme_data(self.db_repo, c.visual.default_renderer)
246 self._get_readme_data(self.db_repo, c.visual.default_renderer)
247
247
248 # loads the summary commits template context
248 # loads the summary commits template context
249 self._load_commits_context(c)
249 self._load_commits_context(c)
250
250
251 return self._get_template_context(c)
251 return self._get_template_context(c)
252
252
253 def get_request_commit_id(self):
253 def get_request_commit_id(self):
254 return self.request.matchdict['commit_id']
254 return self.request.matchdict['commit_id']
255
255
256 @LoginRequired()
256 @LoginRequired()
257 @HasRepoPermissionAnyDecorator(
257 @HasRepoPermissionAnyDecorator(
258 'repository.read', 'repository.write', 'repository.admin')
258 'repository.read', 'repository.write', 'repository.admin')
259 @view_config(
259 @view_config(
260 route_name='repo_stats', request_method='GET',
260 route_name='repo_stats', request_method='GET',
261 renderer='json_ext')
261 renderer='json_ext')
262 def repo_stats(self):
262 def repo_stats(self):
263 commit_id = self.get_request_commit_id()
263 commit_id = self.get_request_commit_id()
264 show_stats = bool(self.db_repo.enable_statistics)
264 show_stats = bool(self.db_repo.enable_statistics)
265 repo_id = self.db_repo.repo_id
265 repo_id = self.db_repo.repo_id
266
266
267 cache_seconds = safe_int(
267 cache_seconds = safe_int(
268 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
268 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
269 cache_on = cache_seconds > 0
269 cache_on = cache_seconds > 0
270 log.debug(
270 log.debug(
271 'Computing REPO TREE for repo_id %s commit_id `%s` '
271 'Computing REPO TREE for repo_id %s commit_id `%s` '
272 'with caching: %s[TTL: %ss]' % (
272 'with caching: %s[TTL: %ss]' % (
273 repo_id, commit_id, cache_on, cache_seconds or 0))
273 repo_id, commit_id, cache_on, cache_seconds or 0))
274
274
275 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
275 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
276 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
276 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
277
277
278 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
278 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
279 condition=cache_on)
279 condition=cache_on)
280 def compute_stats(repo_id, commit_id, show_stats):
280 def compute_stats(repo_id, commit_id, show_stats):
281 code_stats = {}
281 code_stats = {}
282 size = 0
282 size = 0
283 try:
283 try:
284 scm_instance = self.db_repo.scm_instance()
284 scm_instance = self.db_repo.scm_instance()
285 commit = scm_instance.get_commit(commit_id)
285 commit = scm_instance.get_commit(commit_id)
286
286
287 for node in commit.get_filenodes_generator():
287 for node in commit.get_filenodes_generator():
288 size += node.size
288 size += node.size
289 if not show_stats:
289 if not show_stats:
290 continue
290 continue
291 ext = string.lower(node.extension)
291 ext = string.lower(node.extension)
292 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
292 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
293 if ext_info:
293 if ext_info:
294 if ext in code_stats:
294 if ext in code_stats:
295 code_stats[ext]['count'] += 1
295 code_stats[ext]['count'] += 1
296 else:
296 else:
297 code_stats[ext] = {"count": 1, "desc": ext_info}
297 code_stats[ext] = {"count": 1, "desc": ext_info}
298 except (EmptyRepositoryError, CommitDoesNotExistError):
298 except (EmptyRepositoryError, CommitDoesNotExistError):
299 pass
299 pass
300 return {'size': h.format_byte_size_binary(size),
300 return {'size': h.format_byte_size_binary(size),
301 'code_stats': code_stats}
301 'code_stats': code_stats}
302
302
303 stats = compute_stats(self.db_repo.repo_id, commit_id, show_stats)
303 stats = compute_stats(self.db_repo.repo_id, commit_id, show_stats)
304 return stats
304 return stats
305
305
306 @LoginRequired()
306 @LoginRequired()
307 @HasRepoPermissionAnyDecorator(
307 @HasRepoPermissionAnyDecorator(
308 'repository.read', 'repository.write', 'repository.admin')
308 'repository.read', 'repository.write', 'repository.admin')
309 @view_config(
309 @view_config(
310 route_name='repo_refs_data', request_method='GET',
310 route_name='repo_refs_data', request_method='GET',
311 renderer='json_ext')
311 renderer='json_ext')
312 def repo_refs_data(self):
312 def repo_refs_data(self):
313 _ = self.request.translate
313 _ = self.request.translate
314 self.load_default_context()
314 self.load_default_context()
315
315
316 repo = self.rhodecode_vcs_repo
316 repo = self.rhodecode_vcs_repo
317 refs_to_create = [
317 refs_to_create = [
318 (_("Branch"), repo.branches, 'branch'),
318 (_("Branch"), repo.branches, 'branch'),
319 (_("Tag"), repo.tags, 'tag'),
319 (_("Tag"), repo.tags, 'tag'),
320 (_("Bookmark"), repo.bookmarks, 'book'),
320 (_("Bookmark"), repo.bookmarks, 'book'),
321 ]
321 ]
322 res = self._create_reference_data(
322 res = self._create_reference_data(repo, self.db_repo_name, refs_to_create)
323 repo, self.db_repo_name, refs_to_create)
324 data = {
323 data = {
325 'more': False,
324 'more': False,
326 'results': res
325 'results': res
327 }
326 }
328 return data
327 return data
329
328
330 @LoginRequired()
329 @LoginRequired()
331 @HasRepoPermissionAnyDecorator(
330 @HasRepoPermissionAnyDecorator(
332 'repository.read', 'repository.write', 'repository.admin')
331 'repository.read', 'repository.write', 'repository.admin')
333 @view_config(
332 @view_config(
334 route_name='repo_refs_changelog_data', request_method='GET',
333 route_name='repo_refs_changelog_data', request_method='GET',
335 renderer='json_ext')
334 renderer='json_ext')
336 def repo_refs_changelog_data(self):
335 def repo_refs_changelog_data(self):
337 _ = self.request.translate
336 _ = self.request.translate
338 self.load_default_context()
337 self.load_default_context()
339
338
340 repo = self.rhodecode_vcs_repo
339 repo = self.rhodecode_vcs_repo
341
340
342 refs_to_create = [
341 refs_to_create = [
343 (_("Branches"), repo.branches, 'branch'),
342 (_("Branches"), repo.branches, 'branch'),
344 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
343 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
345 # TODO: enable when vcs can handle bookmarks filters
344 # TODO: enable when vcs can handle bookmarks filters
346 # (_("Bookmarks"), repo.bookmarks, "book"),
345 # (_("Bookmarks"), repo.bookmarks, "book"),
347 ]
346 ]
348 res = self._create_reference_data(
347 res = self._create_reference_data(
349 repo, self.db_repo_name, refs_to_create)
348 repo, self.db_repo_name, refs_to_create)
350 data = {
349 data = {
351 'more': False,
350 'more': False,
352 'results': res
351 'results': res
353 }
352 }
354 return data
353 return data
355
354
356 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
355 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
357 format_ref_id = get_format_ref_id(repo)
356 format_ref_id = get_format_ref_id(repo)
358
357
359 result = []
358 result = []
360 for title, refs, ref_type in refs_to_create:
359 for title, refs, ref_type in refs_to_create:
361 if refs:
360 if refs:
362 result.append({
361 result.append({
363 'text': title,
362 'text': title,
364 'children': self._create_reference_items(
363 'children': self._create_reference_items(
365 repo, full_repo_name, refs, ref_type,
364 repo, full_repo_name, refs, ref_type,
366 format_ref_id),
365 format_ref_id),
367 })
366 })
368 return result
367 return result
369
368
370 def _create_reference_items(self, repo, full_repo_name, refs, ref_type, format_ref_id):
369 def _create_reference_items(self, repo, full_repo_name, refs, ref_type, format_ref_id):
371 result = []
370 result = []
372 is_svn = h.is_svn(repo)
371 is_svn = h.is_svn(repo)
373 for ref_name, raw_id in refs.iteritems():
372 for ref_name, raw_id in refs.iteritems():
374 files_url = self._create_files_url(
373 files_url = self._create_files_url(
375 repo, full_repo_name, ref_name, raw_id, is_svn)
374 repo, full_repo_name, ref_name, raw_id, is_svn)
376 result.append({
375 result.append({
377 'text': ref_name,
376 'text': ref_name,
378 'id': format_ref_id(ref_name, raw_id),
377 'id': format_ref_id(ref_name, raw_id),
379 'raw_id': raw_id,
378 'raw_id': raw_id,
380 'type': ref_type,
379 'type': ref_type,
381 'files_url': files_url,
380 'files_url': files_url,
382 'idx': 0,
381 'idx': 0,
383 })
382 })
384 return result
383 return result
385
384
386 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id, is_svn):
385 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id, is_svn):
387 use_commit_id = '/' in ref_name or is_svn
386 use_commit_id = '/' in ref_name or is_svn
388 return h.route_path(
387 return h.route_path(
389 'repo_files',
388 'repo_files',
390 repo_name=full_repo_name,
389 repo_name=full_repo_name,
391 f_path=ref_name if is_svn else '',
390 f_path=ref_name if is_svn else '',
392 commit_id=raw_id if use_commit_id else ref_name,
391 commit_id=raw_id if use_commit_id else ref_name,
393 _query=dict(at=ref_name))
392 _query=dict(at=ref_name))
@@ -1,350 +1,392 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2
2
3 <%def name="title(*args)">
3 <%def name="title(*args)">
4 ${_('{} Files').format(c.repo_name)}
4 ${_('{} Files').format(c.repo_name)}
5 %if hasattr(c,'file'):
5 %if hasattr(c,'file'):
6 &middot; ${(h.safe_unicode(c.file.path) or '\\')}
6 &middot; ${(h.safe_unicode(c.file.path) or '\\')}
7 %endif
7 %endif
8
8
9 %if c.rhodecode_name:
9 %if c.rhodecode_name:
10 &middot; ${h.branding(c.rhodecode_name)}
10 &middot; ${h.branding(c.rhodecode_name)}
11 %endif
11 %endif
12 </%def>
12 </%def>
13
13
14 <%def name="breadcrumbs_links()">
14 <%def name="breadcrumbs_links()">
15 ${_('Files')}
15 ${_('Files')}
16 %if c.file:
16 %if c.file:
17 @ ${h.show_id(c.commit)}
17 @ ${h.show_id(c.commit)}
18 %endif
18 %endif
19 </%def>
19 </%def>
20
20
21 <%def name="menu_bar_nav()">
21 <%def name="menu_bar_nav()">
22 ${self.menu_items(active='repositories')}
22 ${self.menu_items(active='repositories')}
23 </%def>
23 </%def>
24
24
25 <%def name="menu_bar_subnav()">
25 <%def name="menu_bar_subnav()">
26 ${self.repo_menu(active='files')}
26 ${self.repo_menu(active='files')}
27 </%def>
27 </%def>
28
28
29 <%def name="main()">
29 <%def name="main()">
30 <div>
30 <div>
31 <div id="files_data">
31 <div id="files_data">
32 <%include file='files_pjax.mako'/>
32 <%include file='files_pjax.mako'/>
33 </div>
33 </div>
34 </div>
34 </div>
35 <script>
35 <script>
36
36
37 var metadataRequest = null;
37 var metadataRequest = null;
38 var fileSourcePage = ${c.file_source_page};
38 var fileSourcePage = ${c.file_source_page};
39 var atRef = '${request.GET.get('at', '')}';
39 var atRef = '${request.GET.get('at', '')}';
40
40
41 var getState = function(context) {
41 var getState = function(context) {
42 var url = $(location).attr('href');
42 var url = $(location).attr('href');
43 var _base_url = '${h.route_path("repo_files",repo_name=c.repo_name,commit_id='',f_path='')}';
43 var _base_url = '${h.route_path("repo_files",repo_name=c.repo_name,commit_id='',f_path='')}';
44 var _annotate_url = '${h.route_path("repo_files:annotated",repo_name=c.repo_name,commit_id='',f_path='')}';
44 var _annotate_url = '${h.route_path("repo_files:annotated",repo_name=c.repo_name,commit_id='',f_path='')}';
45 _base_url = _base_url.replace('//', '/');
45 _base_url = _base_url.replace('//', '/');
46 _annotate_url = _annotate_url.replace('//', '/');
46 _annotate_url = _annotate_url.replace('//', '/');
47
47
48 //extract f_path from url.
48 //extract f_path from url.
49 var parts = url.split(_base_url);
49 var parts = url.split(_base_url);
50 if (parts.length != 2) {
50 if (parts.length != 2) {
51 parts = url.split(_annotate_url);
51 parts = url.split(_annotate_url);
52 if (parts.length != 2) {
52 if (parts.length != 2) {
53 var rev = "tip";
53 var rev = "tip";
54 var f_path = "";
54 var f_path = "";
55 } else {
55 } else {
56 var parts2 = parts[1].split('/');
56 var parts2 = parts[1].split('/');
57 var rev = parts2.shift(); // pop the first element which is the revision
57 var rev = parts2.shift(); // pop the first element which is the revision
58 var f_path = parts2.join('/');
58 var f_path = parts2.join('/');
59 }
59 }
60
60
61 } else {
61 } else {
62 var parts2 = parts[1].split('/');
62 var parts2 = parts[1].split('/');
63 var rev = parts2.shift(); // pop the first element which is the revision
63 var rev = parts2.shift(); // pop the first element which is the revision
64 var f_path = parts2.join('/');
64 var f_path = parts2.join('/');
65 }
65 }
66
66
67 var url_params = {
67 var url_params = {
68 repo_name: templateContext.repo_name,
68 repo_name: templateContext.repo_name,
69 commit_id: rev,
69 commit_id: rev,
70 f_path:'__FPATH__'
70 f_path:'__FPATH__'
71 };
71 };
72 if (atRef !== '') {
72 if (atRef !== '') {
73 url_params['at'] = atRef
73 url_params['at'] = atRef
74 }
74 }
75
75
76 var _url_base = pyroutes.url('repo_files', url_params);
76 var _url_base = pyroutes.url('repo_files', url_params);
77 var _node_list_url = pyroutes.url('repo_files_nodelist',
77 var _node_list_url = pyroutes.url('repo_files_nodelist',
78 {repo_name: templateContext.repo_name,
78 {repo_name: templateContext.repo_name,
79 commit_id: rev, f_path: f_path});
79 commit_id: rev, f_path: f_path});
80
80
81 return {
81 return {
82 url: url,
82 url: url,
83 f_path: f_path,
83 f_path: f_path,
84 rev: rev,
84 rev: rev,
85 commit_id: "${c.commit.raw_id}",
85 commit_id: "${c.commit.raw_id}",
86 node_list_url: _node_list_url,
86 node_list_url: _node_list_url,
87 url_base: _url_base
87 url_base: _url_base
88 };
88 };
89 };
89 };
90
90
91 var getFilesMetadata = function() {
91 var getFilesMetadata = function() {
92 if (metadataRequest && metadataRequest.readyState != 4) {
92 if (metadataRequest && metadataRequest.readyState != 4) {
93 metadataRequest.abort();
93 metadataRequest.abort();
94 }
94 }
95 if (fileSourcePage) {
95 if (fileSourcePage) {
96 return false;
96 return false;
97 }
97 }
98
98
99 if ($('#file-tree-wrapper').hasClass('full-load')) {
99 if ($('#file-tree-wrapper').hasClass('full-load')) {
100 // in case our HTML wrapper has full-load class we don't
100 // in case our HTML wrapper has full-load class we don't
101 // trigger the async load of metadata
101 // trigger the async load of metadata
102 return false;
102 return false;
103 }
103 }
104
104
105 var state = getState('metadata');
105 var state = getState('metadata');
106 var url_data = {
106 var url_data = {
107 'repo_name': templateContext.repo_name,
107 'repo_name': templateContext.repo_name,
108 'commit_id': state.commit_id,
108 'commit_id': state.commit_id,
109 'f_path': state.f_path
109 'f_path': state.f_path
110 };
110 };
111
111
112 var url = pyroutes.url('repo_nodetree_full', url_data);
112 var url = pyroutes.url('repo_nodetree_full', url_data);
113
113
114 metadataRequest = $.ajax({url: url});
114 metadataRequest = $.ajax({url: url});
115
115
116 metadataRequest.done(function(data) {
116 metadataRequest.done(function(data) {
117 $('#file-tree').html(data);
117 $('#file-tree').html(data);
118 timeagoActivate();
118 timeagoActivate();
119 });
119 });
120 metadataRequest.fail(function (data, textStatus, errorThrown) {
120 metadataRequest.fail(function (data, textStatus, errorThrown) {
121 console.log(data);
121 console.log(data);
122 if (data.status != 0) {
122 if (data.status != 0) {
123 alert("Error while fetching metadata.\nError code {0} ({1}).Please consider reloading the page".format(data.status,data.statusText));
123 alert("Error while fetching metadata.\nError code {0} ({1}).Please consider reloading the page".format(data.status,data.statusText));
124 }
124 }
125 });
125 });
126 };
126 };
127
127
128 var callbacks = function() {
128 var callbacks = function() {
129 timeagoActivate();
129 timeagoActivate();
130
130
131 if ($('#trimmed_message_box').height() < 50) {
131 if ($('#trimmed_message_box').height() < 50) {
132 $('#message_expand').hide();
132 $('#message_expand').hide();
133 }
133 }
134
134
135 $('#message_expand').on('click', function(e) {
135 $('#message_expand').on('click', function(e) {
136 $('#trimmed_message_box').css('max-height', 'none');
136 $('#trimmed_message_box').css('max-height', 'none');
137 $(this).hide();
137 $(this).hide();
138 });
138 });
139
139
140 var state = getState('callbacks');
140 var state = getState('callbacks');
141
141
142 // VIEW FOR FILE SOURCE
142 // VIEW FOR FILE SOURCE
143 if (fileSourcePage) {
143 if (fileSourcePage) {
144 // variants for with source code, not tree view
144 // variants for with source code, not tree view
145
145
146 // select code link event
146 // select code link event
147 $("#hlcode").mouseup(getSelectionLink);
147 $("#hlcode").mouseup(getSelectionLink);
148
148
149 // file history select2 used for history, and switch to
149 // file history select2 used for history, and switch to
150 var initialCommitData = {
150 var initialCommitData = {
151 id: null,
151 id: null,
152 text: '${_("Pick Commit")}',
152 text: '${_("Pick Commit")}',
153 type: 'sha',
153 type: 'sha',
154 raw_id: null,
154 raw_id: null,
155 files_url: null
155 files_url: null
156 };
156 };
157
157
158 select2FileHistorySwitcher('#diff1', initialCommitData, state);
158 select2FileHistorySwitcher('#diff1', initialCommitData, state);
159
159
160 // show at, diff to actions handlers
160 // show at, diff to actions handlers
161 $('#diff1').on('change', function(e) {
161 $('#diff1').on('change', function(e) {
162 $('#diff_to_commit').removeClass('disabled').removeAttr("disabled");
162 $('#diff_to_commit').removeClass('disabled').removeAttr("disabled");
163 $('#diff_to_commit').val(_gettext('Diff to Commit ') + e.val.truncateAfter(8, '...'));
163 $('#diff_to_commit').val(_gettext('Diff to Commit ') + e.val.truncateAfter(8, '...'));
164
164
165 $('#show_at_commit').removeClass('disabled').removeAttr("disabled");
165 $('#show_at_commit').removeClass('disabled').removeAttr("disabled");
166 $('#show_at_commit').val(_gettext('Show at Commit ') + e.val.truncateAfter(8, '...'));
166 $('#show_at_commit').val(_gettext('Show at Commit ') + e.val.truncateAfter(8, '...'));
167 });
167 });
168
168
169 $('#diff_to_commit').on('click', function(e) {
169 $('#diff_to_commit').on('click', function(e) {
170 var diff1 = $('#diff1').val();
170 var diff1 = $('#diff1').val();
171 var diff2 = $('#diff2').val();
171 var diff2 = $('#diff2').val();
172
172
173 var url_data = {
173 var url_data = {
174 repo_name: templateContext.repo_name,
174 repo_name: templateContext.repo_name,
175 source_ref: diff1,
175 source_ref: diff1,
176 source_ref_type: 'rev',
176 source_ref_type: 'rev',
177 target_ref: diff2,
177 target_ref: diff2,
178 target_ref_type: 'rev',
178 target_ref_type: 'rev',
179 merge: 1,
179 merge: 1,
180 f_path: state.f_path
180 f_path: state.f_path
181 };
181 };
182 window.location = pyroutes.url('repo_compare', url_data);
182 window.location = pyroutes.url('repo_compare', url_data);
183 });
183 });
184
184
185 $('#show_at_commit').on('click', function(e) {
185 $('#show_at_commit').on('click', function(e) {
186 var diff1 = $('#diff1').val();
186 var diff1 = $('#diff1').val();
187
187
188 var annotate = $('#annotate').val();
188 var annotate = $('#annotate').val();
189 if (annotate === "True") {
189 if (annotate === "True") {
190 var url = pyroutes.url('repo_files:annotated',
190 var url = pyroutes.url('repo_files:annotated',
191 {'repo_name': templateContext.repo_name,
191 {'repo_name': templateContext.repo_name,
192 'commit_id': diff1, 'f_path': state.f_path});
192 'commit_id': diff1, 'f_path': state.f_path});
193 } else {
193 } else {
194 var url = pyroutes.url('repo_files',
194 var url = pyroutes.url('repo_files',
195 {'repo_name': templateContext.repo_name,
195 {'repo_name': templateContext.repo_name,
196 'commit_id': diff1, 'f_path': state.f_path});
196 'commit_id': diff1, 'f_path': state.f_path});
197 }
197 }
198 window.location = url;
198 window.location = url;
199
199
200 });
200 });
201
201
202 // show more authors
202 // show more authors
203 $('#show_authors').on('click', function(e) {
203 $('#show_authors').on('click', function(e) {
204 e.preventDefault();
204 e.preventDefault();
205 var url = pyroutes.url('repo_file_authors',
205 var url = pyroutes.url('repo_file_authors',
206 {'repo_name': templateContext.repo_name,
206 {'repo_name': templateContext.repo_name,
207 'commit_id': state.rev, 'f_path': state.f_path});
207 'commit_id': state.rev, 'f_path': state.f_path});
208
208
209 $.pjax({
209 $.pjax({
210 url: url,
210 url: url,
211 data: 'annotate=${("1" if c.annotate else "0")}',
211 data: 'annotate=${("1" if c.annotate else "0")}',
212 container: '#file_authors',
212 container: '#file_authors',
213 push: false,
213 push: false,
214 timeout: 5000
214 timeout: 5000
215 }).complete(function(){
215 }).complete(function(){
216 $('#show_authors').hide();
216 $('#show_authors').hide();
217 $('#file_authors_title').html(_gettext('All Authors'))
217 $('#file_authors_title').html(_gettext('All Authors'))
218 })
218 })
219 });
219 });
220
220
221 // load file short history
221 // load file short history
222 $('#file_history_overview').on('click', function(e) {
222 $('#file_history_overview').on('click', function(e) {
223 e.preventDefault();
223 e.preventDefault();
224 path = state.f_path;
224 path = state.f_path;
225 if (path.indexOf("#") >= 0) {
225 if (path.indexOf("#") >= 0) {
226 path = path.slice(0, path.indexOf("#"));
226 path = path.slice(0, path.indexOf("#"));
227 }
227 }
228 var url = pyroutes.url('repo_changelog_file',
228 var url = pyroutes.url('repo_changelog_file',
229 {'repo_name': templateContext.repo_name,
229 {'repo_name': templateContext.repo_name,
230 'commit_id': state.rev, 'f_path': path, 'limit': 6});
230 'commit_id': state.rev, 'f_path': path, 'limit': 6});
231 $('#file_history_container').show();
231 $('#file_history_container').show();
232 $('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_gettext('Loading ...')));
232 $('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_gettext('Loading ...')));
233
233
234 $.pjax({
234 $.pjax({
235 url: url,
235 url: url,
236 container: '#file_history_container',
236 container: '#file_history_container',
237 push: false,
237 push: false,
238 timeout: 5000
238 timeout: 5000
239 })
239 })
240 });
240 });
241
241
242 }
242 }
243 // VIEW FOR FILE TREE BROWSER
243 // VIEW FOR FILE TREE BROWSER
244 else {
244 else {
245 getFilesMetadata();
245 getFilesMetadata();
246
246
247 // fuzzy file filter
247 // fuzzy file filter
248 fileBrowserListeners(state.node_list_url, state.url_base);
248 fileBrowserListeners(state.node_list_url, state.url_base);
249
249
250 // switch to widget
250 // switch to widget
251 var initialCommitData = {
251 var initialCommitData = {
252 at_ref: atRef,
252 at_ref: atRef,
253 id: null,
253 id: null,
254 text: '${c.commit.raw_id}',
254 text: '${c.commit.raw_id}',
255 type: 'sha',
255 type: 'sha',
256 raw_id: '${c.commit.raw_id}',
256 raw_id: '${c.commit.raw_id}',
257 idx: ${c.commit.idx},
257 idx: ${c.commit.idx},
258 files_url: null,
258 files_url: null,
259 };
259 };
260
260
261 // check if we have ref info.
261 // check if we have ref info.
262 var selectedRef = fileTreeRefs[atRef];
262 var selectedRef = fileTreeRefs[atRef];
263 if (selectedRef !== undefined) {
263 if (selectedRef !== undefined) {
264 $.extend(initialCommitData, selectedRef)
264 $.extend(initialCommitData, selectedRef)
265 }
265 }
266
266
267 var loadUrl = pyroutes.url('repo_refs_data', {'repo_name': templateContext.repo_name});
267 var loadUrl = pyroutes.url('repo_refs_data', {'repo_name': templateContext.repo_name});
268 var cacheKey = '__ALL_FILE_REFS__';
269 var cachedDataSource = {};
270
271 var loadRefsData = function (query) {
272 $.ajax({
273 url: loadUrl,
274 data: {},
275 dataType: 'json',
276 type: 'GET',
277 success: function (data) {
278 cachedDataSource[cacheKey] = data;
279 query.callback({results: data.results});
280 }
281 });
282 };
283
284 var feedRefsData = function (query, cachedData) {
285 var data = {results: []};
286 //filter results
287 $.each(cachedData.results, function () {
288 var section = this.text;
289 var children = [];
290 $.each(this.children, function () {
291 if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
292 children.push(this)
293 }
294 });
295 data.results.push({
296 'text': section,
297 'children': children
298 })
299 });
300
301 //push the typed in commit idx
302 if (!isNaN(query.term)) {
303 var files_url = pyroutes.url('repo_files',
304 {'repo_name': templateContext.repo_name,
305 'commit_id': query.term, 'f_path': state.f_path});
306
307 data.results.push({
308 'text': _gettext('go to numeric commit'),
309 'children': [{
310 at_ref: null,
311 id: null,
312 text: 'r{0}'.format(query.term),
313 type: 'sha',
314 raw_id: query.term,
315 idx: query.term,
316 files_url: files_url,
317 }]
318 });
319 }
320 query.callback(data);
321 };
268
322
269 var select2RefFileSwitcher = function (targetElement, loadUrl, initialData) {
323 var select2RefFileSwitcher = function (targetElement, loadUrl, initialData) {
270 var formatResult = function (result, container, query) {
324 var formatResult = function (result, container, query) {
271 return formatSelect2SelectionRefs(result);
325 return formatSelect2SelectionRefs(result);
272 };
326 };
273
327
274 var formatSelection = function (data, container) {
328 var formatSelection = function (data, container) {
275 var commit_ref = data;
329 var commit_ref = data;
276
330
277 var tmpl = '';
331 var tmpl = '';
278 if (commit_ref.type === 'sha') {
332 if (commit_ref.type === 'sha') {
279 tmpl = commit_ref.raw_id.substr(0,8);
333 tmpl = commit_ref.raw_id.substr(0,8);
280 } else if (commit_ref.type === 'branch') {
334 } else if (commit_ref.type === 'branch') {
281 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
335 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
282 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
336 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
283 } else if (commit_ref.type === 'tag') {
337 } else if (commit_ref.type === 'tag') {
284 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
338 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
285 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
339 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
286 } else if (commit_ref.type === 'book') {
340 } else if (commit_ref.type === 'book') {
287 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
341 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
288 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
342 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
289 }
343 }
290
344
291 tmpl = tmpl.concat('<span class="select-index-number">{0}</span>'.format(commit_ref.idx));
345 tmpl = tmpl.concat('<span class="select-index-number">r{0}</span>'.format(commit_ref.idx));
292 return tmpl
346 return tmpl
293 };
347 };
294
348
295 $(targetElement).select2({
349 $(targetElement).select2({
296 cachedDataSource: {},
297 dropdownAutoWidth: true,
350 dropdownAutoWidth: true,
298 width: "resolve",
351 width: "resolve",
299 containerCssClass: "drop-menu",
352 containerCssClass: "drop-menu",
300 dropdownCssClass: "drop-menu-dropdown",
353 dropdownCssClass: "drop-menu-dropdown",
301 query: function(query) {
354 query: function(query) {
302 var self = this;
355
303 var cacheKey = '__ALL_FILE_REFS__';
356 var cachedData = cachedDataSource[cacheKey];
304 var cachedData = self.cachedDataSource[cacheKey];
305 if (cachedData) {
357 if (cachedData) {
306 var data = select2RefFilterResults(query.term, cachedData);
358 feedRefsData(query, cachedData)
307 query.callback({results: data.results});
308 } else {
359 } else {
309 $.ajax({
360 loadRefsData(query)
310 url: loadUrl,
311 data: {},
312 dataType: 'json',
313 type: 'GET',
314 success: function(data) {
315 self.cachedDataSource[cacheKey] = data;
316 query.callback({results: data.results});
317 }
318 });
319 }
361 }
320 },
362 },
321 initSelection: function(element, callback) {
363 initSelection: function(element, callback) {
322 callback(initialData);
364 callback(initialData);
323 },
365 },
324 formatResult: formatResult,
366 formatResult: formatResult,
325 formatSelection: formatSelection
367 formatSelection: formatSelection
326 });
368 });
327
369
328 };
370 };
329
371
330 select2RefFileSwitcher('#refs_filter', loadUrl, initialCommitData);
372 select2RefFileSwitcher('#refs_filter', loadUrl, initialCommitData);
331
373
332 $('#refs_filter').on('change', function(e) {
374 $('#refs_filter').on('change', function(e) {
333 var data = $('#refs_filter').select2('data');
375 var data = $('#refs_filter').select2('data');
334 window.location = data.files_url
376 window.location = data.files_url
335 });
377 });
336
378
337 }
379 }
338 };
380 };
339
381
340 $(document).ready(function() {
382 $(document).ready(function() {
341 callbacks();
383 callbacks();
342 var search_GET = "${request.GET.get('search','')}";
384 var search_GET = "${request.GET.get('search','')}";
343 if (search_GET === "1") {
385 if (search_GET === "1") {
344 _NODEFILTER.initFilter();
386 _NODEFILTER.initFilter();
345 }
387 }
346 });
388 });
347
389
348 </script>
390 </script>
349
391
350 </%def> No newline at end of file
392 </%def>
General Comments 0
You need to be logged in to leave comments. Login now