##// END OF EJS Templates
Fixed issue when node didn't exists at 'tip' and we tried calculate history based on that assumption....
marcink -
r2977:cff9d4e1 beta
parent child Browse files
Show More
@@ -1,545 +1,558 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) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 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 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import tempfile
29 import tempfile
30
30
31 from pylons import request, response, tmpl_context as c, url
31 from pylons import request, response, 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 from pylons.decorators import jsonify
34 from pylons.decorators import jsonify
35
35
36 from rhodecode.lib import diffs
36 from rhodecode.lib import diffs
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38
38
39 from rhodecode.lib.compat import OrderedDict
39 from rhodecode.lib.compat import OrderedDict
40 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\
40 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str,\
41 str2bool
41 str2bool
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.vcs.backends.base import EmptyChangeset
44 from rhodecode.lib.vcs.backends.base import EmptyChangeset
45 from rhodecode.lib.vcs.conf import settings
45 from rhodecode.lib.vcs.conf import settings
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,\
49 NodeDoesNotExistError
49 from rhodecode.lib.vcs.nodes import FileNode
50 from rhodecode.lib.vcs.nodes import FileNode
50
51
51 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.db import Repository
54 from rhodecode.model.db import Repository
54
55
55 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
56 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
56 _context_url, get_line_ctx, get_ignore_ws
57 _context_url, get_line_ctx, get_ignore_ws
57
58
58
59
59 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
60
61
61
62
62 class FilesController(BaseRepoController):
63 class FilesController(BaseRepoController):
63
64
64 def __before__(self):
65 def __before__(self):
65 super(FilesController, self).__before__()
66 super(FilesController, self).__before__()
66 c.cut_off_limit = self.cut_off_limit
67 c.cut_off_limit = self.cut_off_limit
67
68
68 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
69 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
69 """
70 """
70 Safe way to get changeset if error occur it redirects to tip with
71 Safe way to get changeset if error occur it redirects to tip with
71 proper message
72 proper message
72
73
73 :param rev: revision to fetch
74 :param rev: revision to fetch
74 :param repo_name: repo name to redirect after
75 :param repo_name: repo name to redirect after
75 """
76 """
76
77
77 try:
78 try:
78 return c.rhodecode_repo.get_changeset(rev)
79 return c.rhodecode_repo.get_changeset(rev)
79 except EmptyRepositoryError, e:
80 except EmptyRepositoryError, e:
80 if not redirect_after:
81 if not redirect_after:
81 return None
82 return None
82 url_ = url('files_add_home',
83 url_ = url('files_add_home',
83 repo_name=c.repo_name,
84 repo_name=c.repo_name,
84 revision=0, f_path='')
85 revision=0, f_path='')
85 add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file'))
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('click here to add new file'))
86 h.flash(h.literal(_('There are no files yet %s') % add_new),
87 h.flash(h.literal(_('There are no files yet %s') % add_new),
87 category='warning')
88 category='warning')
88 redirect(h.url('summary_home', repo_name=repo_name))
89 redirect(h.url('summary_home', repo_name=repo_name))
89
90
90 except RepositoryError, e:
91 except RepositoryError, e:
91 h.flash(str(e), category='warning')
92 h.flash(str(e), category='warning')
92 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
93
94
94 def __get_filenode_or_redirect(self, repo_name, cs, path):
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
95 """
96 """
96 Returns file_node, if error occurs or given path is directory,
97 Returns file_node, if error occurs or given path is directory,
97 it'll redirect to top level path
98 it'll redirect to top level path
98
99
99 :param repo_name: repo_name
100 :param repo_name: repo_name
100 :param cs: given changeset
101 :param cs: given changeset
101 :param path: path to lookup
102 :param path: path to lookup
102 """
103 """
103
104
104 try:
105 try:
105 file_node = cs.get_node(path)
106 file_node = cs.get_node(path)
106 if file_node.is_dir():
107 if file_node.is_dir():
107 raise RepositoryError('given path is a directory')
108 raise RepositoryError('given path is a directory')
108 except RepositoryError, e:
109 except RepositoryError, e:
109 h.flash(str(e), category='warning')
110 h.flash(str(e), category='warning')
110 redirect(h.url('files_home', repo_name=repo_name,
111 redirect(h.url('files_home', repo_name=repo_name,
111 revision=cs.raw_id))
112 revision=cs.raw_id))
112
113
113 return file_node
114 return file_node
114
115
115 @LoginRequired()
116 @LoginRequired()
116 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
117 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
117 'repository.admin')
118 'repository.admin')
118 def index(self, repo_name, revision, f_path, annotate=False):
119 def index(self, repo_name, revision, f_path, annotate=False):
119 # redirect to given revision from form if given
120 # redirect to given revision from form if given
120 post_revision = request.POST.get('at_rev', None)
121 post_revision = request.POST.get('at_rev', None)
121 if post_revision:
122 if post_revision:
122 cs = self.__get_cs_or_redirect(post_revision, repo_name)
123 cs = self.__get_cs_or_redirect(post_revision, repo_name)
123 redirect(url('files_home', repo_name=c.repo_name,
124 redirect(url('files_home', repo_name=c.repo_name,
124 revision=cs.raw_id, f_path=f_path))
125 revision=cs.raw_id, f_path=f_path))
125
126
126 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
127 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
127 c.branch = request.GET.get('branch', None)
128 c.branch = request.GET.get('branch', None)
128 c.f_path = f_path
129 c.f_path = f_path
129 c.annotate = annotate
130 c.annotate = annotate
130 cur_rev = c.changeset.revision
131 cur_rev = c.changeset.revision
131
132
132 # prev link
133 # prev link
133 try:
134 try:
134 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
135 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
135 c.url_prev = url('files_home', repo_name=c.repo_name,
136 c.url_prev = url('files_home', repo_name=c.repo_name,
136 revision=prev_rev.raw_id, f_path=f_path)
137 revision=prev_rev.raw_id, f_path=f_path)
137 if c.branch:
138 if c.branch:
138 c.url_prev += '?branch=%s' % c.branch
139 c.url_prev += '?branch=%s' % c.branch
139 except (ChangesetDoesNotExistError, VCSError):
140 except (ChangesetDoesNotExistError, VCSError):
140 c.url_prev = '#'
141 c.url_prev = '#'
141
142
142 # next link
143 # next link
143 try:
144 try:
144 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
145 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
145 c.url_next = url('files_home', repo_name=c.repo_name,
146 c.url_next = url('files_home', repo_name=c.repo_name,
146 revision=next_rev.raw_id, f_path=f_path)
147 revision=next_rev.raw_id, f_path=f_path)
147 if c.branch:
148 if c.branch:
148 c.url_next += '?branch=%s' % c.branch
149 c.url_next += '?branch=%s' % c.branch
149 except (ChangesetDoesNotExistError, VCSError):
150 except (ChangesetDoesNotExistError, VCSError):
150 c.url_next = '#'
151 c.url_next = '#'
151
152
152 # files or dirs
153 # files or dirs
153 try:
154 try:
154 c.file = c.changeset.get_node(f_path)
155 c.file = c.changeset.get_node(f_path)
155
156
156 if c.file.is_file():
157 if c.file.is_file():
157 _hist = c.rhodecode_repo.get_changeset().get_file_history(f_path)
158 _hist = c.rhodecode_repo.get_changeset().get_file_history(f_path)
158 c.file_changeset = c.changeset
159 c.file_changeset = c.changeset
159 if _hist:
160 if _hist:
160 c.file_changeset = (c.changeset
161 c.file_changeset = (c.changeset
161 if c.changeset.revision < _hist[0].revision
162 if c.changeset.revision < _hist[0].revision
162 else _hist[0])
163 else _hist[0])
163 c.file_history = self._get_node_history(None, f_path, _hist)
164 c.file_history = self._get_node_history(c.changeset, f_path,
165 _hist)
164 c.authors = []
166 c.authors = []
165 for a in set([x.author for x in _hist]):
167 for a in set([x.author for x in _hist]):
166 c.authors.append((h.email(a), h.person(a)))
168 c.authors.append((h.email(a), h.person(a)))
167 else:
169 else:
168 c.authors = c.file_history = []
170 c.authors = c.file_history = []
169 except RepositoryError, e:
171 except RepositoryError, e:
170 h.flash(str(e), category='warning')
172 h.flash(str(e), category='warning')
171 redirect(h.url('files_home', repo_name=repo_name,
173 redirect(h.url('files_home', repo_name=repo_name,
172 revision='tip'))
174 revision='tip'))
173
175
174 if request.environ.get('HTTP_X_PARTIAL_XHR'):
176 if request.environ.get('HTTP_X_PARTIAL_XHR'):
175 return render('files/files_ypjax.html')
177 return render('files/files_ypjax.html')
176
178
177 return render('files/files.html')
179 return render('files/files.html')
178
180
179 @LoginRequired()
181 @LoginRequired()
180 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
182 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
181 'repository.admin')
183 'repository.admin')
182 def rawfile(self, repo_name, revision, f_path):
184 def rawfile(self, repo_name, revision, f_path):
183 cs = self.__get_cs_or_redirect(revision, repo_name)
185 cs = self.__get_cs_or_redirect(revision, repo_name)
184 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
186 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
185
187
186 response.content_disposition = 'attachment; filename=%s' % \
188 response.content_disposition = 'attachment; filename=%s' % \
187 safe_str(f_path.split(Repository.url_sep())[-1])
189 safe_str(f_path.split(Repository.url_sep())[-1])
188
190
189 response.content_type = file_node.mimetype
191 response.content_type = file_node.mimetype
190 return file_node.content
192 return file_node.content
191
193
192 @LoginRequired()
194 @LoginRequired()
193 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
195 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
194 'repository.admin')
196 'repository.admin')
195 def raw(self, repo_name, revision, f_path):
197 def raw(self, repo_name, revision, f_path):
196 cs = self.__get_cs_or_redirect(revision, repo_name)
198 cs = self.__get_cs_or_redirect(revision, repo_name)
197 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
199 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
198
200
199 raw_mimetype_mapping = {
201 raw_mimetype_mapping = {
200 # map original mimetype to a mimetype used for "show as raw"
202 # map original mimetype to a mimetype used for "show as raw"
201 # you can also provide a content-disposition to override the
203 # you can also provide a content-disposition to override the
202 # default "attachment" disposition.
204 # default "attachment" disposition.
203 # orig_type: (new_type, new_dispo)
205 # orig_type: (new_type, new_dispo)
204
206
205 # show images inline:
207 # show images inline:
206 'image/x-icon': ('image/x-icon', 'inline'),
208 'image/x-icon': ('image/x-icon', 'inline'),
207 'image/png': ('image/png', 'inline'),
209 'image/png': ('image/png', 'inline'),
208 'image/gif': ('image/gif', 'inline'),
210 'image/gif': ('image/gif', 'inline'),
209 'image/jpeg': ('image/jpeg', 'inline'),
211 'image/jpeg': ('image/jpeg', 'inline'),
210 'image/svg+xml': ('image/svg+xml', 'inline'),
212 'image/svg+xml': ('image/svg+xml', 'inline'),
211 }
213 }
212
214
213 mimetype = file_node.mimetype
215 mimetype = file_node.mimetype
214 try:
216 try:
215 mimetype, dispo = raw_mimetype_mapping[mimetype]
217 mimetype, dispo = raw_mimetype_mapping[mimetype]
216 except KeyError:
218 except KeyError:
217 # we don't know anything special about this, handle it safely
219 # we don't know anything special about this, handle it safely
218 if file_node.is_binary:
220 if file_node.is_binary:
219 # do same as download raw for binary files
221 # do same as download raw for binary files
220 mimetype, dispo = 'application/octet-stream', 'attachment'
222 mimetype, dispo = 'application/octet-stream', 'attachment'
221 else:
223 else:
222 # do not just use the original mimetype, but force text/plain,
224 # do not just use the original mimetype, but force text/plain,
223 # otherwise it would serve text/html and that might be unsafe.
225 # otherwise it would serve text/html and that might be unsafe.
224 # Note: underlying vcs library fakes text/plain mimetype if the
226 # Note: underlying vcs library fakes text/plain mimetype if the
225 # mimetype can not be determined and it thinks it is not
227 # mimetype can not be determined and it thinks it is not
226 # binary.This might lead to erroneous text display in some
228 # binary.This might lead to erroneous text display in some
227 # cases, but helps in other cases, like with text files
229 # cases, but helps in other cases, like with text files
228 # without extension.
230 # without extension.
229 mimetype, dispo = 'text/plain', 'inline'
231 mimetype, dispo = 'text/plain', 'inline'
230
232
231 if dispo == 'attachment':
233 if dispo == 'attachment':
232 dispo = 'attachment; filename=%s' % \
234 dispo = 'attachment; filename=%s' % \
233 safe_str(f_path.split(os.sep)[-1])
235 safe_str(f_path.split(os.sep)[-1])
234
236
235 response.content_disposition = dispo
237 response.content_disposition = dispo
236 response.content_type = mimetype
238 response.content_type = mimetype
237 return file_node.content
239 return file_node.content
238
240
239 @LoginRequired()
241 @LoginRequired()
240 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
242 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
241 def edit(self, repo_name, revision, f_path):
243 def edit(self, repo_name, revision, f_path):
242 repo = Repository.get_by_repo_name(repo_name)
244 repo = Repository.get_by_repo_name(repo_name)
243 if repo.enable_locking and repo.locked[0]:
245 if repo.enable_locking and repo.locked[0]:
244 h.flash(_('This repository is has been locked by %s on %s')
246 h.flash(_('This repository is has been locked by %s on %s')
245 % (h.person_by_id(repo.locked[0]),
247 % (h.person_by_id(repo.locked[0]),
246 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
248 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
247 'warning')
249 'warning')
248 return redirect(h.url('files_home',
250 return redirect(h.url('files_home',
249 repo_name=repo_name, revision='tip'))
251 repo_name=repo_name, revision='tip'))
250
252
251 r_post = request.POST
253 r_post = request.POST
252
254
253 c.cs = self.__get_cs_or_redirect(revision, repo_name)
255 c.cs = self.__get_cs_or_redirect(revision, repo_name)
254 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
256 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
255
257
256 if c.file.is_binary:
258 if c.file.is_binary:
257 return redirect(url('files_home', repo_name=c.repo_name,
259 return redirect(url('files_home', repo_name=c.repo_name,
258 revision=c.cs.raw_id, f_path=f_path))
260 revision=c.cs.raw_id, f_path=f_path))
259
261
260 c.f_path = f_path
262 c.f_path = f_path
261
263
262 if r_post:
264 if r_post:
263
265
264 old_content = c.file.content
266 old_content = c.file.content
265 sl = old_content.splitlines(1)
267 sl = old_content.splitlines(1)
266 first_line = sl[0] if sl else ''
268 first_line = sl[0] if sl else ''
267 # modes: 0 - Unix, 1 - Mac, 2 - DOS
269 # modes: 0 - Unix, 1 - Mac, 2 - DOS
268 mode = detect_mode(first_line, 0)
270 mode = detect_mode(first_line, 0)
269 content = convert_line_endings(r_post.get('content'), mode)
271 content = convert_line_endings(r_post.get('content'), mode)
270
272
271 message = r_post.get('message') or (_('Edited %s via RhodeCode')
273 message = r_post.get('message') or (_('Edited %s via RhodeCode')
272 % (f_path))
274 % (f_path))
273 author = self.rhodecode_user.full_contact
275 author = self.rhodecode_user.full_contact
274
276
275 if content == old_content:
277 if content == old_content:
276 h.flash(_('No changes'),
278 h.flash(_('No changes'),
277 category='warning')
279 category='warning')
278 return redirect(url('changeset_home', repo_name=c.repo_name,
280 return redirect(url('changeset_home', repo_name=c.repo_name,
279 revision='tip'))
281 revision='tip'))
280
282
281 try:
283 try:
282 self.scm_model.commit_change(repo=c.rhodecode_repo,
284 self.scm_model.commit_change(repo=c.rhodecode_repo,
283 repo_name=repo_name, cs=c.cs,
285 repo_name=repo_name, cs=c.cs,
284 user=self.rhodecode_user,
286 user=self.rhodecode_user,
285 author=author, message=message,
287 author=author, message=message,
286 content=content, f_path=f_path)
288 content=content, f_path=f_path)
287 h.flash(_('Successfully committed to %s') % f_path,
289 h.flash(_('Successfully committed to %s') % f_path,
288 category='success')
290 category='success')
289
291
290 except Exception:
292 except Exception:
291 log.error(traceback.format_exc())
293 log.error(traceback.format_exc())
292 h.flash(_('Error occurred during commit'), category='error')
294 h.flash(_('Error occurred during commit'), category='error')
293 return redirect(url('changeset_home',
295 return redirect(url('changeset_home',
294 repo_name=c.repo_name, revision='tip'))
296 repo_name=c.repo_name, revision='tip'))
295
297
296 return render('files/files_edit.html')
298 return render('files/files_edit.html')
297
299
298 @LoginRequired()
300 @LoginRequired()
299 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
301 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
300 def add(self, repo_name, revision, f_path):
302 def add(self, repo_name, revision, f_path):
301
303
302 repo = Repository.get_by_repo_name(repo_name)
304 repo = Repository.get_by_repo_name(repo_name)
303 if repo.enable_locking and repo.locked[0]:
305 if repo.enable_locking and repo.locked[0]:
304 h.flash(_('This repository is has been locked by %s on %s')
306 h.flash(_('This repository is has been locked by %s on %s')
305 % (h.person_by_id(repo.locked[0]),
307 % (h.person_by_id(repo.locked[0]),
306 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
308 h.fmt_date(h.time_to_datetime(repo.locked[1]))),
307 'warning')
309 'warning')
308 return redirect(h.url('files_home',
310 return redirect(h.url('files_home',
309 repo_name=repo_name, revision='tip'))
311 repo_name=repo_name, revision='tip'))
310
312
311 r_post = request.POST
313 r_post = request.POST
312 c.cs = self.__get_cs_or_redirect(revision, repo_name,
314 c.cs = self.__get_cs_or_redirect(revision, repo_name,
313 redirect_after=False)
315 redirect_after=False)
314 if c.cs is None:
316 if c.cs is None:
315 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
317 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
316
318
317 c.f_path = f_path
319 c.f_path = f_path
318
320
319 if r_post:
321 if r_post:
320 unix_mode = 0
322 unix_mode = 0
321 content = convert_line_endings(r_post.get('content'), unix_mode)
323 content = convert_line_endings(r_post.get('content'), unix_mode)
322
324
323 message = r_post.get('message') or (_('Added %s via RhodeCode')
325 message = r_post.get('message') or (_('Added %s via RhodeCode')
324 % (f_path))
326 % (f_path))
325 location = r_post.get('location')
327 location = r_post.get('location')
326 filename = r_post.get('filename')
328 filename = r_post.get('filename')
327 file_obj = r_post.get('upload_file', None)
329 file_obj = r_post.get('upload_file', None)
328
330
329 if file_obj is not None and hasattr(file_obj, 'filename'):
331 if file_obj is not None and hasattr(file_obj, 'filename'):
330 filename = file_obj.filename
332 filename = file_obj.filename
331 content = file_obj.file
333 content = file_obj.file
332
334
333 node_path = os.path.join(location, filename)
335 node_path = os.path.join(location, filename)
334 author = self.rhodecode_user.full_contact
336 author = self.rhodecode_user.full_contact
335
337
336 if not content:
338 if not content:
337 h.flash(_('No content'), category='warning')
339 h.flash(_('No content'), category='warning')
338 return redirect(url('changeset_home', repo_name=c.repo_name,
340 return redirect(url('changeset_home', repo_name=c.repo_name,
339 revision='tip'))
341 revision='tip'))
340 if not filename:
342 if not filename:
341 h.flash(_('No filename'), category='warning')
343 h.flash(_('No filename'), category='warning')
342 return redirect(url('changeset_home', repo_name=c.repo_name,
344 return redirect(url('changeset_home', repo_name=c.repo_name,
343 revision='tip'))
345 revision='tip'))
344
346
345 try:
347 try:
346 self.scm_model.create_node(repo=c.rhodecode_repo,
348 self.scm_model.create_node(repo=c.rhodecode_repo,
347 repo_name=repo_name, cs=c.cs,
349 repo_name=repo_name, cs=c.cs,
348 user=self.rhodecode_user,
350 user=self.rhodecode_user,
349 author=author, message=message,
351 author=author, message=message,
350 content=content, f_path=node_path)
352 content=content, f_path=node_path)
351 h.flash(_('Successfully committed to %s') % node_path,
353 h.flash(_('Successfully committed to %s') % node_path,
352 category='success')
354 category='success')
353 except NodeAlreadyExistsError, e:
355 except NodeAlreadyExistsError, e:
354 h.flash(_(e), category='error')
356 h.flash(_(e), category='error')
355 except Exception:
357 except Exception:
356 log.error(traceback.format_exc())
358 log.error(traceback.format_exc())
357 h.flash(_('Error occurred during commit'), category='error')
359 h.flash(_('Error occurred during commit'), category='error')
358 return redirect(url('changeset_home',
360 return redirect(url('changeset_home',
359 repo_name=c.repo_name, revision='tip'))
361 repo_name=c.repo_name, revision='tip'))
360
362
361 return render('files/files_add.html')
363 return render('files/files_add.html')
362
364
363 @LoginRequired()
365 @LoginRequired()
364 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
366 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
365 'repository.admin')
367 'repository.admin')
366 def archivefile(self, repo_name, fname):
368 def archivefile(self, repo_name, fname):
367
369
368 fileformat = None
370 fileformat = None
369 revision = None
371 revision = None
370 ext = None
372 ext = None
371 subrepos = request.GET.get('subrepos') == 'true'
373 subrepos = request.GET.get('subrepos') == 'true'
372
374
373 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
375 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
374 archive_spec = fname.split(ext_data[1])
376 archive_spec = fname.split(ext_data[1])
375 if len(archive_spec) == 2 and archive_spec[1] == '':
377 if len(archive_spec) == 2 and archive_spec[1] == '':
376 fileformat = a_type or ext_data[1]
378 fileformat = a_type or ext_data[1]
377 revision = archive_spec[0]
379 revision = archive_spec[0]
378 ext = ext_data[1]
380 ext = ext_data[1]
379
381
380 try:
382 try:
381 dbrepo = RepoModel().get_by_repo_name(repo_name)
383 dbrepo = RepoModel().get_by_repo_name(repo_name)
382 if dbrepo.enable_downloads is False:
384 if dbrepo.enable_downloads is False:
383 return _('downloads disabled')
385 return _('downloads disabled')
384
386
385 if c.rhodecode_repo.alias == 'hg':
387 if c.rhodecode_repo.alias == 'hg':
386 # patch and reset hooks section of UI config to not run any
388 # patch and reset hooks section of UI config to not run any
387 # hooks on fetching archives with subrepos
389 # hooks on fetching archives with subrepos
388 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
390 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
389 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
391 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
390
392
391 cs = c.rhodecode_repo.get_changeset(revision)
393 cs = c.rhodecode_repo.get_changeset(revision)
392 content_type = settings.ARCHIVE_SPECS[fileformat][0]
394 content_type = settings.ARCHIVE_SPECS[fileformat][0]
393 except ChangesetDoesNotExistError:
395 except ChangesetDoesNotExistError:
394 return _('Unknown revision %s') % revision
396 return _('Unknown revision %s') % revision
395 except EmptyRepositoryError:
397 except EmptyRepositoryError:
396 return _('Empty repository')
398 return _('Empty repository')
397 except (ImproperArchiveTypeError, KeyError):
399 except (ImproperArchiveTypeError, KeyError):
398 return _('Unknown archive type')
400 return _('Unknown archive type')
399
401
400 fd, archive = tempfile.mkstemp()
402 fd, archive = tempfile.mkstemp()
401 t = open(archive, 'wb')
403 t = open(archive, 'wb')
402 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
404 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
403 t.close()
405 t.close()
404
406
405 def get_chunked_archive(archive):
407 def get_chunked_archive(archive):
406 stream = open(archive, 'rb')
408 stream = open(archive, 'rb')
407 while True:
409 while True:
408 data = stream.read(16 * 1024)
410 data = stream.read(16 * 1024)
409 if not data:
411 if not data:
410 stream.close()
412 stream.close()
411 os.close(fd)
413 os.close(fd)
412 os.remove(archive)
414 os.remove(archive)
413 break
415 break
414 yield data
416 yield data
415
417
416 response.content_disposition = str('attachment; filename=%s-%s%s' \
418 response.content_disposition = str('attachment; filename=%s-%s%s' \
417 % (repo_name, revision[:12], ext))
419 % (repo_name, revision[:12], ext))
418 response.content_type = str(content_type)
420 response.content_type = str(content_type)
419 return get_chunked_archive(archive)
421 return get_chunked_archive(archive)
420
422
421 @LoginRequired()
423 @LoginRequired()
422 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
424 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
423 'repository.admin')
425 'repository.admin')
424 def diff(self, repo_name, f_path):
426 def diff(self, repo_name, f_path):
425 ignore_whitespace = request.GET.get('ignorews') == '1'
427 ignore_whitespace = request.GET.get('ignorews') == '1'
426 line_context = request.GET.get('context', 3)
428 line_context = request.GET.get('context', 3)
427 diff1 = request.GET.get('diff1', '')
429 diff1 = request.GET.get('diff1', '')
428 diff2 = request.GET.get('diff2', '')
430 diff2 = request.GET.get('diff2', '')
429 c.action = request.GET.get('diff')
431 c.action = request.GET.get('diff')
430 c.no_changes = diff1 == diff2
432 c.no_changes = diff1 == diff2
431 c.f_path = f_path
433 c.f_path = f_path
432 c.big_diff = False
434 c.big_diff = False
433 c.anchor_url = anchor_url
435 c.anchor_url = anchor_url
434 c.ignorews_url = _ignorews_url
436 c.ignorews_url = _ignorews_url
435 c.context_url = _context_url
437 c.context_url = _context_url
436 c.changes = OrderedDict()
438 c.changes = OrderedDict()
437 c.changes[diff2] = []
439 c.changes[diff2] = []
438
440
439 #special case if we want a show rev only, it's impl here
441 #special case if we want a show rev only, it's impl here
440 #to reduce JS and callbacks
442 #to reduce JS and callbacks
441 if request.GET.get('show_rev'):
443 if request.GET.get('show_rev'):
442 if str2bool(request.GET.get('annotate', 'False')):
444 if str2bool(request.GET.get('annotate', 'False')):
443 _url = url('files_annotate_home', repo_name=c.repo_name,
445 _url = url('files_annotate_home', repo_name=c.repo_name,
444 revision=diff1, f_path=c.f_path)
446 revision=diff1, f_path=c.f_path)
445 else:
447 else:
446 _url = url('files_home', repo_name=c.repo_name,
448 _url = url('files_home', repo_name=c.repo_name,
447 revision=diff1, f_path=c.f_path)
449 revision=diff1, f_path=c.f_path)
448
450
449 return redirect(_url)
451 return redirect(_url)
450 try:
452 try:
451 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
453 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
452 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
454 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
453 node1 = c.changeset_1.get_node(f_path)
455 node1 = c.changeset_1.get_node(f_path)
454 else:
456 else:
455 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
457 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
456 node1 = FileNode('.', '', changeset=c.changeset_1)
458 node1 = FileNode('.', '', changeset=c.changeset_1)
457
459
458 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
460 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
459 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
461 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
460 node2 = c.changeset_2.get_node(f_path)
462 node2 = c.changeset_2.get_node(f_path)
461 else:
463 else:
462 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
464 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
463 node2 = FileNode('.', '', changeset=c.changeset_2)
465 node2 = FileNode('.', '', changeset=c.changeset_2)
464 except RepositoryError:
466 except RepositoryError:
465 return redirect(url('files_home', repo_name=c.repo_name,
467 return redirect(url('files_home', repo_name=c.repo_name,
466 f_path=f_path))
468 f_path=f_path))
467
469
468 if c.action == 'download':
470 if c.action == 'download':
469 _diff = diffs.get_gitdiff(node1, node2,
471 _diff = diffs.get_gitdiff(node1, node2,
470 ignore_whitespace=ignore_whitespace,
472 ignore_whitespace=ignore_whitespace,
471 context=line_context)
473 context=line_context)
472 diff = diffs.DiffProcessor(_diff, format='gitdiff')
474 diff = diffs.DiffProcessor(_diff, format='gitdiff')
473
475
474 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
476 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
475 response.content_type = 'text/plain'
477 response.content_type = 'text/plain'
476 response.content_disposition = (
478 response.content_disposition = (
477 'attachment; filename=%s' % diff_name
479 'attachment; filename=%s' % diff_name
478 )
480 )
479 return diff.raw_diff()
481 return diff.raw_diff()
480
482
481 elif c.action == 'raw':
483 elif c.action == 'raw':
482 _diff = diffs.get_gitdiff(node1, node2,
484 _diff = diffs.get_gitdiff(node1, node2,
483 ignore_whitespace=ignore_whitespace,
485 ignore_whitespace=ignore_whitespace,
484 context=line_context)
486 context=line_context)
485 diff = diffs.DiffProcessor(_diff, format='gitdiff')
487 diff = diffs.DiffProcessor(_diff, format='gitdiff')
486 response.content_type = 'text/plain'
488 response.content_type = 'text/plain'
487 return diff.raw_diff()
489 return diff.raw_diff()
488
490
489 else:
491 else:
490 fid = h.FID(diff2, node2.path)
492 fid = h.FID(diff2, node2.path)
491 line_context_lcl = get_line_ctx(fid, request.GET)
493 line_context_lcl = get_line_ctx(fid, request.GET)
492 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
494 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
493
495
494 lim = request.GET.get('fulldiff') or self.cut_off_limit
496 lim = request.GET.get('fulldiff') or self.cut_off_limit
495 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
497 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
496 filenode_new=node2,
498 filenode_new=node2,
497 cut_off_limit=lim,
499 cut_off_limit=lim,
498 ignore_whitespace=ign_whitespace_lcl,
500 ignore_whitespace=ign_whitespace_lcl,
499 line_context=line_context_lcl,
501 line_context=line_context_lcl,
500 enable_comments=False)
502 enable_comments=False)
501
503
502 c.changes = [('', node2, diff, cs1, cs2, st,)]
504 c.changes = [('', node2, diff, cs1, cs2, st,)]
503
505
504 return render('files/file_diff.html')
506 return render('files/file_diff.html')
505
507
506 def _get_node_history(self, cs, f_path, changesets=None):
508 def _get_node_history(self, cs, f_path, changesets=None):
507 if cs is None:
509 """
508 # if we pass empty CS calculate history based on tip
510 get changesets history for given node
509 cs = c.rhodecode_repo.get_changeset()
511
512 :param cs: changeset to calculate history
513 :param f_path: path for node to calculate history for
514 :param changesets: if passed don't calculate history and take
515 changesets defined in this list
516 """
517 # calculate history based on tip
518 tip_cs = c.rhodecode_repo.get_changeset()
510 if changesets is None:
519 if changesets is None:
520 try:
521 changesets = tip_cs.get_file_history(f_path)
522 except NodeDoesNotExistError:
523 #this node is not present at tip !
511 changesets = cs.get_file_history(f_path)
524 changesets = cs.get_file_history(f_path)
512
525
513 hist_l = []
526 hist_l = []
514
527
515 changesets_group = ([], _("Changesets"))
528 changesets_group = ([], _("Changesets"))
516 branches_group = ([], _("Branches"))
529 branches_group = ([], _("Branches"))
517 tags_group = ([], _("Tags"))
530 tags_group = ([], _("Tags"))
518 _hg = cs.repository.alias == 'hg'
531 _hg = cs.repository.alias == 'hg'
519 for chs in changesets:
532 for chs in changesets:
520 _branch = '(%s)' % chs.branch if _hg else ''
533 _branch = '(%s)' % chs.branch if _hg else ''
521 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
534 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
522 changesets_group[0].append((chs.raw_id, n_desc,))
535 changesets_group[0].append((chs.raw_id, n_desc,))
523
536
524 hist_l.append(changesets_group)
537 hist_l.append(changesets_group)
525
538
526 for name, chs in c.rhodecode_repo.branches.items():
539 for name, chs in c.rhodecode_repo.branches.items():
527 branches_group[0].append((chs, name),)
540 branches_group[0].append((chs, name),)
528 hist_l.append(branches_group)
541 hist_l.append(branches_group)
529
542
530 for name, chs in c.rhodecode_repo.tags.items():
543 for name, chs in c.rhodecode_repo.tags.items():
531 tags_group[0].append((chs, name),)
544 tags_group[0].append((chs, name),)
532 hist_l.append(tags_group)
545 hist_l.append(tags_group)
533
546
534 return hist_l
547 return hist_l
535
548
536 @LoginRequired()
549 @LoginRequired()
537 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
550 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
538 'repository.admin')
551 'repository.admin')
539 @jsonify
552 @jsonify
540 def nodelist(self, repo_name, revision, f_path):
553 def nodelist(self, repo_name, revision, f_path):
541 if request.environ.get('HTTP_X_PARTIAL_XHR'):
554 if request.environ.get('HTTP_X_PARTIAL_XHR'):
542 cs = self.__get_cs_or_redirect(revision, repo_name)
555 cs = self.__get_cs_or_redirect(revision, repo_name)
543 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
556 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
544 flat=False)
557 flat=False)
545 return {'nodes': _d + _f}
558 return {'nodes': _d + _f}
@@ -1,144 +1,144 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('%s files') % c.repo_name} - ${c.rhodecode_name}
4 ${_('%s files') % c.repo_name} - ${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.repo_name,h.url('files_home',repo_name=c.repo_name))}
10 ${h.link_to(c.repo_name,h.url('files_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('files')}
12 ${_('files')}
13 %if c.file:
13 %if c.file:
14 @ r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
14 @ r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)}
15 %endif
15 %endif
16 </%def>
16 </%def>
17
17
18 <%def name="page_nav()">
18 <%def name="page_nav()">
19 ${self.menu('files')}
19 ${self.menu('files')}
20 </%def>
20 </%def>
21
21
22 <%def name="main()">
22 <%def name="main()">
23 <div class="box">
23 <div class="box">
24 <!-- box / title -->
24 <!-- box / title -->
25 <div class="title">
25 <div class="title">
26 ${self.breadcrumbs()}
26 ${self.breadcrumbs()}
27 <ul class="links">
27 <ul class="links">
28 <li>
28 <li>
29 <span style="text-transform: uppercase;"><a href="#">${_('branch')}: ${c.changeset.branch}</a></span>
29 <span style="text-transform: uppercase;"><a href="#">${_('branch')}: ${c.changeset.branch}</a></span>
30 </li>
30 </li>
31 </ul>
31 </ul>
32 </div>
32 </div>
33 <div class="table">
33 <div class="table">
34 <div id="files_data">
34 <div id="files_data">
35 <%include file='files_ypjax.html'/>
35 <%include file='files_ypjax.html'/>
36 </div>
36 </div>
37 </div>
37 </div>
38 </div>
38 </div>
39
39
40 <script type="text/javascript">
40 <script type="text/javascript">
41 var CACHE = {};
41 var CACHE = {};
42 var CACHE_EXPIRE = 60*1000; //cache for 60s
42 var CACHE_EXPIRE = 60*1000; //cache for 60s
43 //used to construct links from the search list
43 //used to construct links from the search list
44 var url_base = '${h.url("files_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
44 var url_base = '${h.url("files_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
45 //send the nodelist request to this url
45 //send the nodelist request to this url
46 var node_list_url = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
46 var node_list_url = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
47
47
48 var ypjax_links = function(){
48 var ypjax_links = function(){
49 YUE.on(YUQ('.ypjax-link'), 'click',function(e){
49 YUE.on(YUQ('.ypjax-link'), 'click',function(e){
50
50
51 //don't do ypjax on middle click
51 //don't do ypjax on middle click
52 if(e.which == 2 || !History.enabled){
52 if(e.which == 2 || !History.enabled){
53 return true;
53 return true;
54 }
54 }
55
55
56 var el = e.currentTarget;
56 var el = e.currentTarget;
57 var url = el.href;
57 var url = el.href;
58
58
59 var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}';
59 var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}';
60 _base_url = _base_url.replace('//','/')
60 _base_url = _base_url.replace('//','/')
61
61
62 //extract rev and the f_path from url.
62 //extract rev and the f_path from url.
63 parts = url.split(_base_url)
63 parts = url.split(_base_url)
64 if(parts.length != 2){
64 if(parts.length != 2){
65 return false;
65 return false;
66 }
66 }
67
67
68 var parts2 = parts[1].split('/');
68 var parts2 = parts[1].split('/');
69 var rev = parts2.shift(); // pop the first element which is the revision
69 var rev = parts2.shift(); // pop the first element which is the revision
70 var f_path = parts2.join('/');
70 var f_path = parts2.join('/');
71
71
72 var title = "${_('%s files') % c.repo_name}" + " - " + f_path;
72 var title = "${_('%s files') % c.repo_name}" + " - " + f_path;
73
73
74 var _node_list_url = node_list_url.replace('__REV__',rev).replace('__FPATH__', f_path);
74 var _node_list_url = node_list_url.replace('__REV__',rev).replace('__FPATH__', f_path);
75 var _url_base = url_base.replace('__REV__',rev);
75 var _url_base = url_base.replace('__REV__',rev);
76
76
77 // Change our States and save some data for handling events
77 // Change our States and save some data for handling events
78 var data = {url:url,title:title, url_base:_url_base,
78 var data = {url:url,title:title, url_base:_url_base,
79 node_list_url:_node_list_url};
79 node_list_url:_node_list_url};
80 History.pushState(data, title, url);
80 History.pushState(data, title, url);
81
81
82 //now we're sure that we can do ypjax things
82 //now we're sure that we can do ypjax things
83 YUE.preventDefault(e)
83 YUE.preventDefault(e);
84 return false;
84 return false;
85 });
85 });
86 }
86 }
87
87
88 var callbacks = function(State){
88 var callbacks = function(State){
89 ypjax_links();
89 ypjax_links();
90 tooltip_activate();
90 tooltip_activate();
91 fileBrowserListeners(State.url, State.data.node_list_url, State.data.url_base);
91 fileBrowserListeners(State.url, State.data.node_list_url, State.data.url_base);
92 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"));
92 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"));
93
93
94 // Inform Google Analytics of the change
94 // Inform Google Analytics of the change
95 if ( typeof window.pageTracker !== 'undefined' ) {
95 if ( typeof window.pageTracker !== 'undefined' ) {
96 window.pageTracker._trackPageview(State.url);
96 window.pageTracker._trackPageview(State.url);
97 }
97 }
98 }
98 }
99
99
100 YUE.onDOMReady(function(){
100 YUE.onDOMReady(function(){
101 ypjax_links();
101 ypjax_links();
102 var container = 'files_data';
102 var container = 'files_data';
103 //Bind to StateChange Event
103 //Bind to StateChange Event
104 History.Adapter.bind(window,'statechange',function(){
104 History.Adapter.bind(window,'statechange',function(){
105 var State = History.getState();
105 var State = History.getState();
106 cache_key = State.url;
106 cache_key = State.url;
107 //check if we have this request in cache maybe ?
107 //check if we have this request in cache maybe ?
108 var _cache_obj = CACHE[cache_key];
108 var _cache_obj = CACHE[cache_key];
109 var _cur_time = new Date().getTime();
109 var _cur_time = new Date().getTime();
110 // get from cache if it's there and not yet expired !
110 // get from cache if it's there and not yet expired !
111 if(_cache_obj !== undefined && _cache_obj[0] > _cur_time){
111 if(_cache_obj !== undefined && _cache_obj[0] > _cur_time){
112 YUD.get(container).innerHTML=_cache_obj[1];
112 YUD.get(container).innerHTML=_cache_obj[1];
113 YUD.setStyle(container,'opacity','1.0');
113 YUD.setStyle(container,'opacity','1.0');
114
114
115 //callbacks after ypjax call
115 //callbacks after ypjax call
116 callbacks(State);
116 callbacks(State);
117 }
117 }
118 else{
118 else{
119 ypjax(State.url,container,function(o){
119 ypjax(State.url,container,function(o){
120 //callbacks after ypjax call
120 //callbacks after ypjax call
121 callbacks(State);
121 callbacks(State);
122 if (o !== undefined){
122 if (o !== undefined){
123 //store our request in cache
123 //store our request in cache
124 var _expire_on = new Date().getTime()+CACHE_EXPIRE;
124 var _expire_on = new Date().getTime()+CACHE_EXPIRE;
125 CACHE[cache_key] = [_expire_on, o.responseText];
125 CACHE[cache_key] = [_expire_on, o.responseText];
126 }
126 }
127 });
127 });
128 }
128 }
129 });
129 });
130
130
131 // init the search filter
131 // init the search filter
132 var _State = {
132 var _State = {
133 url: "${h.url.current()}",
133 url: "${h.url.current()}",
134 data: {
134 data: {
135 node_list_url: node_list_url.replace('__REV__',"${c.changeset.raw_id}").replace('__FPATH__', "${h.safe_unicode(c.file.path)}"),
135 node_list_url: node_list_url.replace('__REV__',"${c.changeset.raw_id}").replace('__FPATH__', "${h.safe_unicode(c.file.path)}"),
136 url_base: url_base.replace('__REV__',"${c.changeset.raw_id}")
136 url_base: url_base.replace('__REV__',"${c.changeset.raw_id}")
137 }
137 }
138 }
138 }
139 fileBrowserListeners(_State.url, _State.data.node_list_url, _State.data.url_base);
139 fileBrowserListeners(_State.url, _State.data.node_list_url, _State.data.url_base);
140 });
140 });
141
141
142 </script>
142 </script>
143
143
144 </%def>
144 </%def>
General Comments 0
You need to be logged in to leave comments. Login now