##// END OF EJS Templates
fixes #214 added support for downloading subrepos in download menu.
marcink -
r1450:2a8bf2a3 beta
parent child Browse files
Show More
@@ -1,414 +1,415 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.files
3 rhodecode.controllers.files
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Files controller for RhodeCode
6 Files controller for RhodeCode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import mimetypes
28 import mimetypes
29 import traceback
29 import traceback
30
30
31 from pylons import request, response, session, tmpl_context as c, url
31 from pylons import request, response, session, tmpl_context as c, url
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34
34
35 from vcs.backends import ARCHIVE_SPECS
35 from vcs.backends import ARCHIVE_SPECS
36 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
36 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
37 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
37 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
38 from vcs.nodes import FileNode, NodeKind
38 from vcs.nodes import FileNode, NodeKind
39 from vcs.utils import diffs as differ
39 from vcs.utils import diffs as differ
40
40
41 from rhodecode.lib import convert_line_endings, detect_mode, safe_str
41 from rhodecode.lib import convert_line_endings, detect_mode, safe_str
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
43 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.base import BaseRepoController, render
44 from rhodecode.lib.utils import EmptyChangeset
44 from rhodecode.lib.utils import EmptyChangeset
45 import rhodecode.lib.helpers as h
45 import rhodecode.lib.helpers as h
46 from rhodecode.model.repo import RepoModel
46 from rhodecode.model.repo import RepoModel
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50
51 class FilesController(BaseRepoController):
51 class FilesController(BaseRepoController):
52
52
53 @LoginRequired()
53 @LoginRequired()
54 def __before__(self):
54 def __before__(self):
55 super(FilesController, self).__before__()
55 super(FilesController, self).__before__()
56 c.cut_off_limit = self.cut_off_limit
56 c.cut_off_limit = self.cut_off_limit
57
57
58 def __get_cs_or_redirect(self, rev, repo_name):
58 def __get_cs_or_redirect(self, rev, repo_name):
59 """
59 """
60 Safe way to get changeset if error occur it redirects to tip with
60 Safe way to get changeset if error occur it redirects to tip with
61 proper message
61 proper message
62
62
63 :param rev: revision to fetch
63 :param rev: revision to fetch
64 :param repo_name: repo name to redirect after
64 :param repo_name: repo name to redirect after
65 """
65 """
66
66
67 try:
67 try:
68 return c.rhodecode_repo.get_changeset(rev)
68 return c.rhodecode_repo.get_changeset(rev)
69 except EmptyRepositoryError, e:
69 except EmptyRepositoryError, e:
70 h.flash(_('There are no files yet'), category='warning')
70 h.flash(_('There are no files yet'), category='warning')
71 redirect(h.url('summary_home', repo_name=repo_name))
71 redirect(h.url('summary_home', repo_name=repo_name))
72
72
73 except RepositoryError, e:
73 except RepositoryError, e:
74 h.flash(str(e), category='warning')
74 h.flash(str(e), category='warning')
75 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
75 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
76
76
77 def __get_filenode_or_redirect(self, repo_name, cs, path):
77 def __get_filenode_or_redirect(self, repo_name, cs, path):
78 """
78 """
79 Returns file_node, if error occurs or given path is directory,
79 Returns file_node, if error occurs or given path is directory,
80 it'll redirect to top level path
80 it'll redirect to top level path
81
81
82 :param repo_name: repo_name
82 :param repo_name: repo_name
83 :param cs: given changeset
83 :param cs: given changeset
84 :param path: path to lookup
84 :param path: path to lookup
85 """
85 """
86
86
87 try:
87 try:
88 file_node = cs.get_node(path)
88 file_node = cs.get_node(path)
89 if file_node.is_dir():
89 if file_node.is_dir():
90 raise RepositoryError('given path is a directory')
90 raise RepositoryError('given path is a directory')
91 except RepositoryError, e:
91 except RepositoryError, e:
92 h.flash(str(e), category='warning')
92 h.flash(str(e), category='warning')
93 redirect(h.url('files_home', repo_name=repo_name,
93 redirect(h.url('files_home', repo_name=repo_name,
94 revision=cs.raw_id))
94 revision=cs.raw_id))
95
95
96 return file_node
96 return file_node
97
97
98 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
98 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
99 'repository.admin')
99 'repository.admin')
100 def index(self, repo_name, revision, f_path):
100 def index(self, repo_name, revision, f_path):
101 #reditect to given revision from form if given
101 #reditect to given revision from form if given
102 post_revision = request.POST.get('at_rev', None)
102 post_revision = request.POST.get('at_rev', None)
103 if post_revision:
103 if post_revision:
104 cs = self.__get_cs_or_redirect(post_revision, repo_name)
104 cs = self.__get_cs_or_redirect(post_revision, repo_name)
105 redirect(url('files_home', repo_name=c.repo_name,
105 redirect(url('files_home', repo_name=c.repo_name,
106 revision=cs.raw_id, f_path=f_path))
106 revision=cs.raw_id, f_path=f_path))
107
107
108 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
108 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
109 c.branch = request.GET.get('branch', None)
109 c.branch = request.GET.get('branch', None)
110 c.f_path = f_path
110 c.f_path = f_path
111
111
112 cur_rev = c.changeset.revision
112 cur_rev = c.changeset.revision
113
113
114 #prev link
114 #prev link
115 try:
115 try:
116 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
116 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
117 c.url_prev = url('files_home', repo_name=c.repo_name,
117 c.url_prev = url('files_home', repo_name=c.repo_name,
118 revision=prev_rev.raw_id, f_path=f_path)
118 revision=prev_rev.raw_id, f_path=f_path)
119 if c.branch:
119 if c.branch:
120 c.url_prev += '?branch=%s' % c.branch
120 c.url_prev += '?branch=%s' % c.branch
121 except (ChangesetDoesNotExistError, VCSError):
121 except (ChangesetDoesNotExistError, VCSError):
122 c.url_prev = '#'
122 c.url_prev = '#'
123
123
124 #next link
124 #next link
125 try:
125 try:
126 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
126 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
127 c.url_next = url('files_home', repo_name=c.repo_name,
127 c.url_next = url('files_home', repo_name=c.repo_name,
128 revision=next_rev.raw_id, f_path=f_path)
128 revision=next_rev.raw_id, f_path=f_path)
129 if c.branch:
129 if c.branch:
130 c.url_next += '?branch=%s' % c.branch
130 c.url_next += '?branch=%s' % c.branch
131 except (ChangesetDoesNotExistError, VCSError):
131 except (ChangesetDoesNotExistError, VCSError):
132 c.url_next = '#'
132 c.url_next = '#'
133
133
134 #files or dirs
134 #files or dirs
135 try:
135 try:
136 c.files_list = c.changeset.get_node(f_path)
136 c.files_list = c.changeset.get_node(f_path)
137
137
138 if c.files_list.is_file():
138 if c.files_list.is_file():
139 c.file_history = self._get_node_history(c.changeset, f_path)
139 c.file_history = self._get_node_history(c.changeset, f_path)
140 else:
140 else:
141 c.file_history = []
141 c.file_history = []
142 except RepositoryError, e:
142 except RepositoryError, e:
143 h.flash(str(e), category='warning')
143 h.flash(str(e), category='warning')
144 redirect(h.url('files_home', repo_name=repo_name,
144 redirect(h.url('files_home', repo_name=repo_name,
145 revision=revision))
145 revision=revision))
146
146
147 return render('files/files.html')
147 return render('files/files.html')
148
148
149 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
149 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
150 'repository.admin')
150 'repository.admin')
151 def rawfile(self, repo_name, revision, f_path):
151 def rawfile(self, repo_name, revision, f_path):
152 cs = self.__get_cs_or_redirect(revision, repo_name)
152 cs = self.__get_cs_or_redirect(revision, repo_name)
153 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
153 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
154
154
155 response.content_disposition = 'attachment; filename=%s' % \
155 response.content_disposition = 'attachment; filename=%s' % \
156 safe_str(f_path.split(os.sep)[-1])
156 safe_str(f_path.split(os.sep)[-1])
157
157
158 response.content_type = file_node.mimetype
158 response.content_type = file_node.mimetype
159 return file_node.content
159 return file_node.content
160
160
161 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
161 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
162 'repository.admin')
162 'repository.admin')
163 def raw(self, repo_name, revision, f_path):
163 def raw(self, repo_name, revision, f_path):
164 cs = self.__get_cs_or_redirect(revision, repo_name)
164 cs = self.__get_cs_or_redirect(revision, repo_name)
165 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
165 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
166
166
167 raw_mimetype_mapping = {
167 raw_mimetype_mapping = {
168 # map original mimetype to a mimetype used for "show as raw"
168 # map original mimetype to a mimetype used for "show as raw"
169 # you can also provide a content-disposition to override the
169 # you can also provide a content-disposition to override the
170 # default "attachment" disposition.
170 # default "attachment" disposition.
171 # orig_type: (new_type, new_dispo)
171 # orig_type: (new_type, new_dispo)
172
172
173 # show images inline:
173 # show images inline:
174 'image/x-icon': ('image/x-icon', 'inline'),
174 'image/x-icon': ('image/x-icon', 'inline'),
175 'image/png': ('image/png', 'inline'),
175 'image/png': ('image/png', 'inline'),
176 'image/gif': ('image/gif', 'inline'),
176 'image/gif': ('image/gif', 'inline'),
177 'image/jpeg': ('image/jpeg', 'inline'),
177 'image/jpeg': ('image/jpeg', 'inline'),
178 'image/svg+xml': ('image/svg+xml', 'inline'),
178 'image/svg+xml': ('image/svg+xml', 'inline'),
179 }
179 }
180
180
181 mimetype = file_node.mimetype
181 mimetype = file_node.mimetype
182 try:
182 try:
183 mimetype, dispo = raw_mimetype_mapping[mimetype]
183 mimetype, dispo = raw_mimetype_mapping[mimetype]
184 except KeyError:
184 except KeyError:
185 # we don't know anything special about this, handle it safely
185 # we don't know anything special about this, handle it safely
186 if file_node.is_binary:
186 if file_node.is_binary:
187 # do same as download raw for binary files
187 # do same as download raw for binary files
188 mimetype, dispo = 'application/octet-stream', 'attachment'
188 mimetype, dispo = 'application/octet-stream', 'attachment'
189 else:
189 else:
190 # do not just use the original mimetype, but force text/plain,
190 # do not just use the original mimetype, but force text/plain,
191 # otherwise it would serve text/html and that might be unsafe.
191 # otherwise it would serve text/html and that might be unsafe.
192 # Note: underlying vcs library fakes text/plain mimetype if the
192 # Note: underlying vcs library fakes text/plain mimetype if the
193 # mimetype can not be determined and it thinks it is not
193 # mimetype can not be determined and it thinks it is not
194 # binary.This might lead to erroneous text display in some
194 # binary.This might lead to erroneous text display in some
195 # cases, but helps in other cases, like with text files
195 # cases, but helps in other cases, like with text files
196 # without extension.
196 # without extension.
197 mimetype, dispo = 'text/plain', 'inline'
197 mimetype, dispo = 'text/plain', 'inline'
198
198
199 if dispo == 'attachment':
199 if dispo == 'attachment':
200 dispo = 'attachment; filename=%s' % \
200 dispo = 'attachment; filename=%s' % \
201 safe_str(f_path.split(os.sep)[-1])
201 safe_str(f_path.split(os.sep)[-1])
202
202
203 response.content_disposition = dispo
203 response.content_disposition = dispo
204 response.content_type = mimetype
204 response.content_type = mimetype
205 return file_node.content
205 return file_node.content
206
206
207 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
207 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
208 'repository.admin')
208 'repository.admin')
209 def annotate(self, repo_name, revision, f_path):
209 def annotate(self, repo_name, revision, f_path):
210 c.cs = self.__get_cs_or_redirect(revision, repo_name)
210 c.cs = self.__get_cs_or_redirect(revision, repo_name)
211 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
211 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
212
212
213 c.file_history = self._get_node_history(c.cs, f_path)
213 c.file_history = self._get_node_history(c.cs, f_path)
214 c.f_path = f_path
214 c.f_path = f_path
215 return render('files/files_annotate.html')
215 return render('files/files_annotate.html')
216
216
217 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
217 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
218 def edit(self, repo_name, revision, f_path):
218 def edit(self, repo_name, revision, f_path):
219 r_post = request.POST
219 r_post = request.POST
220
220
221 c.cs = self.__get_cs_or_redirect(revision, repo_name)
221 c.cs = self.__get_cs_or_redirect(revision, repo_name)
222 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
222 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
223
223
224 if c.file.is_binary:
224 if c.file.is_binary:
225 return redirect(url('files_home', repo_name=c.repo_name,
225 return redirect(url('files_home', repo_name=c.repo_name,
226 revision=c.cs.raw_id, f_path=f_path))
226 revision=c.cs.raw_id, f_path=f_path))
227
227
228 c.file_history = self._get_node_history(c.cs, f_path)
228 c.file_history = self._get_node_history(c.cs, f_path)
229 c.f_path = f_path
229 c.f_path = f_path
230
230
231 if r_post:
231 if r_post:
232
232
233 old_content = c.file.content
233 old_content = c.file.content
234 sl = old_content.splitlines(1)
234 sl = old_content.splitlines(1)
235 first_line = sl[0] if sl else ''
235 first_line = sl[0] if sl else ''
236 # modes: 0 - Unix, 1 - Mac, 2 - DOS
236 # modes: 0 - Unix, 1 - Mac, 2 - DOS
237 mode = detect_mode(first_line, 0)
237 mode = detect_mode(first_line, 0)
238 content = convert_line_endings(r_post.get('content'), mode)
238 content = convert_line_endings(r_post.get('content'), mode)
239
239
240 message = r_post.get('message') or (_('Edited %s via RhodeCode')
240 message = r_post.get('message') or (_('Edited %s via RhodeCode')
241 % (f_path))
241 % (f_path))
242 author = self.rhodecode_user.full_contact
242 author = self.rhodecode_user.full_contact
243
243
244 if content == old_content:
244 if content == old_content:
245 h.flash(_('No changes'),
245 h.flash(_('No changes'),
246 category='warning')
246 category='warning')
247 return redirect(url('changeset_home', repo_name=c.repo_name,
247 return redirect(url('changeset_home', repo_name=c.repo_name,
248 revision='tip'))
248 revision='tip'))
249
249
250 try:
250 try:
251 self.scm_model.commit_change(repo=c.rhodecode_repo,
251 self.scm_model.commit_change(repo=c.rhodecode_repo,
252 repo_name=repo_name, cs=c.cs,
252 repo_name=repo_name, cs=c.cs,
253 user=self.rhodecode_user,
253 user=self.rhodecode_user,
254 author=author, message=message,
254 author=author, message=message,
255 content=content, f_path=f_path)
255 content=content, f_path=f_path)
256 h.flash(_('Successfully committed to %s' % f_path),
256 h.flash(_('Successfully committed to %s' % f_path),
257 category='success')
257 category='success')
258
258
259 except Exception:
259 except Exception:
260 log.error(traceback.format_exc())
260 log.error(traceback.format_exc())
261 h.flash(_('Error occurred during commit'), category='error')
261 h.flash(_('Error occurred during commit'), category='error')
262 return redirect(url('changeset_home',
262 return redirect(url('changeset_home',
263 repo_name=c.repo_name, revision='tip'))
263 repo_name=c.repo_name, revision='tip'))
264
264
265 return render('files/files_edit.html')
265 return render('files/files_edit.html')
266
266
267 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
267 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
268 'repository.admin')
268 'repository.admin')
269 def archivefile(self, repo_name, fname):
269 def archivefile(self, repo_name, fname):
270
270
271 fileformat = None
271 fileformat = None
272 revision = None
272 revision = None
273 ext = None
273 ext = None
274 subrepos = request.GET.get('subrepos') == 'true'
274
275
275 for a_type, ext_data in ARCHIVE_SPECS.items():
276 for a_type, ext_data in ARCHIVE_SPECS.items():
276 archive_spec = fname.split(ext_data[1])
277 archive_spec = fname.split(ext_data[1])
277 if len(archive_spec) == 2 and archive_spec[1] == '':
278 if len(archive_spec) == 2 and archive_spec[1] == '':
278 fileformat = a_type or ext_data[1]
279 fileformat = a_type or ext_data[1]
279 revision = archive_spec[0]
280 revision = archive_spec[0]
280 ext = ext_data[1]
281 ext = ext_data[1]
281
282
282 try:
283 try:
283 dbrepo = RepoModel().get_by_repo_name(repo_name)
284 dbrepo = RepoModel().get_by_repo_name(repo_name)
284 if dbrepo.enable_downloads is False:
285 if dbrepo.enable_downloads is False:
285 return _('downloads disabled')
286 return _('downloads disabled')
286
287
287 cs = c.rhodecode_repo.get_changeset(revision)
288 cs = c.rhodecode_repo.get_changeset(revision)
288 content_type = ARCHIVE_SPECS[fileformat][0]
289 content_type = ARCHIVE_SPECS[fileformat][0]
289 except ChangesetDoesNotExistError:
290 except ChangesetDoesNotExistError:
290 return _('Unknown revision %s') % revision
291 return _('Unknown revision %s') % revision
291 except EmptyRepositoryError:
292 except EmptyRepositoryError:
292 return _('Empty repository')
293 return _('Empty repository')
293 except (ImproperArchiveTypeError, KeyError):
294 except (ImproperArchiveTypeError, KeyError):
294 return _('Unknown archive type')
295 return _('Unknown archive type')
295
296
296 response.content_type = content_type
297 response.content_type = content_type
297 response.content_disposition = 'attachment; filename=%s-%s%s' \
298 response.content_disposition = 'attachment; filename=%s-%s%s' \
298 % (repo_name, revision, ext)
299 % (repo_name, revision, ext)
299
300
300 import tempfile
301 import tempfile
301 archive = tempfile.mkstemp()[1]
302 archive = tempfile.mkstemp()[1]
302 t = open(archive, 'wb')
303 t = open(archive, 'wb')
303 cs.fill_archive(stream=t, kind=fileformat)
304 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
304
305
305 def get_chunked_archive(archive):
306 def get_chunked_archive(archive):
306 stream = open(archive, 'rb')
307 stream = open(archive, 'rb')
307 while True:
308 while True:
308 data = stream.read(4096)
309 data = stream.read(4096)
309 if not data:
310 if not data:
310 os.remove(archive)
311 os.remove(archive)
311 break
312 break
312 yield data
313 yield data
313
314
314 return get_chunked_archive(archive)
315 return get_chunked_archive(archive)
315
316
316 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
317 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
317 'repository.admin')
318 'repository.admin')
318 def diff(self, repo_name, f_path):
319 def diff(self, repo_name, f_path):
319 diff1 = request.GET.get('diff1')
320 diff1 = request.GET.get('diff1')
320 diff2 = request.GET.get('diff2')
321 diff2 = request.GET.get('diff2')
321 c.action = request.GET.get('diff')
322 c.action = request.GET.get('diff')
322 c.no_changes = diff1 == diff2
323 c.no_changes = diff1 == diff2
323 c.f_path = f_path
324 c.f_path = f_path
324 c.big_diff = False
325 c.big_diff = False
325
326
326 try:
327 try:
327 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
328 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
328 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
329 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
329 node1 = c.changeset_1.get_node(f_path)
330 node1 = c.changeset_1.get_node(f_path)
330 else:
331 else:
331 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
332 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
332 node1 = FileNode('.', '', changeset=c.changeset_1)
333 node1 = FileNode('.', '', changeset=c.changeset_1)
333
334
334 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
335 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
335 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
336 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
336 node2 = c.changeset_2.get_node(f_path)
337 node2 = c.changeset_2.get_node(f_path)
337 else:
338 else:
338 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
339 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
339 node2 = FileNode('.', '', changeset=c.changeset_2)
340 node2 = FileNode('.', '', changeset=c.changeset_2)
340 except RepositoryError:
341 except RepositoryError:
341 return redirect(url('files_home',
342 return redirect(url('files_home',
342 repo_name=c.repo_name, f_path=f_path))
343 repo_name=c.repo_name, f_path=f_path))
343
344
344 if c.action == 'download':
345 if c.action == 'download':
345 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
346 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
346 format='gitdiff')
347 format='gitdiff')
347
348
348 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
349 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
349 response.content_type = 'text/plain'
350 response.content_type = 'text/plain'
350 response.content_disposition = 'attachment; filename=%s' \
351 response.content_disposition = 'attachment; filename=%s' \
351 % diff_name
352 % diff_name
352 return diff.raw_diff()
353 return diff.raw_diff()
353
354
354 elif c.action == 'raw':
355 elif c.action == 'raw':
355 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
356 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
356 format='gitdiff')
357 format='gitdiff')
357 response.content_type = 'text/plain'
358 response.content_type = 'text/plain'
358 return diff.raw_diff()
359 return diff.raw_diff()
359
360
360 elif c.action == 'diff':
361 elif c.action == 'diff':
361 if node1.is_binary or node2.is_binary:
362 if node1.is_binary or node2.is_binary:
362 c.cur_diff = _('Binary file')
363 c.cur_diff = _('Binary file')
363 elif node1.size > self.cut_off_limit or \
364 elif node1.size > self.cut_off_limit or \
364 node2.size > self.cut_off_limit:
365 node2.size > self.cut_off_limit:
365 c.cur_diff = ''
366 c.cur_diff = ''
366 c.big_diff = True
367 c.big_diff = True
367 else:
368 else:
368 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
369 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
369 format='gitdiff')
370 format='gitdiff')
370 c.cur_diff = diff.as_html()
371 c.cur_diff = diff.as_html()
371 else:
372 else:
372
373
373 #default option
374 #default option
374 if node1.is_binary or node2.is_binary:
375 if node1.is_binary or node2.is_binary:
375 c.cur_diff = _('Binary file')
376 c.cur_diff = _('Binary file')
376 elif node1.size > self.cut_off_limit or \
377 elif node1.size > self.cut_off_limit or \
377 node2.size > self.cut_off_limit:
378 node2.size > self.cut_off_limit:
378 c.cur_diff = ''
379 c.cur_diff = ''
379 c.big_diff = True
380 c.big_diff = True
380
381
381 else:
382 else:
382 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
383 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
383 format='gitdiff')
384 format='gitdiff')
384 c.cur_diff = diff.as_html()
385 c.cur_diff = diff.as_html()
385
386
386 if not c.cur_diff and not c.big_diff:
387 if not c.cur_diff and not c.big_diff:
387 c.no_changes = True
388 c.no_changes = True
388 return render('files/file_diff.html')
389 return render('files/file_diff.html')
389
390
390 def _get_node_history(self, cs, f_path):
391 def _get_node_history(self, cs, f_path):
391 changesets = cs.get_file_history(f_path)
392 changesets = cs.get_file_history(f_path)
392 hist_l = []
393 hist_l = []
393
394
394 changesets_group = ([], _("Changesets"))
395 changesets_group = ([], _("Changesets"))
395 branches_group = ([], _("Branches"))
396 branches_group = ([], _("Branches"))
396 tags_group = ([], _("Tags"))
397 tags_group = ([], _("Tags"))
397
398
398 for chs in changesets:
399 for chs in changesets:
399 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
400 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
400 changesets_group[0].append((chs.raw_id, n_desc,))
401 changesets_group[0].append((chs.raw_id, n_desc,))
401
402
402 hist_l.append(changesets_group)
403 hist_l.append(changesets_group)
403
404
404 for name, chs in c.rhodecode_repo.branches.items():
405 for name, chs in c.rhodecode_repo.branches.items():
405 #chs = chs.split(':')[-1]
406 #chs = chs.split(':')[-1]
406 branches_group[0].append((chs, name),)
407 branches_group[0].append((chs, name),)
407 hist_l.append(branches_group)
408 hist_l.append(branches_group)
408
409
409 for name, chs in c.rhodecode_repo.tags.items():
410 for name, chs in c.rhodecode_repo.tags.items():
410 #chs = chs.split(':')[-1]
411 #chs = chs.split(':')[-1]
411 tags_group[0].append((chs, name),)
412 tags_group[0].append((chs, name),)
412 hist_l.append(tags_group)
413 hist_l.append(tags_group)
413
414
414 return hist_l
415 return hist_l
@@ -1,696 +1,700 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
4 ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(u'Home',h.url('/'))}
8 ${h.link_to(u'Home',h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.dbrepo.just_name,h.url('summary_home',repo_name=c.repo_name))}
10 ${h.link_to(c.dbrepo.just_name,h.url('summary_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('summary')}
12 ${_('summary')}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('summary')}
16 ${self.menu('summary')}
17 </%def>
17 </%def>
18
18
19 <%def name="main()">
19 <%def name="main()">
20 <div class="box box-left">
20 <div class="box box-left">
21 <!-- box / title -->
21 <!-- box / title -->
22 <div class="title">
22 <div class="title">
23 ${self.breadcrumbs()}
23 ${self.breadcrumbs()}
24 </div>
24 </div>
25 <!-- end box / title -->
25 <!-- end box / title -->
26 <div class="form">
26 <div class="form">
27 <div id="summary" class="fields">
27 <div id="summary" class="fields">
28
28
29 <div class="field">
29 <div class="field">
30 <div class="label">
30 <div class="label">
31 <label>${_('Name')}:</label>
31 <label>${_('Name')}:</label>
32 </div>
32 </div>
33 <div class="input-short">
33 <div class="input-short">
34 %if c.rhodecode_user.username != 'default':
34 %if c.rhodecode_user.username != 'default':
35 %if c.following:
35 %if c.following:
36 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
36 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
37 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
37 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
38 </span>
38 </span>
39 %else:
39 %else:
40 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
40 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
41 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
41 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
42 </span>
42 </span>
43 %endif
43 %endif
44 %endif:
44 %endif:
45
45
46 ##REPO TYPE
46 ##REPO TYPE
47 %if c.dbrepo.repo_type =='hg':
47 %if c.dbrepo.repo_type =='hg':
48 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
48 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="${h.url("/images/icons/hgicon.png")}"/>
49 %endif
49 %endif
50 %if c.dbrepo.repo_type =='git':
50 %if c.dbrepo.repo_type =='git':
51 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
51 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="${h.url("/images/icons/giticon.png")}"/>
52 %endif
52 %endif
53
53
54 ##PUBLIC/PRIVATE
54 ##PUBLIC/PRIVATE
55 %if c.dbrepo.private:
55 %if c.dbrepo.private:
56 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url("/images/icons/lock.png")}"/>
56 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="${h.url("/images/icons/lock.png")}"/>
57 %else:
57 %else:
58 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url("/images/icons/lock_open.png")}"/>
58 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="${h.url("/images/icons/lock_open.png")}"/>
59 %endif
59 %endif
60
60
61 ##REPO NAME
61 ##REPO NAME
62 <span class="repo_name">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
62 <span class="repo_name">${h.repo_link(c.dbrepo.groups_and_repo)}</span>
63
63
64 ##FORK
64 ##FORK
65 %if c.dbrepo.fork:
65 %if c.dbrepo.fork:
66 <div style="margin-top:5px;clear:both"">
66 <div style="margin-top:5px;clear:both"">
67 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}">
67 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}">
68 <img class="icon" alt="${_('public')}"
68 <img class="icon" alt="${_('public')}"
69 title="${_('Fork of')} ${c.dbrepo.fork.repo_name}"
69 title="${_('Fork of')} ${c.dbrepo.fork.repo_name}"
70 src="${h.url("/images/icons/arrow_divide.png")}"/>
70 src="${h.url("/images/icons/arrow_divide.png")}"/>
71 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
71 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
72 </a>
72 </a>
73 </div>
73 </div>
74 %endif
74 %endif
75 ##REMOTE
75 ##REMOTE
76 %if c.dbrepo.clone_uri:
76 %if c.dbrepo.clone_uri:
77 <div style="margin-top:5px;clear:both">
77 <div style="margin-top:5px;clear:both">
78 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}">
78 <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}">
79 <img class="icon" alt="${_('remote clone')}"
79 <img class="icon" alt="${_('remote clone')}"
80 title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}"
80 title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}"
81 src="${h.url("/images/icons/connect.png")}"/>
81 src="${h.url("/images/icons/connect.png")}"/>
82 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
82 ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}
83 </a>
83 </a>
84 </div>
84 </div>
85 %endif
85 %endif
86 </div>
86 </div>
87 </div>
87 </div>
88
88
89
89
90 <div class="field">
90 <div class="field">
91 <div class="label">
91 <div class="label">
92 <label>${_('Description')}:</label>
92 <label>${_('Description')}:</label>
93 </div>
93 </div>
94 <div class="input-short desc">${h.urlify_text(c.dbrepo.description)}</div>
94 <div class="input-short desc">${h.urlify_text(c.dbrepo.description)}</div>
95 </div>
95 </div>
96
96
97
97
98 <div class="field">
98 <div class="field">
99 <div class="label">
99 <div class="label">
100 <label>${_('Contact')}:</label>
100 <label>${_('Contact')}:</label>
101 </div>
101 </div>
102 <div class="input-short">
102 <div class="input-short">
103 <div class="gravatar">
103 <div class="gravatar">
104 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
104 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
105 </div>
105 </div>
106 ${_('Username')}: ${c.dbrepo.user.username}<br/>
106 ${_('Username')}: ${c.dbrepo.user.username}<br/>
107 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
107 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
108 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
108 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
109 </div>
109 </div>
110 </div>
110 </div>
111
111
112 <div class="field">
112 <div class="field">
113 <div class="label">
113 <div class="label">
114 <label>${_('Last change')}:</label>
114 <label>${_('Last change')}:</label>
115 </div>
115 </div>
116 <div class="input-short">
116 <div class="input-short">
117 <b>${'r%s:%s' % (h.get_changeset_safe(c.rhodecode_repo,'tip').revision,
117 <b>${'r%s:%s' % (h.get_changeset_safe(c.rhodecode_repo,'tip').revision,
118 h.get_changeset_safe(c.rhodecode_repo,'tip').short_id)}</b> -
118 h.get_changeset_safe(c.rhodecode_repo,'tip').short_id)}</b> -
119 <span class="tooltip" title="${c.rhodecode_repo.last_change}">
119 <span class="tooltip" title="${c.rhodecode_repo.last_change}">
120 ${h.age(c.rhodecode_repo.last_change)}</span><br/>
120 ${h.age(c.rhodecode_repo.last_change)}</span><br/>
121 ${_('by')} ${h.get_changeset_safe(c.rhodecode_repo,'tip').author}
121 ${_('by')} ${h.get_changeset_safe(c.rhodecode_repo,'tip').author}
122
122
123 </div>
123 </div>
124 </div>
124 </div>
125
125
126 <div class="field">
126 <div class="field">
127 <div class="label">
127 <div class="label">
128 <label>${_('Clone url')}:</label>
128 <label>${_('Clone url')}:</label>
129 </div>
129 </div>
130 <div class="input-short">
130 <div class="input-short">
131 <input type="text" id="clone_url" readonly="readonly" value="${c.rhodecode_repo.alias} clone ${c.clone_repo_url}" size="70"/>
131 <input type="text" id="clone_url" readonly="readonly" value="${c.rhodecode_repo.alias} clone ${c.clone_repo_url}" size="70"/>
132 </div>
132 </div>
133 </div>
133 </div>
134
134
135 <div class="field">
135 <div class="field">
136 <div class="label">
136 <div class="label">
137 <label>${_('Trending source files')}:</label>
137 <label>${_('Trending source files')}:</label>
138 </div>
138 </div>
139 <div class="input-short">
139 <div class="input-short">
140 <div id="lang_stats"></div>
140 <div id="lang_stats"></div>
141 </div>
141 </div>
142 </div>
142 </div>
143
143
144 <div class="field">
144 <div class="field">
145 <div class="label">
145 <div class="label">
146 <label>${_('Download')}:</label>
146 <label>${_('Download')}:</label>
147 </div>
147 </div>
148 <div class="input-short">
148 <div class="input-short">
149 %if len(c.rhodecode_repo.revisions) == 0:
149 %if len(c.rhodecode_repo.revisions) == 0:
150 ${_('There are no downloads yet')}
150 ${_('There are no downloads yet')}
151 %elif c.enable_downloads is False:
151 %elif c.enable_downloads is False:
152 ${_('Downloads are disabled for this repository')}
152 ${_('Downloads are disabled for this repository')}
153 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
153 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
154 [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
154 [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
155 %endif
155 %endif
156 %else:
156 %else:
157 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
157 ${h.select('download_options',c.rhodecode_repo.get_changeset().raw_id,c.download_options)}
158 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
158 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
159 %if cnt >=1:
159 %if cnt >=1:
160 |
160 |
161 %endif
161 %endif
162 <span class="tooltip" title="${_('Download %s as %s') %('tip',archive['type'])}"
162 <span class="tooltip" title="${_('Download %s as %s') %('tip',archive['type'])}"
163 id="${archive['type']+'_link'}">${h.link_to(archive['type'],
163 id="${archive['type']+'_link'}">${h.link_to(archive['type'],
164 h.url('files_archive_home',repo_name=c.dbrepo.repo_name,
164 h.url('files_archive_home',repo_name=c.dbrepo.repo_name,
165 fname='tip'+archive['extension']),class_="archive_icon")}</span>
165 fname='tip'+archive['extension']),class_="archive_icon")}</span>
166 %endfor
166 %endfor
167 <span style="vertical-align: bottom">
168 <input id="archive_subrepos" type="checkbox" name="subrepos"/> <span class="tooltip" title="${_('Check this to download archive with subrepos')}" >${_('with subrepos')}</span>
169 </span>
167 %endif
170 %endif
168 </div>
171 </div>
169 </div>
172 </div>
170
173
171 <div class="field">
174 <div class="field">
172 <div class="label">
175 <div class="label">
173 <label>${_('Feeds')}:</label>
176 <label>${_('Feeds')}:</label>
174 </div>
177 </div>
175 <div class="input-short">
178 <div class="input-short">
176 %if c.rhodecode_user.username != 'default':
179 %if c.rhodecode_user.username != 'default':
177 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
180 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='rss_icon')}
178 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
181 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name,api_key=c.rhodecode_user.api_key),class_='atom_icon')}
179 %else:
182 %else:
180 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
183 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.dbrepo.repo_name),class_='rss_icon')}
181 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
184 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.dbrepo.repo_name),class_='atom_icon')}
182 %endif
185 %endif
183 </div>
186 </div>
184 </div>
187 </div>
185 </div>
188 </div>
186 </div>
189 </div>
187 <script type="text/javascript">
190 <script type="text/javascript">
188 YUE.onDOMReady(function(e){
191 YUE.onDOMReady(function(e){
189 id = 'clone_url';
192 id = 'clone_url';
190 YUE.on(id,'click',function(e){
193 YUE.on(id,'click',function(e){
191 if(YUD.hasClass(id,'selected')){
194 if(YUD.hasClass(id,'selected')){
192 return
195 return
193 }
196 }
194 else{
197 else{
195 YUD.addClass(id,'selected');
198 YUD.addClass(id,'selected');
196 YUD.get(id).select();
199 YUD.get(id).select();
197 }
200 }
198
201
199 })
202 })
200 })
203 })
201 var data = ${c.trending_languages|n};
204 var data = ${c.trending_languages|n};
202 var total = 0;
205 var total = 0;
203 var no_data = true;
206 var no_data = true;
204 for (k in data){
207 for (k in data){
205 total += data[k].count;
208 total += data[k].count;
206 no_data = false;
209 no_data = false;
207 }
210 }
208 var tbl = document.createElement('table');
211 var tbl = document.createElement('table');
209 tbl.setAttribute('class','trending_language_tbl');
212 tbl.setAttribute('class','trending_language_tbl');
210 var cnt = 0;
213 var cnt = 0;
211 for (k in data){
214 for (k in data){
212 cnt += 1;
215 cnt += 1;
213 var hide = cnt>2;
216 var hide = cnt>2;
214 var tr = document.createElement('tr');
217 var tr = document.createElement('tr');
215 if (hide){
218 if (hide){
216 tr.setAttribute('style','display:none');
219 tr.setAttribute('style','display:none');
217 tr.setAttribute('class','stats_hidden');
220 tr.setAttribute('class','stats_hidden');
218 }
221 }
219 var percentage = Math.round((data[k].count/total*100),2);
222 var percentage = Math.round((data[k].count/total*100),2);
220 var value = data[k].count;
223 var value = data[k].count;
221 var td1 = document.createElement('td');
224 var td1 = document.createElement('td');
222 td1.width = 150;
225 td1.width = 150;
223 var trending_language_label = document.createElement('div');
226 var trending_language_label = document.createElement('div');
224 trending_language_label.innerHTML = data[k].desc+" ("+k+")";
227 trending_language_label.innerHTML = data[k].desc+" ("+k+")";
225 td1.appendChild(trending_language_label);
228 td1.appendChild(trending_language_label);
226
229
227 var td2 = document.createElement('td');
230 var td2 = document.createElement('td');
228 td2.setAttribute('style','padding-right:14px !important');
231 td2.setAttribute('style','padding-right:14px !important');
229 var trending_language = document.createElement('div');
232 var trending_language = document.createElement('div');
230 var nr_files = value+" ${_('files')}";
233 var nr_files = value+" ${_('files')}";
231
234
232 trending_language.title = k+" "+nr_files;
235 trending_language.title = k+" "+nr_files;
233
236
234 if (percentage>22){
237 if (percentage>22){
235 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
238 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";
236 }
239 }
237 else{
240 else{
238 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
241 trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
239 }
242 }
240
243
241 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
244 trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
242 trending_language.style.width=percentage+"%";
245 trending_language.style.width=percentage+"%";
243 td2.appendChild(trending_language);
246 td2.appendChild(trending_language);
244
247
245 tr.appendChild(td1);
248 tr.appendChild(td1);
246 tr.appendChild(td2);
249 tr.appendChild(td2);
247 tbl.appendChild(tr);
250 tbl.appendChild(tr);
248 if(cnt == 3){
251 if(cnt == 3){
249 var show_more = document.createElement('tr');
252 var show_more = document.createElement('tr');
250 var td = document.createElement('td');
253 var td = document.createElement('td');
251 lnk = document.createElement('a');
254 lnk = document.createElement('a');
252
255
253 lnk.href='#';
256 lnk.href='#';
254 lnk.innerHTML = "${_('show more')}";
257 lnk.innerHTML = "${_('show more')}";
255 lnk.id='code_stats_show_more';
258 lnk.id='code_stats_show_more';
256 td.appendChild(lnk);
259 td.appendChild(lnk);
257
260
258 show_more.appendChild(td);
261 show_more.appendChild(td);
259 show_more.appendChild(document.createElement('td'));
262 show_more.appendChild(document.createElement('td'));
260 tbl.appendChild(show_more);
263 tbl.appendChild(show_more);
261 }
264 }
262
265
263 }
266 }
264 if(no_data){
267 if(no_data){
265 var tr = document.createElement('tr');
268 var tr = document.createElement('tr');
266 var td1 = document.createElement('td');
269 var td1 = document.createElement('td');
267 td1.innerHTML = "${c.no_data_msg}";
270 td1.innerHTML = "${c.no_data_msg}";
268 tr.appendChild(td1);
271 tr.appendChild(td1);
269 tbl.appendChild(tr);
272 tbl.appendChild(tr);
270 }
273 }
271 YUD.get('lang_stats').appendChild(tbl);
274 YUD.get('lang_stats').appendChild(tbl);
272 YUE.on('code_stats_show_more','click',function(){
275 YUE.on('code_stats_show_more','click',function(){
273 l = YUD.getElementsByClassName('stats_hidden')
276 l = YUD.getElementsByClassName('stats_hidden')
274 for (e in l){
277 for (e in l){
275 YUD.setStyle(l[e],'display','');
278 YUD.setStyle(l[e],'display','');
276 };
279 };
277 YUD.setStyle(YUD.get('code_stats_show_more'),
280 YUD.setStyle(YUD.get('code_stats_show_more'),
278 'display','none');
281 'display','none');
279 })
282 })
280
283
281
284 var tmpl_links = {}
282 YUE.on('download_options','change',function(e){
285 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
283 var new_cs = e.target.options[e.target.selectedIndex];
286 tmpl_links['${archive['type']}'] = '${h.link_to(archive['type'],
284 var tmpl_links = {}
287 h.url('files_archive_home',repo_name=c.dbrepo.repo_name,
285 %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()):
288 fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_="archive_icon")}';
286 tmpl_links['${archive['type']}'] = '${h.link_to(archive['type'],
289 %endfor
287 h.url('files_archive_home',repo_name=c.dbrepo.repo_name,
290
288 fname='__CS__'+archive['extension']),class_="archive_icon")}';
291 YUE.on(['download_options','archive_subrepos'],'change',function(e){
289 %endfor
292 var sm = YUD.get('download_options');
290
293 var new_cs = sm.options[sm.selectedIndex];
291
294
292 for(k in tmpl_links){
295 for(k in tmpl_links){
293 var s = YUD.get(k+'_link')
296 var s = YUD.get(k+'_link');
294 title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
297 title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}";
295 s.title = title_tmpl.replace('__CS_NAME__',new_cs.text);
298 s.title = title_tmpl.replace('__CS_NAME__',new_cs.text);
296 s.title = s.title.replace('__CS_EXT__',k);
299 s.title = s.title.replace('__CS_EXT__',k);
297 s.innerHTML = tmpl_links[k].replace('__CS__',new_cs.value);
300 var url = tmpl_links[k].replace('__CS__',new_cs.value);
301 var subrepos = YUD.get('archive_subrepos').checked
302 url = url.replace('__SUB__',subrepos);
303 s.innerHTML = url
298 }
304 }
299
305 });
300 })
301
302 </script>
306 </script>
303 </div>
307 </div>
304
308
305 <div class="box box-right" style="min-height:455px">
309 <div class="box box-right" style="min-height:455px">
306 <!-- box / title -->
310 <!-- box / title -->
307 <div class="title">
311 <div class="title">
308 <h5>${_('Commit activity by day / author')}</h5>
312 <h5>${_('Commit activity by day / author')}</h5>
309 </div>
313 </div>
310
314
311 <div class="graph">
315 <div class="graph">
312 <div style="padding:0 10px 10px 15px;font-size: 1.2em;">
316 <div style="padding:0 10px 10px 15px;font-size: 1.2em;">
313 %if c.no_data:
317 %if c.no_data:
314 ${c.no_data_msg}
318 ${c.no_data_msg}
315 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
319 %if h.HasPermissionAll('hg.admin')('enable stats on from summary'):
316 [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
320 [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
317 %endif
321 %endif
318
322
319 %else:
323 %else:
320 ${_('Loaded in')} ${c.stats_percentage} %
324 ${_('Loaded in')} ${c.stats_percentage} %
321 %endif
325 %endif
322 </div>
326 </div>
323 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
327 <div id="commit_history" style="width:450px;height:300px;float:left"></div>
324 <div style="clear: both;height: 10px"></div>
328 <div style="clear: both;height: 10px"></div>
325 <div id="overview" style="width:450px;height:100px;float:left"></div>
329 <div id="overview" style="width:450px;height:100px;float:left"></div>
326
330
327 <div id="legend_data" style="clear:both;margin-top:10px;">
331 <div id="legend_data" style="clear:both;margin-top:10px;">
328 <div id="legend_container"></div>
332 <div id="legend_container"></div>
329 <div id="legend_choices">
333 <div id="legend_choices">
330 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
334 <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
331 </div>
335 </div>
332 </div>
336 </div>
333 <script type="text/javascript">
337 <script type="text/javascript">
334 /**
338 /**
335 * Plots summary graph
339 * Plots summary graph
336 *
340 *
337 * @class SummaryPlot
341 * @class SummaryPlot
338 * @param {from} initial from for detailed graph
342 * @param {from} initial from for detailed graph
339 * @param {to} initial to for detailed graph
343 * @param {to} initial to for detailed graph
340 * @param {dataset}
344 * @param {dataset}
341 * @param {overview_dataset}
345 * @param {overview_dataset}
342 */
346 */
343 function SummaryPlot(from,to,dataset,overview_dataset) {
347 function SummaryPlot(from,to,dataset,overview_dataset) {
344 var initial_ranges = {
348 var initial_ranges = {
345 "xaxis":{
349 "xaxis":{
346 "from":from,
350 "from":from,
347 "to":to,
351 "to":to,
348 },
352 },
349 };
353 };
350 var dataset = dataset;
354 var dataset = dataset;
351 var overview_dataset = [overview_dataset];
355 var overview_dataset = [overview_dataset];
352 var choiceContainer = YUD.get("legend_choices");
356 var choiceContainer = YUD.get("legend_choices");
353 var choiceContainerTable = YUD.get("legend_choices_tables");
357 var choiceContainerTable = YUD.get("legend_choices_tables");
354 var plotContainer = YUD.get('commit_history');
358 var plotContainer = YUD.get('commit_history');
355 var overviewContainer = YUD.get('overview');
359 var overviewContainer = YUD.get('overview');
356
360
357 var plot_options = {
361 var plot_options = {
358 bars: {show:true,align:'center',lineWidth:4},
362 bars: {show:true,align:'center',lineWidth:4},
359 legend: {show:true, container:"legend_container"},
363 legend: {show:true, container:"legend_container"},
360 points: {show:true,radius:0,fill:false},
364 points: {show:true,radius:0,fill:false},
361 yaxis: {tickDecimals:0,},
365 yaxis: {tickDecimals:0,},
362 xaxis: {
366 xaxis: {
363 mode: "time",
367 mode: "time",
364 timeformat: "%d/%m",
368 timeformat: "%d/%m",
365 min:from,
369 min:from,
366 max:to,
370 max:to,
367 },
371 },
368 grid: {
372 grid: {
369 hoverable: true,
373 hoverable: true,
370 clickable: true,
374 clickable: true,
371 autoHighlight:true,
375 autoHighlight:true,
372 color: "#999"
376 color: "#999"
373 },
377 },
374 //selection: {mode: "x"}
378 //selection: {mode: "x"}
375 };
379 };
376 var overview_options = {
380 var overview_options = {
377 legend:{show:false},
381 legend:{show:false},
378 bars: {show:true,barWidth: 2,},
382 bars: {show:true,barWidth: 2,},
379 shadowSize: 0,
383 shadowSize: 0,
380 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
384 xaxis: {mode: "time", timeformat: "%d/%m/%y",},
381 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
385 yaxis: {ticks: 3, min: 0,tickDecimals:0,},
382 grid: {color: "#999",},
386 grid: {color: "#999",},
383 selection: {mode: "x"}
387 selection: {mode: "x"}
384 };
388 };
385
389
386 /**
390 /**
387 *get dummy data needed in few places
391 *get dummy data needed in few places
388 */
392 */
389 function getDummyData(label){
393 function getDummyData(label){
390 return {"label":label,
394 return {"label":label,
391 "data":[{"time":0,
395 "data":[{"time":0,
392 "commits":0,
396 "commits":0,
393 "added":0,
397 "added":0,
394 "changed":0,
398 "changed":0,
395 "removed":0,
399 "removed":0,
396 }],
400 }],
397 "schema":["commits"],
401 "schema":["commits"],
398 "color":'#ffffff',
402 "color":'#ffffff',
399 }
403 }
400 }
404 }
401
405
402 /**
406 /**
403 * generate checkboxes accordindly to data
407 * generate checkboxes accordindly to data
404 * @param keys
408 * @param keys
405 * @returns
409 * @returns
406 */
410 */
407 function generateCheckboxes(data) {
411 function generateCheckboxes(data) {
408 //append checkboxes
412 //append checkboxes
409 var i = 0;
413 var i = 0;
410 choiceContainerTable.innerHTML = '';
414 choiceContainerTable.innerHTML = '';
411 for(var pos in data) {
415 for(var pos in data) {
412
416
413 data[pos].color = i;
417 data[pos].color = i;
414 i++;
418 i++;
415 if(data[pos].label != ''){
419 if(data[pos].label != ''){
416 choiceContainerTable.innerHTML += '<tr><td>'+
420 choiceContainerTable.innerHTML += '<tr><td>'+
417 '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
421 '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
418 +data[pos].label+
422 +data[pos].label+
419 '</td></tr>';
423 '</td></tr>';
420 }
424 }
421 }
425 }
422 }
426 }
423
427
424 /**
428 /**
425 * ToolTip show
429 * ToolTip show
426 */
430 */
427 function showTooltip(x, y, contents) {
431 function showTooltip(x, y, contents) {
428 var div=document.getElementById('tooltip');
432 var div=document.getElementById('tooltip');
429 if(!div) {
433 if(!div) {
430 div = document.createElement('div');
434 div = document.createElement('div');
431 div.id="tooltip";
435 div.id="tooltip";
432 div.style.position="absolute";
436 div.style.position="absolute";
433 div.style.border='1px solid #fdd';
437 div.style.border='1px solid #fdd';
434 div.style.padding='2px';
438 div.style.padding='2px';
435 div.style.backgroundColor='#fee';
439 div.style.backgroundColor='#fee';
436 document.body.appendChild(div);
440 document.body.appendChild(div);
437 }
441 }
438 YUD.setStyle(div, 'opacity', 0);
442 YUD.setStyle(div, 'opacity', 0);
439 div.innerHTML = contents;
443 div.innerHTML = contents;
440 div.style.top=(y + 5) + "px";
444 div.style.top=(y + 5) + "px";
441 div.style.left=(x + 5) + "px";
445 div.style.left=(x + 5) + "px";
442
446
443 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
447 var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
444 anim.animate();
448 anim.animate();
445 }
449 }
446
450
447 /**
451 /**
448 * This function will detect if selected period has some changesets
452 * This function will detect if selected period has some changesets
449 for this user if it does this data is then pushed for displaying
453 for this user if it does this data is then pushed for displaying
450 Additionally it will only display users that are selected by the checkbox
454 Additionally it will only display users that are selected by the checkbox
451 */
455 */
452 function getDataAccordingToRanges(ranges) {
456 function getDataAccordingToRanges(ranges) {
453
457
454 var data = [];
458 var data = [];
455 var new_dataset = {};
459 var new_dataset = {};
456 var keys = [];
460 var keys = [];
457 var max_commits = 0;
461 var max_commits = 0;
458 for(var key in dataset){
462 for(var key in dataset){
459
463
460 for(var ds in dataset[key].data){
464 for(var ds in dataset[key].data){
461 commit_data = dataset[key].data[ds];
465 commit_data = dataset[key].data[ds];
462 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
466 if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
463
467
464 if(new_dataset[key] === undefined){
468 if(new_dataset[key] === undefined){
465 new_dataset[key] = {data:[],schema:["commits"],label:key};
469 new_dataset[key] = {data:[],schema:["commits"],label:key};
466 }
470 }
467 new_dataset[key].data.push(commit_data);
471 new_dataset[key].data.push(commit_data);
468 }
472 }
469 }
473 }
470 if (new_dataset[key] !== undefined){
474 if (new_dataset[key] !== undefined){
471 data.push(new_dataset[key]);
475 data.push(new_dataset[key]);
472 }
476 }
473 }
477 }
474
478
475 if (data.length > 0){
479 if (data.length > 0){
476 return data;
480 return data;
477 }
481 }
478 else{
482 else{
479 //just return dummy data for graph to plot itself
483 //just return dummy data for graph to plot itself
480 return [getDummyData('')];
484 return [getDummyData('')];
481 }
485 }
482 }
486 }
483
487
484 /**
488 /**
485 * redraw using new checkbox data
489 * redraw using new checkbox data
486 */
490 */
487 function plotchoiced(e,args){
491 function plotchoiced(e,args){
488 var cur_data = args[0];
492 var cur_data = args[0];
489 var cur_ranges = args[1];
493 var cur_ranges = args[1];
490
494
491 var new_data = [];
495 var new_data = [];
492 var inputs = choiceContainer.getElementsByTagName("input");
496 var inputs = choiceContainer.getElementsByTagName("input");
493
497
494 //show only checked labels
498 //show only checked labels
495 for(var i=0; i<inputs.length; i++) {
499 for(var i=0; i<inputs.length; i++) {
496 var checkbox_key = inputs[i].name;
500 var checkbox_key = inputs[i].name;
497
501
498 if(inputs[i].checked){
502 if(inputs[i].checked){
499 for(var d in cur_data){
503 for(var d in cur_data){
500 if(cur_data[d].label == checkbox_key){
504 if(cur_data[d].label == checkbox_key){
501 new_data.push(cur_data[d]);
505 new_data.push(cur_data[d]);
502 }
506 }
503 }
507 }
504 }
508 }
505 else{
509 else{
506 //push dummy data to not hide the label
510 //push dummy data to not hide the label
507 new_data.push(getDummyData(checkbox_key));
511 new_data.push(getDummyData(checkbox_key));
508 }
512 }
509 }
513 }
510
514
511 var new_options = YAHOO.lang.merge(plot_options, {
515 var new_options = YAHOO.lang.merge(plot_options, {
512 xaxis: {
516 xaxis: {
513 min: cur_ranges.xaxis.from,
517 min: cur_ranges.xaxis.from,
514 max: cur_ranges.xaxis.to,
518 max: cur_ranges.xaxis.to,
515 mode:"time",
519 mode:"time",
516 timeformat: "%d/%m",
520 timeformat: "%d/%m",
517 },
521 },
518 });
522 });
519 if (!new_data){
523 if (!new_data){
520 new_data = [[0,1]];
524 new_data = [[0,1]];
521 }
525 }
522 // do the zooming
526 // do the zooming
523 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
527 plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
524
528
525 plot.subscribe("plotselected", plotselected);
529 plot.subscribe("plotselected", plotselected);
526
530
527 //resubscribe plothover
531 //resubscribe plothover
528 plot.subscribe("plothover", plothover);
532 plot.subscribe("plothover", plothover);
529
533
530 // don't fire event on the overview to prevent eternal loop
534 // don't fire event on the overview to prevent eternal loop
531 overview.setSelection(cur_ranges, true);
535 overview.setSelection(cur_ranges, true);
532
536
533 }
537 }
534
538
535 /**
539 /**
536 * plot only selected items from overview
540 * plot only selected items from overview
537 * @param ranges
541 * @param ranges
538 * @returns
542 * @returns
539 */
543 */
540 function plotselected(ranges,cur_data) {
544 function plotselected(ranges,cur_data) {
541 //updates the data for new plot
545 //updates the data for new plot
542 var data = getDataAccordingToRanges(ranges);
546 var data = getDataAccordingToRanges(ranges);
543 generateCheckboxes(data);
547 generateCheckboxes(data);
544
548
545 var new_options = YAHOO.lang.merge(plot_options, {
549 var new_options = YAHOO.lang.merge(plot_options, {
546 xaxis: {
550 xaxis: {
547 min: ranges.xaxis.from,
551 min: ranges.xaxis.from,
548 max: ranges.xaxis.to,
552 max: ranges.xaxis.to,
549 mode:"time",
553 mode:"time",
550 timeformat: "%d/%m",
554 timeformat: "%d/%m",
551 },
555 },
552 });
556 });
553 // do the zooming
557 // do the zooming
554 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
558 plot = YAHOO.widget.Flot(plotContainer, data, new_options);
555
559
556 plot.subscribe("plotselected", plotselected);
560 plot.subscribe("plotselected", plotselected);
557
561
558 //resubscribe plothover
562 //resubscribe plothover
559 plot.subscribe("plothover", plothover);
563 plot.subscribe("plothover", plothover);
560
564
561 // don't fire event on the overview to prevent eternal loop
565 // don't fire event on the overview to prevent eternal loop
562 overview.setSelection(ranges, true);
566 overview.setSelection(ranges, true);
563
567
564 //resubscribe choiced
568 //resubscribe choiced
565 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
569 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
566 }
570 }
567
571
568 var previousPoint = null;
572 var previousPoint = null;
569
573
570 function plothover(o) {
574 function plothover(o) {
571 var pos = o.pos;
575 var pos = o.pos;
572 var item = o.item;
576 var item = o.item;
573
577
574 //YUD.get("x").innerHTML = pos.x.toFixed(2);
578 //YUD.get("x").innerHTML = pos.x.toFixed(2);
575 //YUD.get("y").innerHTML = pos.y.toFixed(2);
579 //YUD.get("y").innerHTML = pos.y.toFixed(2);
576 if (item) {
580 if (item) {
577 if (previousPoint != item.datapoint) {
581 if (previousPoint != item.datapoint) {
578 previousPoint = item.datapoint;
582 previousPoint = item.datapoint;
579
583
580 var tooltip = YUD.get("tooltip");
584 var tooltip = YUD.get("tooltip");
581 if(tooltip) {
585 if(tooltip) {
582 tooltip.parentNode.removeChild(tooltip);
586 tooltip.parentNode.removeChild(tooltip);
583 }
587 }
584 var x = item.datapoint.x.toFixed(2);
588 var x = item.datapoint.x.toFixed(2);
585 var y = item.datapoint.y.toFixed(2);
589 var y = item.datapoint.y.toFixed(2);
586
590
587 if (!item.series.label){
591 if (!item.series.label){
588 item.series.label = 'commits';
592 item.series.label = 'commits';
589 }
593 }
590 var d = new Date(x*1000);
594 var d = new Date(x*1000);
591 var fd = d.toDateString()
595 var fd = d.toDateString()
592 var nr_commits = parseInt(y);
596 var nr_commits = parseInt(y);
593
597
594 var cur_data = dataset[item.series.label].data[item.dataIndex];
598 var cur_data = dataset[item.series.label].data[item.dataIndex];
595 var added = cur_data.added;
599 var added = cur_data.added;
596 var changed = cur_data.changed;
600 var changed = cur_data.changed;
597 var removed = cur_data.removed;
601 var removed = cur_data.removed;
598
602
599 var nr_commits_suffix = " ${_('commits')} ";
603 var nr_commits_suffix = " ${_('commits')} ";
600 var added_suffix = " ${_('files added')} ";
604 var added_suffix = " ${_('files added')} ";
601 var changed_suffix = " ${_('files changed')} ";
605 var changed_suffix = " ${_('files changed')} ";
602 var removed_suffix = " ${_('files removed')} ";
606 var removed_suffix = " ${_('files removed')} ";
603
607
604
608
605 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
609 if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
606 if(added==1){added_suffix=" ${_('file added')} ";}
610 if(added==1){added_suffix=" ${_('file added')} ";}
607 if(changed==1){changed_suffix=" ${_('file changed')} ";}
611 if(changed==1){changed_suffix=" ${_('file changed')} ";}
608 if(removed==1){removed_suffix=" ${_('file removed')} ";}
612 if(removed==1){removed_suffix=" ${_('file removed')} ";}
609
613
610 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
614 showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
611 +'<br/>'+
615 +'<br/>'+
612 nr_commits + nr_commits_suffix+'<br/>'+
616 nr_commits + nr_commits_suffix+'<br/>'+
613 added + added_suffix +'<br/>'+
617 added + added_suffix +'<br/>'+
614 changed + changed_suffix + '<br/>'+
618 changed + changed_suffix + '<br/>'+
615 removed + removed_suffix + '<br/>');
619 removed + removed_suffix + '<br/>');
616 }
620 }
617 }
621 }
618 else {
622 else {
619 var tooltip = YUD.get("tooltip");
623 var tooltip = YUD.get("tooltip");
620
624
621 if(tooltip) {
625 if(tooltip) {
622 tooltip.parentNode.removeChild(tooltip);
626 tooltip.parentNode.removeChild(tooltip);
623 }
627 }
624 previousPoint = null;
628 previousPoint = null;
625 }
629 }
626 }
630 }
627
631
628 /**
632 /**
629 * MAIN EXECUTION
633 * MAIN EXECUTION
630 */
634 */
631
635
632 var data = getDataAccordingToRanges(initial_ranges);
636 var data = getDataAccordingToRanges(initial_ranges);
633 generateCheckboxes(data);
637 generateCheckboxes(data);
634
638
635 //main plot
639 //main plot
636 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
640 var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
637
641
638 //overview
642 //overview
639 var overview = YAHOO.widget.Flot(overviewContainer,
643 var overview = YAHOO.widget.Flot(overviewContainer,
640 overview_dataset, overview_options);
644 overview_dataset, overview_options);
641
645
642 //show initial selection on overview
646 //show initial selection on overview
643 overview.setSelection(initial_ranges);
647 overview.setSelection(initial_ranges);
644
648
645 plot.subscribe("plotselected", plotselected);
649 plot.subscribe("plotselected", plotselected);
646 plot.subscribe("plothover", plothover)
650 plot.subscribe("plothover", plothover)
647
651
648 overview.subscribe("plotselected", function (ranges) {
652 overview.subscribe("plotselected", function (ranges) {
649 plot.setSelection(ranges);
653 plot.setSelection(ranges);
650 });
654 });
651
655
652 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
656 YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
653 }
657 }
654 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
658 SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});
655 </script>
659 </script>
656
660
657 </div>
661 </div>
658 </div>
662 </div>
659
663
660 <div class="box">
664 <div class="box">
661 <div class="title">
665 <div class="title">
662 <div class="breadcrumbs">${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</div>
666 <div class="breadcrumbs">${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</div>
663 </div>
667 </div>
664 <div class="table">
668 <div class="table">
665 <div id="shortlog_data">
669 <div id="shortlog_data">
666 <%include file='../shortlog/shortlog_data.html'/>
670 <%include file='../shortlog/shortlog_data.html'/>
667 </div>
671 </div>
668 ##%if c.repo_changesets:
672 ##%if c.repo_changesets:
669 ## ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
673 ## ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))}
670 ##%endif
674 ##%endif
671 </div>
675 </div>
672 </div>
676 </div>
673 <div class="box">
677 <div class="box">
674 <div class="title">
678 <div class="title">
675 <div class="breadcrumbs">${h.link_to(_('Tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
679 <div class="breadcrumbs">${h.link_to(_('Tags'),h.url('tags_home',repo_name=c.repo_name))}</div>
676 </div>
680 </div>
677 <div class="table">
681 <div class="table">
678 <%include file='../tags/tags_data.html'/>
682 <%include file='../tags/tags_data.html'/>
679 %if c.repo_changesets:
683 %if c.repo_changesets:
680 ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))}
684 ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))}
681 %endif
685 %endif
682 </div>
686 </div>
683 </div>
687 </div>
684 <div class="box">
688 <div class="box">
685 <div class="title">
689 <div class="title">
686 <div class="breadcrumbs">${h.link_to(_('Branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
690 <div class="breadcrumbs">${h.link_to(_('Branches'),h.url('branches_home',repo_name=c.repo_name))}</div>
687 </div>
691 </div>
688 <div class="table">
692 <div class="table">
689 <%include file='../branches/branches_data.html'/>
693 <%include file='../branches/branches_data.html'/>
690 %if c.repo_changesets:
694 %if c.repo_changesets:
691 ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))}
695 ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))}
692 %endif
696 %endif
693 </div>
697 </div>
694 </div>
698 </div>
695
699
696 </%def>
700 </%def>
General Comments 0
You need to be logged in to leave comments. Login now