##// END OF EJS Templates
removed JSON array envelope from filter files function...
marcink -
r2428:530bd12f beta
parent child Browse files
Show More
@@ -1,490 +1,490 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 from paste.fileapp import FileApp, _FileIter
35 from paste.fileapp import FileApp, _FileIter
36
36
37 from rhodecode.lib import diffs
37 from rhodecode.lib import diffs
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39
39
40 from rhodecode.lib.compat import OrderedDict
40 from rhodecode.lib.compat import OrderedDict
41 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
41 from rhodecode.lib.utils2 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 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 from rhodecode.lib.vcs.nodes import FileNode
49 from rhodecode.lib.vcs.nodes import FileNode
50
50
51 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.scm import ScmModel
52 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.db import Repository
53 from rhodecode.model.db import Repository
54
54
55 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
55 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
56 _context_url, get_line_ctx, get_ignore_ws
56 _context_url, get_line_ctx, get_ignore_ws
57
57
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 class FilesController(BaseRepoController):
62 class FilesController(BaseRepoController):
63
63
64 @LoginRequired()
64 @LoginRequired()
65 def __before__(self):
65 def __before__(self):
66 super(FilesController, self).__before__()
66 super(FilesController, self).__before__()
67 c.cut_off_limit = self.cut_off_limit
67 c.cut_off_limit = self.cut_off_limit
68
68
69 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):
70 """
70 """
71 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
72 proper message
72 proper message
73
73
74 :param rev: revision to fetch
74 :param rev: revision to fetch
75 :param repo_name: repo name to redirect after
75 :param repo_name: repo name to redirect after
76 """
76 """
77
77
78 try:
78 try:
79 return c.rhodecode_repo.get_changeset(rev)
79 return c.rhodecode_repo.get_changeset(rev)
80 except EmptyRepositoryError, e:
80 except EmptyRepositoryError, e:
81 if not redirect_after:
81 if not redirect_after:
82 return None
82 return None
83 url_ = url('files_add_home',
83 url_ = url('files_add_home',
84 repo_name=c.repo_name,
84 repo_name=c.repo_name,
85 revision=0, f_path='')
85 revision=0, f_path='')
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
87 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)),
88 category='warning')
88 category='warning')
89 redirect(h.url('summary_home', repo_name=repo_name))
89 redirect(h.url('summary_home', repo_name=repo_name))
90
90
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, revision='tip'))
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
94
94
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
96 """
96 """
97 Returns file_node, if error occurs or given path is directory,
97 Returns file_node, if error occurs or given path is directory,
98 it'll redirect to top level path
98 it'll redirect to top level path
99
99
100 :param repo_name: repo_name
100 :param repo_name: repo_name
101 :param cs: given changeset
101 :param cs: given changeset
102 :param path: path to lookup
102 :param path: path to lookup
103 """
103 """
104
104
105 try:
105 try:
106 file_node = cs.get_node(path)
106 file_node = cs.get_node(path)
107 if file_node.is_dir():
107 if file_node.is_dir():
108 raise RepositoryError('given path is a directory')
108 raise RepositoryError('given path is a directory')
109 except RepositoryError, e:
109 except RepositoryError, e:
110 h.flash(str(e), category='warning')
110 h.flash(str(e), category='warning')
111 redirect(h.url('files_home', repo_name=repo_name,
111 redirect(h.url('files_home', repo_name=repo_name,
112 revision=cs.raw_id))
112 revision=cs.raw_id))
113
113
114 return file_node
114 return file_node
115
115
116 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
116 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
117 'repository.admin')
117 'repository.admin')
118 def index(self, repo_name, revision, f_path, annotate=False):
118 def index(self, repo_name, revision, f_path, annotate=False):
119 # redirect to given revision from form if given
119 # redirect to given revision from form if given
120 post_revision = request.POST.get('at_rev', None)
120 post_revision = request.POST.get('at_rev', None)
121 if post_revision:
121 if post_revision:
122 cs = self.__get_cs_or_redirect(post_revision, repo_name)
122 cs = self.__get_cs_or_redirect(post_revision, repo_name)
123 redirect(url('files_home', repo_name=c.repo_name,
123 redirect(url('files_home', repo_name=c.repo_name,
124 revision=cs.raw_id, f_path=f_path))
124 revision=cs.raw_id, f_path=f_path))
125
125
126 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
126 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
127 c.branch = request.GET.get('branch', None)
127 c.branch = request.GET.get('branch', None)
128 c.f_path = f_path
128 c.f_path = f_path
129 c.annotate = annotate
129 c.annotate = annotate
130 cur_rev = c.changeset.revision
130 cur_rev = c.changeset.revision
131
131
132 # prev link
132 # prev link
133 try:
133 try:
134 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
134 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
135 c.url_prev = url('files_home', repo_name=c.repo_name,
135 c.url_prev = url('files_home', repo_name=c.repo_name,
136 revision=prev_rev.raw_id, f_path=f_path)
136 revision=prev_rev.raw_id, f_path=f_path)
137 if c.branch:
137 if c.branch:
138 c.url_prev += '?branch=%s' % c.branch
138 c.url_prev += '?branch=%s' % c.branch
139 except (ChangesetDoesNotExistError, VCSError):
139 except (ChangesetDoesNotExistError, VCSError):
140 c.url_prev = '#'
140 c.url_prev = '#'
141
141
142 # next link
142 # next link
143 try:
143 try:
144 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
144 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
145 c.url_next = url('files_home', repo_name=c.repo_name,
145 c.url_next = url('files_home', repo_name=c.repo_name,
146 revision=next_rev.raw_id, f_path=f_path)
146 revision=next_rev.raw_id, f_path=f_path)
147 if c.branch:
147 if c.branch:
148 c.url_next += '?branch=%s' % c.branch
148 c.url_next += '?branch=%s' % c.branch
149 except (ChangesetDoesNotExistError, VCSError):
149 except (ChangesetDoesNotExistError, VCSError):
150 c.url_next = '#'
150 c.url_next = '#'
151
151
152 # files or dirs
152 # files or dirs
153 try:
153 try:
154 c.file = c.changeset.get_node(f_path)
154 c.file = c.changeset.get_node(f_path)
155
155
156 if c.file.is_file():
156 if c.file.is_file():
157 c.file_history = self._get_node_history(c.changeset, f_path)
157 c.file_history = self._get_node_history(c.changeset, f_path)
158 else:
158 else:
159 c.file_history = []
159 c.file_history = []
160 except RepositoryError, e:
160 except RepositoryError, e:
161 h.flash(str(e), category='warning')
161 h.flash(str(e), category='warning')
162 redirect(h.url('files_home', repo_name=repo_name,
162 redirect(h.url('files_home', repo_name=repo_name,
163 revision=revision))
163 revision=revision))
164
164
165 return render('files/files.html')
165 return render('files/files.html')
166
166
167 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
167 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
168 'repository.admin')
168 'repository.admin')
169 def rawfile(self, repo_name, revision, f_path):
169 def rawfile(self, repo_name, revision, f_path):
170 cs = self.__get_cs_or_redirect(revision, repo_name)
170 cs = self.__get_cs_or_redirect(revision, repo_name)
171 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
171 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
172
172
173 response.content_disposition = 'attachment; filename=%s' % \
173 response.content_disposition = 'attachment; filename=%s' % \
174 safe_str(f_path.split(Repository.url_sep())[-1])
174 safe_str(f_path.split(Repository.url_sep())[-1])
175
175
176 response.content_type = file_node.mimetype
176 response.content_type = file_node.mimetype
177 return file_node.content
177 return file_node.content
178
178
179 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
179 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
180 'repository.admin')
180 'repository.admin')
181 def raw(self, repo_name, revision, f_path):
181 def raw(self, repo_name, revision, f_path):
182 cs = self.__get_cs_or_redirect(revision, repo_name)
182 cs = self.__get_cs_or_redirect(revision, repo_name)
183 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
183 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
184
184
185 raw_mimetype_mapping = {
185 raw_mimetype_mapping = {
186 # map original mimetype to a mimetype used for "show as raw"
186 # map original mimetype to a mimetype used for "show as raw"
187 # you can also provide a content-disposition to override the
187 # you can also provide a content-disposition to override the
188 # default "attachment" disposition.
188 # default "attachment" disposition.
189 # orig_type: (new_type, new_dispo)
189 # orig_type: (new_type, new_dispo)
190
190
191 # show images inline:
191 # show images inline:
192 'image/x-icon': ('image/x-icon', 'inline'),
192 'image/x-icon': ('image/x-icon', 'inline'),
193 'image/png': ('image/png', 'inline'),
193 'image/png': ('image/png', 'inline'),
194 'image/gif': ('image/gif', 'inline'),
194 'image/gif': ('image/gif', 'inline'),
195 'image/jpeg': ('image/jpeg', 'inline'),
195 'image/jpeg': ('image/jpeg', 'inline'),
196 'image/svg+xml': ('image/svg+xml', 'inline'),
196 'image/svg+xml': ('image/svg+xml', 'inline'),
197 }
197 }
198
198
199 mimetype = file_node.mimetype
199 mimetype = file_node.mimetype
200 try:
200 try:
201 mimetype, dispo = raw_mimetype_mapping[mimetype]
201 mimetype, dispo = raw_mimetype_mapping[mimetype]
202 except KeyError:
202 except KeyError:
203 # we don't know anything special about this, handle it safely
203 # we don't know anything special about this, handle it safely
204 if file_node.is_binary:
204 if file_node.is_binary:
205 # do same as download raw for binary files
205 # do same as download raw for binary files
206 mimetype, dispo = 'application/octet-stream', 'attachment'
206 mimetype, dispo = 'application/octet-stream', 'attachment'
207 else:
207 else:
208 # do not just use the original mimetype, but force text/plain,
208 # do not just use the original mimetype, but force text/plain,
209 # otherwise it would serve text/html and that might be unsafe.
209 # otherwise it would serve text/html and that might be unsafe.
210 # Note: underlying vcs library fakes text/plain mimetype if the
210 # Note: underlying vcs library fakes text/plain mimetype if the
211 # mimetype can not be determined and it thinks it is not
211 # mimetype can not be determined and it thinks it is not
212 # binary.This might lead to erroneous text display in some
212 # binary.This might lead to erroneous text display in some
213 # cases, but helps in other cases, like with text files
213 # cases, but helps in other cases, like with text files
214 # without extension.
214 # without extension.
215 mimetype, dispo = 'text/plain', 'inline'
215 mimetype, dispo = 'text/plain', 'inline'
216
216
217 if dispo == 'attachment':
217 if dispo == 'attachment':
218 dispo = 'attachment; filename=%s' % \
218 dispo = 'attachment; filename=%s' % \
219 safe_str(f_path.split(os.sep)[-1])
219 safe_str(f_path.split(os.sep)[-1])
220
220
221 response.content_disposition = dispo
221 response.content_disposition = dispo
222 response.content_type = mimetype
222 response.content_type = mimetype
223 return file_node.content
223 return file_node.content
224
224
225 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
225 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
226 def edit(self, repo_name, revision, f_path):
226 def edit(self, repo_name, revision, f_path):
227 r_post = request.POST
227 r_post = request.POST
228
228
229 c.cs = self.__get_cs_or_redirect(revision, repo_name)
229 c.cs = self.__get_cs_or_redirect(revision, repo_name)
230 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
230 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
231
231
232 if c.file.is_binary:
232 if c.file.is_binary:
233 return redirect(url('files_home', repo_name=c.repo_name,
233 return redirect(url('files_home', repo_name=c.repo_name,
234 revision=c.cs.raw_id, f_path=f_path))
234 revision=c.cs.raw_id, f_path=f_path))
235
235
236 c.f_path = f_path
236 c.f_path = f_path
237
237
238 if r_post:
238 if r_post:
239
239
240 old_content = c.file.content
240 old_content = c.file.content
241 sl = old_content.splitlines(1)
241 sl = old_content.splitlines(1)
242 first_line = sl[0] if sl else ''
242 first_line = sl[0] if sl else ''
243 # modes: 0 - Unix, 1 - Mac, 2 - DOS
243 # modes: 0 - Unix, 1 - Mac, 2 - DOS
244 mode = detect_mode(first_line, 0)
244 mode = detect_mode(first_line, 0)
245 content = convert_line_endings(r_post.get('content'), mode)
245 content = convert_line_endings(r_post.get('content'), mode)
246
246
247 message = r_post.get('message') or (_('Edited %s via RhodeCode')
247 message = r_post.get('message') or (_('Edited %s via RhodeCode')
248 % (f_path))
248 % (f_path))
249 author = self.rhodecode_user.full_contact
249 author = self.rhodecode_user.full_contact
250
250
251 if content == old_content:
251 if content == old_content:
252 h.flash(_('No changes'),
252 h.flash(_('No changes'),
253 category='warning')
253 category='warning')
254 return redirect(url('changeset_home', repo_name=c.repo_name,
254 return redirect(url('changeset_home', repo_name=c.repo_name,
255 revision='tip'))
255 revision='tip'))
256
256
257 try:
257 try:
258 self.scm_model.commit_change(repo=c.rhodecode_repo,
258 self.scm_model.commit_change(repo=c.rhodecode_repo,
259 repo_name=repo_name, cs=c.cs,
259 repo_name=repo_name, cs=c.cs,
260 user=self.rhodecode_user,
260 user=self.rhodecode_user,
261 author=author, message=message,
261 author=author, message=message,
262 content=content, f_path=f_path)
262 content=content, f_path=f_path)
263 h.flash(_('Successfully committed to %s' % f_path),
263 h.flash(_('Successfully committed to %s' % f_path),
264 category='success')
264 category='success')
265
265
266 except Exception:
266 except Exception:
267 log.error(traceback.format_exc())
267 log.error(traceback.format_exc())
268 h.flash(_('Error occurred during commit'), category='error')
268 h.flash(_('Error occurred during commit'), category='error')
269 return redirect(url('changeset_home',
269 return redirect(url('changeset_home',
270 repo_name=c.repo_name, revision='tip'))
270 repo_name=c.repo_name, revision='tip'))
271
271
272 return render('files/files_edit.html')
272 return render('files/files_edit.html')
273
273
274 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
274 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
275 def add(self, repo_name, revision, f_path):
275 def add(self, repo_name, revision, f_path):
276 r_post = request.POST
276 r_post = request.POST
277 c.cs = self.__get_cs_or_redirect(revision, repo_name,
277 c.cs = self.__get_cs_or_redirect(revision, repo_name,
278 redirect_after=False)
278 redirect_after=False)
279 if c.cs is None:
279 if c.cs is None:
280 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
280 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
281
281
282 c.f_path = f_path
282 c.f_path = f_path
283
283
284 if r_post:
284 if r_post:
285 unix_mode = 0
285 unix_mode = 0
286 content = convert_line_endings(r_post.get('content'), unix_mode)
286 content = convert_line_endings(r_post.get('content'), unix_mode)
287
287
288 message = r_post.get('message') or (_('Added %s via RhodeCode')
288 message = r_post.get('message') or (_('Added %s via RhodeCode')
289 % (f_path))
289 % (f_path))
290 location = r_post.get('location')
290 location = r_post.get('location')
291 filename = r_post.get('filename')
291 filename = r_post.get('filename')
292 file_obj = r_post.get('upload_file', None)
292 file_obj = r_post.get('upload_file', None)
293
293
294 if file_obj is not None and hasattr(file_obj, 'filename'):
294 if file_obj is not None and hasattr(file_obj, 'filename'):
295 filename = file_obj.filename
295 filename = file_obj.filename
296 content = file_obj.file
296 content = file_obj.file
297
297
298 node_path = os.path.join(location, filename)
298 node_path = os.path.join(location, filename)
299 author = self.rhodecode_user.full_contact
299 author = self.rhodecode_user.full_contact
300
300
301 if not content:
301 if not content:
302 h.flash(_('No content'), category='warning')
302 h.flash(_('No content'), category='warning')
303 return redirect(url('changeset_home', repo_name=c.repo_name,
303 return redirect(url('changeset_home', repo_name=c.repo_name,
304 revision='tip'))
304 revision='tip'))
305 if not filename:
305 if not filename:
306 h.flash(_('No filename'), category='warning')
306 h.flash(_('No filename'), category='warning')
307 return redirect(url('changeset_home', repo_name=c.repo_name,
307 return redirect(url('changeset_home', repo_name=c.repo_name,
308 revision='tip'))
308 revision='tip'))
309
309
310 try:
310 try:
311 self.scm_model.create_node(repo=c.rhodecode_repo,
311 self.scm_model.create_node(repo=c.rhodecode_repo,
312 repo_name=repo_name, cs=c.cs,
312 repo_name=repo_name, cs=c.cs,
313 user=self.rhodecode_user,
313 user=self.rhodecode_user,
314 author=author, message=message,
314 author=author, message=message,
315 content=content, f_path=node_path)
315 content=content, f_path=node_path)
316 h.flash(_('Successfully committed to %s' % node_path),
316 h.flash(_('Successfully committed to %s' % node_path),
317 category='success')
317 category='success')
318 except NodeAlreadyExistsError, e:
318 except NodeAlreadyExistsError, e:
319 h.flash(_(e), category='error')
319 h.flash(_(e), category='error')
320 except Exception:
320 except Exception:
321 log.error(traceback.format_exc())
321 log.error(traceback.format_exc())
322 h.flash(_('Error occurred during commit'), category='error')
322 h.flash(_('Error occurred during commit'), category='error')
323 return redirect(url('changeset_home',
323 return redirect(url('changeset_home',
324 repo_name=c.repo_name, revision='tip'))
324 repo_name=c.repo_name, revision='tip'))
325
325
326 return render('files/files_add.html')
326 return render('files/files_add.html')
327
327
328 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
328 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
329 'repository.admin')
329 'repository.admin')
330 def archivefile(self, repo_name, fname):
330 def archivefile(self, repo_name, fname):
331
331
332 fileformat = None
332 fileformat = None
333 revision = None
333 revision = None
334 ext = None
334 ext = None
335 subrepos = request.GET.get('subrepos') == 'true'
335 subrepos = request.GET.get('subrepos') == 'true'
336
336
337 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
337 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
338 archive_spec = fname.split(ext_data[1])
338 archive_spec = fname.split(ext_data[1])
339 if len(archive_spec) == 2 and archive_spec[1] == '':
339 if len(archive_spec) == 2 and archive_spec[1] == '':
340 fileformat = a_type or ext_data[1]
340 fileformat = a_type or ext_data[1]
341 revision = archive_spec[0]
341 revision = archive_spec[0]
342 ext = ext_data[1]
342 ext = ext_data[1]
343
343
344 try:
344 try:
345 dbrepo = RepoModel().get_by_repo_name(repo_name)
345 dbrepo = RepoModel().get_by_repo_name(repo_name)
346 if dbrepo.enable_downloads is False:
346 if dbrepo.enable_downloads is False:
347 return _('downloads disabled')
347 return _('downloads disabled')
348
348
349 if c.rhodecode_repo.alias == 'hg':
349 if c.rhodecode_repo.alias == 'hg':
350 # patch and reset hooks section of UI config to not run any
350 # patch and reset hooks section of UI config to not run any
351 # hooks on fetching archives with subrepos
351 # hooks on fetching archives with subrepos
352 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
352 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
353 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
353 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
354
354
355 cs = c.rhodecode_repo.get_changeset(revision)
355 cs = c.rhodecode_repo.get_changeset(revision)
356 content_type = settings.ARCHIVE_SPECS[fileformat][0]
356 content_type = settings.ARCHIVE_SPECS[fileformat][0]
357 except ChangesetDoesNotExistError:
357 except ChangesetDoesNotExistError:
358 return _('Unknown revision %s') % revision
358 return _('Unknown revision %s') % revision
359 except EmptyRepositoryError:
359 except EmptyRepositoryError:
360 return _('Empty repository')
360 return _('Empty repository')
361 except (ImproperArchiveTypeError, KeyError):
361 except (ImproperArchiveTypeError, KeyError):
362 return _('Unknown archive type')
362 return _('Unknown archive type')
363
363
364 fd, archive = tempfile.mkstemp()
364 fd, archive = tempfile.mkstemp()
365 t = open(archive, 'wb')
365 t = open(archive, 'wb')
366 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
366 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
367 t.close()
367 t.close()
368
368
369 def get_chunked_archive(archive):
369 def get_chunked_archive(archive):
370 stream = open(archive, 'rb')
370 stream = open(archive, 'rb')
371 while True:
371 while True:
372 data = stream.read(16 * 1024)
372 data = stream.read(16 * 1024)
373 if not data:
373 if not data:
374 stream.close()
374 stream.close()
375 os.close(fd)
375 os.close(fd)
376 os.remove(archive)
376 os.remove(archive)
377 break
377 break
378 yield data
378 yield data
379
379
380 response.content_disposition = str('attachment; filename=%s-%s%s' \
380 response.content_disposition = str('attachment; filename=%s-%s%s' \
381 % (repo_name, revision[:12], ext))
381 % (repo_name, revision[:12], ext))
382 response.content_type = str(content_type)
382 response.content_type = str(content_type)
383 return get_chunked_archive(archive)
383 return get_chunked_archive(archive)
384
384
385 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
385 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
386 'repository.admin')
386 'repository.admin')
387 def diff(self, repo_name, f_path):
387 def diff(self, repo_name, f_path):
388 ignore_whitespace = request.GET.get('ignorews') == '1'
388 ignore_whitespace = request.GET.get('ignorews') == '1'
389 line_context = request.GET.get('context', 3)
389 line_context = request.GET.get('context', 3)
390 diff1 = request.GET.get('diff1', '')
390 diff1 = request.GET.get('diff1', '')
391 diff2 = request.GET.get('diff2', '')
391 diff2 = request.GET.get('diff2', '')
392 c.action = request.GET.get('diff')
392 c.action = request.GET.get('diff')
393 c.no_changes = diff1 == diff2
393 c.no_changes = diff1 == diff2
394 c.f_path = f_path
394 c.f_path = f_path
395 c.big_diff = False
395 c.big_diff = False
396 c.anchor_url = anchor_url
396 c.anchor_url = anchor_url
397 c.ignorews_url = _ignorews_url
397 c.ignorews_url = _ignorews_url
398 c.context_url = _context_url
398 c.context_url = _context_url
399 c.changes = OrderedDict()
399 c.changes = OrderedDict()
400 c.changes[diff2] = []
400 c.changes[diff2] = []
401 try:
401 try:
402 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
402 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
403 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
403 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
404 node1 = c.changeset_1.get_node(f_path)
404 node1 = c.changeset_1.get_node(f_path)
405 else:
405 else:
406 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
406 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
407 node1 = FileNode('.', '', changeset=c.changeset_1)
407 node1 = FileNode('.', '', changeset=c.changeset_1)
408
408
409 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
409 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
410 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
410 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
411 node2 = c.changeset_2.get_node(f_path)
411 node2 = c.changeset_2.get_node(f_path)
412 else:
412 else:
413 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
413 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
414 node2 = FileNode('.', '', changeset=c.changeset_2)
414 node2 = FileNode('.', '', changeset=c.changeset_2)
415 except RepositoryError:
415 except RepositoryError:
416 return redirect(url('files_home', repo_name=c.repo_name,
416 return redirect(url('files_home', repo_name=c.repo_name,
417 f_path=f_path))
417 f_path=f_path))
418
418
419 if c.action == 'download':
419 if c.action == 'download':
420 _diff = diffs.get_gitdiff(node1, node2,
420 _diff = diffs.get_gitdiff(node1, node2,
421 ignore_whitespace=ignore_whitespace,
421 ignore_whitespace=ignore_whitespace,
422 context=line_context)
422 context=line_context)
423 diff = diffs.DiffProcessor(_diff, format='gitdiff')
423 diff = diffs.DiffProcessor(_diff, format='gitdiff')
424
424
425 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
425 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
426 response.content_type = 'text/plain'
426 response.content_type = 'text/plain'
427 response.content_disposition = (
427 response.content_disposition = (
428 'attachment; filename=%s' % diff_name
428 'attachment; filename=%s' % diff_name
429 )
429 )
430 return diff.raw_diff()
430 return diff.raw_diff()
431
431
432 elif c.action == 'raw':
432 elif c.action == 'raw':
433 _diff = diffs.get_gitdiff(node1, node2,
433 _diff = diffs.get_gitdiff(node1, node2,
434 ignore_whitespace=ignore_whitespace,
434 ignore_whitespace=ignore_whitespace,
435 context=line_context)
435 context=line_context)
436 diff = diffs.DiffProcessor(_diff, format='gitdiff')
436 diff = diffs.DiffProcessor(_diff, format='gitdiff')
437 response.content_type = 'text/plain'
437 response.content_type = 'text/plain'
438 return diff.raw_diff()
438 return diff.raw_diff()
439
439
440 else:
440 else:
441 fid = h.FID(diff2, node2.path)
441 fid = h.FID(diff2, node2.path)
442 line_context_lcl = get_line_ctx(fid, request.GET)
442 line_context_lcl = get_line_ctx(fid, request.GET)
443 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
443 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
444
444
445 lim = request.GET.get('fulldiff') or self.cut_off_limit
445 lim = request.GET.get('fulldiff') or self.cut_off_limit
446 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
446 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
447 filenode_new=node2,
447 filenode_new=node2,
448 cut_off_limit=lim,
448 cut_off_limit=lim,
449 ignore_whitespace=ign_whitespace_lcl,
449 ignore_whitespace=ign_whitespace_lcl,
450 line_context=line_context_lcl,
450 line_context=line_context_lcl,
451 enable_comments=False)
451 enable_comments=False)
452
452
453 c.changes = [('', node2, diff, cs1, cs2, st,)]
453 c.changes = [('', node2, diff, cs1, cs2, st,)]
454
454
455 return render('files/file_diff.html')
455 return render('files/file_diff.html')
456
456
457 def _get_node_history(self, cs, f_path):
457 def _get_node_history(self, cs, f_path):
458 changesets = cs.get_file_history(f_path)
458 changesets = cs.get_file_history(f_path)
459 hist_l = []
459 hist_l = []
460
460
461 changesets_group = ([], _("Changesets"))
461 changesets_group = ([], _("Changesets"))
462 branches_group = ([], _("Branches"))
462 branches_group = ([], _("Branches"))
463 tags_group = ([], _("Tags"))
463 tags_group = ([], _("Tags"))
464 _hg = cs.repository.alias == 'hg'
464 _hg = cs.repository.alias == 'hg'
465 for chs in changesets:
465 for chs in changesets:
466 _branch = '(%s)' % chs.branch if _hg else ''
466 _branch = '(%s)' % chs.branch if _hg else ''
467 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
467 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
468 changesets_group[0].append((chs.raw_id, n_desc,))
468 changesets_group[0].append((chs.raw_id, n_desc,))
469
469
470 hist_l.append(changesets_group)
470 hist_l.append(changesets_group)
471
471
472 for name, chs in c.rhodecode_repo.branches.items():
472 for name, chs in c.rhodecode_repo.branches.items():
473 branches_group[0].append((chs, name),)
473 branches_group[0].append((chs, name),)
474 hist_l.append(branches_group)
474 hist_l.append(branches_group)
475
475
476 for name, chs in c.rhodecode_repo.tags.items():
476 for name, chs in c.rhodecode_repo.tags.items():
477 tags_group[0].append((chs, name),)
477 tags_group[0].append((chs, name),)
478 hist_l.append(tags_group)
478 hist_l.append(tags_group)
479
479
480 return hist_l
480 return hist_l
481
481
482 @jsonify
482 @jsonify
483 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
483 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
484 'repository.admin')
484 'repository.admin')
485 def nodelist(self, repo_name, revision, f_path):
485 def nodelist(self, repo_name, revision, f_path):
486 if request.environ.get('HTTP_X_PARTIAL_XHR'):
486 if request.environ.get('HTTP_X_PARTIAL_XHR'):
487 cs = self.__get_cs_or_redirect(revision, repo_name)
487 cs = self.__get_cs_or_redirect(revision, repo_name)
488 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
488 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
489 flat=False)
489 flat=False)
490 return _d + _f
490 return {'nodes': _d + _f}
@@ -1,1325 +1,1324 b''
1 /**
1 /**
2 RhodeCode JS Files
2 RhodeCode JS Files
3 **/
3 **/
4
4
5 if (typeof console == "undefined" || typeof console.log == "undefined"){
5 if (typeof console == "undefined" || typeof console.log == "undefined"){
6 console = { log: function() {} }
6 console = { log: function() {} }
7 }
7 }
8
8
9
9
10 var str_repeat = function(i, m) {
10 var str_repeat = function(i, m) {
11 for (var o = []; m > 0; o[--m] = i);
11 for (var o = []; m > 0; o[--m] = i);
12 return o.join('');
12 return o.join('');
13 };
13 };
14
14
15 /**
15 /**
16 * INJECT .format function into String
16 * INJECT .format function into String
17 * Usage: "My name is {0} {1}".format("Johny","Bravo")
17 * Usage: "My name is {0} {1}".format("Johny","Bravo")
18 * Return "My name is Johny Bravo"
18 * Return "My name is Johny Bravo"
19 * Inspired by https://gist.github.com/1049426
19 * Inspired by https://gist.github.com/1049426
20 */
20 */
21 String.prototype.format = function() {
21 String.prototype.format = function() {
22
22
23 function format() {
23 function format() {
24 var str = this;
24 var str = this;
25 var len = arguments.length+1;
25 var len = arguments.length+1;
26 var safe = undefined;
26 var safe = undefined;
27 var arg = undefined;
27 var arg = undefined;
28
28
29 // For each {0} {1} {n...} replace with the argument in that position. If
29 // For each {0} {1} {n...} replace with the argument in that position. If
30 // the argument is an object or an array it will be stringified to JSON.
30 // the argument is an object or an array it will be stringified to JSON.
31 for (var i=0; i < len; arg = arguments[i++]) {
31 for (var i=0; i < len; arg = arguments[i++]) {
32 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
32 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
33 str = str.replace(RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
33 str = str.replace(RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
34 }
34 }
35 return str;
35 return str;
36 }
36 }
37
37
38 // Save a reference of what may already exist under the property native.
38 // Save a reference of what may already exist under the property native.
39 // Allows for doing something like: if("".format.native) { /* use native */ }
39 // Allows for doing something like: if("".format.native) { /* use native */ }
40 format.native = String.prototype.format;
40 format.native = String.prototype.format;
41
41
42 // Replace the prototype property
42 // Replace the prototype property
43 return format;
43 return format;
44
44
45 }();
45 }();
46
46
47 String.prototype.strip = function(char) {
47 String.prototype.strip = function(char) {
48 if(char === undefined){
48 if(char === undefined){
49 char = '\\s';
49 char = '\\s';
50 }
50 }
51 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
51 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
52 }
52 }
53 String.prototype.lstrip = function(char) {
53 String.prototype.lstrip = function(char) {
54 if(char === undefined){
54 if(char === undefined){
55 char = '\\s';
55 char = '\\s';
56 }
56 }
57 return this.replace(new RegExp('^'+char+'+'),'');
57 return this.replace(new RegExp('^'+char+'+'),'');
58 }
58 }
59 String.prototype.rstrip = function(char) {
59 String.prototype.rstrip = function(char) {
60 if(char === undefined){
60 if(char === undefined){
61 char = '\\s';
61 char = '\\s';
62 }
62 }
63 return this.replace(new RegExp(''+char+'+$'),'');
63 return this.replace(new RegExp(''+char+'+$'),'');
64 }
64 }
65
65
66 /**
66 /**
67 * SmartColorGenerator
67 * SmartColorGenerator
68 *
68 *
69 *usage::
69 *usage::
70 * var CG = new ColorGenerator();
70 * var CG = new ColorGenerator();
71 * var col = CG.getColor(key); //returns array of RGB
71 * var col = CG.getColor(key); //returns array of RGB
72 * 'rgb({0})'.format(col.join(',')
72 * 'rgb({0})'.format(col.join(',')
73 *
73 *
74 * @returns {ColorGenerator}
74 * @returns {ColorGenerator}
75 */
75 */
76 var ColorGenerator = function(){
76 var ColorGenerator = function(){
77 this.GOLDEN_RATIO = 0.618033988749895;
77 this.GOLDEN_RATIO = 0.618033988749895;
78 this.CURRENT_RATIO = 0.22717784590367374 // this can be random
78 this.CURRENT_RATIO = 0.22717784590367374 // this can be random
79 this.HSV_1 = 0.75;//saturation
79 this.HSV_1 = 0.75;//saturation
80 this.HSV_2 = 0.95;
80 this.HSV_2 = 0.95;
81 this.color;
81 this.color;
82 this.cacheColorMap = {};
82 this.cacheColorMap = {};
83 };
83 };
84
84
85 ColorGenerator.prototype = {
85 ColorGenerator.prototype = {
86 getColor:function(key){
86 getColor:function(key){
87 if(this.cacheColorMap[key] !== undefined){
87 if(this.cacheColorMap[key] !== undefined){
88 return this.cacheColorMap[key];
88 return this.cacheColorMap[key];
89 }
89 }
90 else{
90 else{
91 this.cacheColorMap[key] = this.generateColor();
91 this.cacheColorMap[key] = this.generateColor();
92 return this.cacheColorMap[key];
92 return this.cacheColorMap[key];
93 }
93 }
94 },
94 },
95 _hsvToRgb:function(h,s,v){
95 _hsvToRgb:function(h,s,v){
96 if (s == 0.0)
96 if (s == 0.0)
97 return [v, v, v];
97 return [v, v, v];
98 i = parseInt(h * 6.0)
98 i = parseInt(h * 6.0)
99 f = (h * 6.0) - i
99 f = (h * 6.0) - i
100 p = v * (1.0 - s)
100 p = v * (1.0 - s)
101 q = v * (1.0 - s * f)
101 q = v * (1.0 - s * f)
102 t = v * (1.0 - s * (1.0 - f))
102 t = v * (1.0 - s * (1.0 - f))
103 i = i % 6
103 i = i % 6
104 if (i == 0)
104 if (i == 0)
105 return [v, t, p]
105 return [v, t, p]
106 if (i == 1)
106 if (i == 1)
107 return [q, v, p]
107 return [q, v, p]
108 if (i == 2)
108 if (i == 2)
109 return [p, v, t]
109 return [p, v, t]
110 if (i == 3)
110 if (i == 3)
111 return [p, q, v]
111 return [p, q, v]
112 if (i == 4)
112 if (i == 4)
113 return [t, p, v]
113 return [t, p, v]
114 if (i == 5)
114 if (i == 5)
115 return [v, p, q]
115 return [v, p, q]
116 },
116 },
117 generateColor:function(){
117 generateColor:function(){
118 this.CURRENT_RATIO = this.CURRENT_RATIO+this.GOLDEN_RATIO;
118 this.CURRENT_RATIO = this.CURRENT_RATIO+this.GOLDEN_RATIO;
119 this.CURRENT_RATIO = this.CURRENT_RATIO %= 1;
119 this.CURRENT_RATIO = this.CURRENT_RATIO %= 1;
120 HSV_tuple = [this.CURRENT_RATIO, this.HSV_1, this.HSV_2]
120 HSV_tuple = [this.CURRENT_RATIO, this.HSV_1, this.HSV_2]
121 RGB_tuple = this._hsvToRgb(HSV_tuple[0],HSV_tuple[1],HSV_tuple[2]);
121 RGB_tuple = this._hsvToRgb(HSV_tuple[0],HSV_tuple[1],HSV_tuple[2]);
122 function toRgb(v){
122 function toRgb(v){
123 return ""+parseInt(v*256)
123 return ""+parseInt(v*256)
124 }
124 }
125 return [toRgb(RGB_tuple[0]),toRgb(RGB_tuple[1]),toRgb(RGB_tuple[2])];
125 return [toRgb(RGB_tuple[0]),toRgb(RGB_tuple[1]),toRgb(RGB_tuple[2])];
126
126
127 }
127 }
128 }
128 }
129
129
130
130
131
131
132
132
133
133
134 /**
134 /**
135 * GLOBAL YUI Shortcuts
135 * GLOBAL YUI Shortcuts
136 */
136 */
137 var YUC = YAHOO.util.Connect;
137 var YUC = YAHOO.util.Connect;
138 var YUD = YAHOO.util.Dom;
138 var YUD = YAHOO.util.Dom;
139 var YUE = YAHOO.util.Event;
139 var YUE = YAHOO.util.Event;
140 var YUQ = YAHOO.util.Selector.query;
140 var YUQ = YAHOO.util.Selector.query;
141
141
142 // defines if push state is enabled for this browser ?
142 // defines if push state is enabled for this browser ?
143 var push_state_enabled = Boolean(
143 var push_state_enabled = Boolean(
144 window.history && window.history.pushState && window.history.replaceState
144 window.history && window.history.pushState && window.history.replaceState
145 && !( /* disable for versions of iOS before version 4.3 (8F190) */
145 && !( /* disable for versions of iOS before version 4.3 (8F190) */
146 (/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent)
146 (/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent)
147 /* disable for the mercury iOS browser, or at least older versions of the webkit engine */
147 /* disable for the mercury iOS browser, or at least older versions of the webkit engine */
148 || (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent)
148 || (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent)
149 )
149 )
150 );
150 );
151
151
152 var _run_callbacks = function(callbacks){
152 var _run_callbacks = function(callbacks){
153 if (callbacks !== undefined){
153 if (callbacks !== undefined){
154 var _l = callbacks.length;
154 var _l = callbacks.length;
155 for (var i=0;i<_l;i++){
155 for (var i=0;i<_l;i++){
156 var func = callbacks[i];
156 var func = callbacks[i];
157 if(typeof(func)=='function'){
157 if(typeof(func)=='function'){
158 try{
158 try{
159 func();
159 func();
160 }catch (err){};
160 }catch (err){};
161 }
161 }
162 }
162 }
163 }
163 }
164 }
164 }
165
165
166 /**
166 /**
167 * Partial Ajax Implementation
167 * Partial Ajax Implementation
168 *
168 *
169 * @param url: defines url to make partial request
169 * @param url: defines url to make partial request
170 * @param container: defines id of container to input partial result
170 * @param container: defines id of container to input partial result
171 * @param s_call: success callback function that takes o as arg
171 * @param s_call: success callback function that takes o as arg
172 * o.tId
172 * o.tId
173 * o.status
173 * o.status
174 * o.statusText
174 * o.statusText
175 * o.getResponseHeader[ ]
175 * o.getResponseHeader[ ]
176 * o.getAllResponseHeaders
176 * o.getAllResponseHeaders
177 * o.responseText
177 * o.responseText
178 * o.responseXML
178 * o.responseXML
179 * o.argument
179 * o.argument
180 * @param f_call: failure callback
180 * @param f_call: failure callback
181 * @param args arguments
181 * @param args arguments
182 */
182 */
183 function ypjax(url,container,s_call,f_call,args){
183 function ypjax(url,container,s_call,f_call,args){
184 var method='GET';
184 var method='GET';
185 if(args===undefined){
185 if(args===undefined){
186 args=null;
186 args=null;
187 }
187 }
188
188
189 // Set special header for partial ajax == HTTP_X_PARTIAL_XHR
189 // Set special header for partial ajax == HTTP_X_PARTIAL_XHR
190 YUC.initHeader('X-PARTIAL-XHR',true);
190 YUC.initHeader('X-PARTIAL-XHR',true);
191
191
192 // wrapper of passed callback
192 // wrapper of passed callback
193 var s_wrapper = (function(o){
193 var s_wrapper = (function(o){
194 return function(o){
194 return function(o){
195 YUD.get(container).innerHTML=o.responseText;
195 YUD.get(container).innerHTML=o.responseText;
196 YUD.setStyle(container,'opacity','1.0');
196 YUD.setStyle(container,'opacity','1.0');
197 //execute the given original callback
197 //execute the given original callback
198 if (s_call !== undefined){
198 if (s_call !== undefined){
199 s_call(o);
199 s_call(o);
200 }
200 }
201 }
201 }
202 })()
202 })()
203 YUD.setStyle(container,'opacity','0.3');
203 YUD.setStyle(container,'opacity','0.3');
204 YUC.asyncRequest(method,url,{
204 YUC.asyncRequest(method,url,{
205 success:s_wrapper,
205 success:s_wrapper,
206 failure:function(o){
206 failure:function(o){
207 console.log(o);
207 console.log(o);
208 YUD.get(container).innerHTML='ERROR';
208 YUD.get(container).innerHTML='ERROR';
209 YUD.setStyle(container,'opacity','1.0');
209 YUD.setStyle(container,'opacity','1.0');
210 YUD.setStyle(container,'color','red');
210 YUD.setStyle(container,'color','red');
211 }
211 }
212 },args);
212 },args);
213
213
214 };
214 };
215
215
216 var ajaxPOST = function(url,postData,success) {
216 var ajaxPOST = function(url,postData,success) {
217 // Set special header for ajax == HTTP_X_PARTIAL_XHR
217 // Set special header for ajax == HTTP_X_PARTIAL_XHR
218 YUC.initHeader('X-PARTIAL-XHR',true);
218 YUC.initHeader('X-PARTIAL-XHR',true);
219
219
220 var toQueryString = function(o) {
220 var toQueryString = function(o) {
221 if(typeof o !== 'object') {
221 if(typeof o !== 'object') {
222 return false;
222 return false;
223 }
223 }
224 var _p, _qs = [];
224 var _p, _qs = [];
225 for(_p in o) {
225 for(_p in o) {
226 _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
226 _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
227 }
227 }
228 return _qs.join('&');
228 return _qs.join('&');
229 };
229 };
230
230
231 var sUrl = url;
231 var sUrl = url;
232 var callback = {
232 var callback = {
233 success: success,
233 success: success,
234 failure: function (o) {
234 failure: function (o) {
235 alert("error");
235 alert("error");
236 },
236 },
237 };
237 };
238 var postData = toQueryString(postData);
238 var postData = toQueryString(postData);
239 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
239 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);
240 return request;
240 return request;
241 };
241 };
242
242
243
243
244 /**
244 /**
245 * tooltip activate
245 * tooltip activate
246 */
246 */
247 var tooltip_activate = function(){
247 var tooltip_activate = function(){
248 function toolTipsId(){
248 function toolTipsId(){
249 var ids = [];
249 var ids = [];
250 var tts = YUQ('.tooltip');
250 var tts = YUQ('.tooltip');
251 for (var i = 0; i < tts.length; i++) {
251 for (var i = 0; i < tts.length; i++) {
252 // if element doesn't not have and id
252 // if element doesn't not have and id
253 // autogenerate one for tooltip
253 // autogenerate one for tooltip
254 if (!tts[i].id){
254 if (!tts[i].id){
255 tts[i].id='tt'+((i*100)+tts.length);
255 tts[i].id='tt'+((i*100)+tts.length);
256 }
256 }
257 ids.push(tts[i].id);
257 ids.push(tts[i].id);
258 }
258 }
259 return ids
259 return ids
260 };
260 };
261 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
261 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
262 context: [[toolTipsId()],"tl","bl",null,[0,5]],
262 context: [[toolTipsId()],"tl","bl",null,[0,5]],
263 monitorresize:false,
263 monitorresize:false,
264 xyoffset :[0,0],
264 xyoffset :[0,0],
265 autodismissdelay:300000,
265 autodismissdelay:300000,
266 hidedelay:5,
266 hidedelay:5,
267 showdelay:20,
267 showdelay:20,
268 });
268 });
269 };
269 };
270
270
271 /**
271 /**
272 * show more
272 * show more
273 */
273 */
274 var show_more_event = function(){
274 var show_more_event = function(){
275 YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
275 YUE.on(YUD.getElementsByClassName('show_more'),'click',function(e){
276 var el = e.target;
276 var el = e.target;
277 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
277 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
278 YUD.setStyle(el.parentNode,'display','none');
278 YUD.setStyle(el.parentNode,'display','none');
279 });
279 });
280 };
280 };
281
281
282
282
283 /**
283 /**
284 * Quick filter widget
284 * Quick filter widget
285 *
285 *
286 * @param target: filter input target
286 * @param target: filter input target
287 * @param nodes: list of nodes in html we want to filter.
287 * @param nodes: list of nodes in html we want to filter.
288 * @param display_element function that takes current node from nodes and
288 * @param display_element function that takes current node from nodes and
289 * does hide or show based on the node
289 * does hide or show based on the node
290 *
290 *
291 */
291 */
292 var q_filter = function(target,nodes,display_element){
292 var q_filter = function(target,nodes,display_element){
293
293
294 var nodes = nodes;
294 var nodes = nodes;
295 var q_filter_field = YUD.get(target);
295 var q_filter_field = YUD.get(target);
296 var F = YAHOO.namespace(target);
296 var F = YAHOO.namespace(target);
297
297
298 YUE.on(q_filter_field,'click',function(){
298 YUE.on(q_filter_field,'click',function(){
299 q_filter_field.value = '';
299 q_filter_field.value = '';
300 });
300 });
301
301
302 YUE.on(q_filter_field,'keyup',function(e){
302 YUE.on(q_filter_field,'keyup',function(e){
303 clearTimeout(F.filterTimeout);
303 clearTimeout(F.filterTimeout);
304 F.filterTimeout = setTimeout(F.updateFilter,600);
304 F.filterTimeout = setTimeout(F.updateFilter,600);
305 });
305 });
306
306
307 F.filterTimeout = null;
307 F.filterTimeout = null;
308
308
309 var show_node = function(node){
309 var show_node = function(node){
310 YUD.setStyle(node,'display','')
310 YUD.setStyle(node,'display','')
311 }
311 }
312 var hide_node = function(node){
312 var hide_node = function(node){
313 YUD.setStyle(node,'display','none');
313 YUD.setStyle(node,'display','none');
314 }
314 }
315
315
316 F.updateFilter = function() {
316 F.updateFilter = function() {
317 // Reset timeout
317 // Reset timeout
318 F.filterTimeout = null;
318 F.filterTimeout = null;
319
319
320 var obsolete = [];
320 var obsolete = [];
321
321
322 var req = q_filter_field.value.toLowerCase();
322 var req = q_filter_field.value.toLowerCase();
323
323
324 var l = nodes.length;
324 var l = nodes.length;
325 var i;
325 var i;
326 var showing = 0;
326 var showing = 0;
327
327
328 for (i=0;i<l;i++ ){
328 for (i=0;i<l;i++ ){
329 var n = nodes[i];
329 var n = nodes[i];
330 var target_element = display_element(n)
330 var target_element = display_element(n)
331 if(req && n.innerHTML.toLowerCase().indexOf(req) == -1){
331 if(req && n.innerHTML.toLowerCase().indexOf(req) == -1){
332 hide_node(target_element);
332 hide_node(target_element);
333 }
333 }
334 else{
334 else{
335 show_node(target_element);
335 show_node(target_element);
336 showing+=1;
336 showing+=1;
337 }
337 }
338 }
338 }
339
339
340 // if repo_count is set update the number
340 // if repo_count is set update the number
341 var cnt = YUD.get('repo_count');
341 var cnt = YUD.get('repo_count');
342 if(cnt){
342 if(cnt){
343 YUD.get('repo_count').innerHTML = showing;
343 YUD.get('repo_count').innerHTML = showing;
344 }
344 }
345
345
346 }
346 }
347 };
347 };
348
348
349 var tableTr = function(cls,body){
349 var tableTr = function(cls,body){
350 var tr = document.createElement('tr');
350 var tr = document.createElement('tr');
351 YUD.addClass(tr, cls);
351 YUD.addClass(tr, cls);
352
352
353
353
354 var cont = new YAHOO.util.Element(body);
354 var cont = new YAHOO.util.Element(body);
355 var comment_id = fromHTML(body).children[0].id.split('comment-')[1];
355 var comment_id = fromHTML(body).children[0].id.split('comment-')[1];
356 tr.id = 'comment-tr-{0}'.format(comment_id);
356 tr.id = 'comment-tr-{0}'.format(comment_id);
357 tr.innerHTML = '<td class="lineno-inline new-inline"></td>'+
357 tr.innerHTML = '<td class="lineno-inline new-inline"></td>'+
358 '<td class="lineno-inline old-inline"></td>'+
358 '<td class="lineno-inline old-inline"></td>'+
359 '<td>{0}</td>'.format(body);
359 '<td>{0}</td>'.format(body);
360 return tr;
360 return tr;
361 };
361 };
362
362
363 /** comments **/
363 /** comments **/
364 var removeInlineForm = function(form) {
364 var removeInlineForm = function(form) {
365 form.parentNode.removeChild(form);
365 form.parentNode.removeChild(form);
366 };
366 };
367
367
368 var createInlineForm = function(parent_tr, f_path, line) {
368 var createInlineForm = function(parent_tr, f_path, line) {
369 var tmpl = YUD.get('comment-inline-form-template').innerHTML;
369 var tmpl = YUD.get('comment-inline-form-template').innerHTML;
370 tmpl = tmpl.format(f_path, line);
370 tmpl = tmpl.format(f_path, line);
371 var form = tableTr('comment-form-inline',tmpl)
371 var form = tableTr('comment-form-inline',tmpl)
372
372
373 // create event for hide button
373 // create event for hide button
374 form = new YAHOO.util.Element(form);
374 form = new YAHOO.util.Element(form);
375 var form_hide_button = new YAHOO.util.Element(form.getElementsByClassName('hide-inline-form')[0]);
375 var form_hide_button = new YAHOO.util.Element(form.getElementsByClassName('hide-inline-form')[0]);
376 form_hide_button.on('click', function(e) {
376 form_hide_button.on('click', function(e) {
377 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
377 var newtr = e.currentTarget.parentNode.parentNode.parentNode.parentNode.parentNode;
378 if(YUD.hasClass(newtr.nextElementSibling,'inline-comments-button')){
378 if(YUD.hasClass(newtr.nextElementSibling,'inline-comments-button')){
379 YUD.setStyle(newtr.nextElementSibling,'display','');
379 YUD.setStyle(newtr.nextElementSibling,'display','');
380 }
380 }
381 removeInlineForm(newtr);
381 removeInlineForm(newtr);
382 YUD.removeClass(parent_tr, 'form-open');
382 YUD.removeClass(parent_tr, 'form-open');
383
383
384 });
384 });
385
385
386 return form
386 return form
387 };
387 };
388
388
389 /**
389 /**
390 * Inject inline comment for on given TR this tr should be always an .line
390 * Inject inline comment for on given TR this tr should be always an .line
391 * tr containing the line. Code will detect comment, and always put the comment
391 * tr containing the line. Code will detect comment, and always put the comment
392 * block at the very bottom
392 * block at the very bottom
393 */
393 */
394 var injectInlineForm = function(tr){
394 var injectInlineForm = function(tr){
395 if(!YUD.hasClass(tr, 'line')){
395 if(!YUD.hasClass(tr, 'line')){
396 return
396 return
397 }
397 }
398 var submit_url = AJAX_COMMENT_URL;
398 var submit_url = AJAX_COMMENT_URL;
399 if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context') || YUD.hasClass(tr,'no-comment')){
399 if(YUD.hasClass(tr,'form-open') || YUD.hasClass(tr,'context') || YUD.hasClass(tr,'no-comment')){
400 return
400 return
401 }
401 }
402 YUD.addClass(tr,'form-open');
402 YUD.addClass(tr,'form-open');
403 var node = tr.parentNode.parentNode.parentNode.getElementsByClassName('full_f_path')[0];
403 var node = tr.parentNode.parentNode.parentNode.getElementsByClassName('full_f_path')[0];
404 var f_path = YUD.getAttribute(node,'path');
404 var f_path = YUD.getAttribute(node,'path');
405 var lineno = getLineNo(tr);
405 var lineno = getLineNo(tr);
406 var form = createInlineForm(tr, f_path, lineno, submit_url);
406 var form = createInlineForm(tr, f_path, lineno, submit_url);
407
407
408 var parent = tr;
408 var parent = tr;
409 while (1){
409 while (1){
410 var n = parent.nextElementSibling;
410 var n = parent.nextElementSibling;
411 // next element are comments !
411 // next element are comments !
412 if(YUD.hasClass(n,'inline-comments')){
412 if(YUD.hasClass(n,'inline-comments')){
413 parent = n;
413 parent = n;
414 }
414 }
415 else{
415 else{
416 break;
416 break;
417 }
417 }
418 }
418 }
419 YUD.insertAfter(form,parent);
419 YUD.insertAfter(form,parent);
420
420
421 YUD.get('text_'+lineno).focus();
421 YUD.get('text_'+lineno).focus();
422 var f = YUD.get(form);
422 var f = YUD.get(form);
423
423
424 var overlay = f.getElementsByClassName('overlay')[0];
424 var overlay = f.getElementsByClassName('overlay')[0];
425 var _form = f.getElementsByClassName('inline-form')[0];
425 var _form = f.getElementsByClassName('inline-form')[0];
426
426
427 form.on('submit',function(e){
427 form.on('submit',function(e){
428 YUE.preventDefault(e);
428 YUE.preventDefault(e);
429
429
430 //ajax submit
430 //ajax submit
431 var text = YUD.get('text_'+lineno).value;
431 var text = YUD.get('text_'+lineno).value;
432 var postData = {
432 var postData = {
433 'text':text,
433 'text':text,
434 'f_path':f_path,
434 'f_path':f_path,
435 'line':lineno
435 'line':lineno
436 };
436 };
437
437
438 if(lineno === undefined){
438 if(lineno === undefined){
439 alert('missing line !');
439 alert('missing line !');
440 return
440 return
441 }
441 }
442 if(f_path === undefined){
442 if(f_path === undefined){
443 alert('missing file path !');
443 alert('missing file path !');
444 return
444 return
445 }
445 }
446
446
447 if(text == ""){
447 if(text == ""){
448 return
448 return
449 }
449 }
450
450
451 var success = function(o){
451 var success = function(o){
452 YUD.removeClass(tr, 'form-open');
452 YUD.removeClass(tr, 'form-open');
453 removeInlineForm(f);
453 removeInlineForm(f);
454 var json_data = JSON.parse(o.responseText);
454 var json_data = JSON.parse(o.responseText);
455 renderInlineComment(json_data);
455 renderInlineComment(json_data);
456 };
456 };
457
457
458 if (YUD.hasClass(overlay,'overlay')){
458 if (YUD.hasClass(overlay,'overlay')){
459 var w = _form.offsetWidth;
459 var w = _form.offsetWidth;
460 var h = _form.offsetHeight;
460 var h = _form.offsetHeight;
461 YUD.setStyle(overlay,'width',w+'px');
461 YUD.setStyle(overlay,'width',w+'px');
462 YUD.setStyle(overlay,'height',h+'px');
462 YUD.setStyle(overlay,'height',h+'px');
463 }
463 }
464 YUD.addClass(overlay, 'submitting');
464 YUD.addClass(overlay, 'submitting');
465
465
466 ajaxPOST(submit_url, postData, success);
466 ajaxPOST(submit_url, postData, success);
467 });
467 });
468 // callbacks
468 // callbacks
469 tooltip_activate();
469 tooltip_activate();
470 };
470 };
471
471
472 var deleteComment = function(comment_id){
472 var deleteComment = function(comment_id){
473 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__',comment_id);
473 var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__',comment_id);
474 var postData = {'_method':'delete'};
474 var postData = {'_method':'delete'};
475 var success = function(o){
475 var success = function(o){
476 var n = YUD.get('comment-tr-'+comment_id);
476 var n = YUD.get('comment-tr-'+comment_id);
477 var root = n.previousElementSibling.previousElementSibling;
477 var root = n.previousElementSibling.previousElementSibling;
478 n.parentNode.removeChild(n);
478 n.parentNode.removeChild(n);
479
479
480 // scann nodes, and attach add button to last one
480 // scann nodes, and attach add button to last one
481 placeAddButton(root);
481 placeAddButton(root);
482 }
482 }
483 ajaxPOST(url,postData,success);
483 ajaxPOST(url,postData,success);
484 }
484 }
485
485
486
486
487 var createInlineAddButton = function(tr){
487 var createInlineAddButton = function(tr){
488
488
489 var label = TRANSLATION_MAP['add another comment'];
489 var label = TRANSLATION_MAP['add another comment'];
490
490
491 var html_el = document.createElement('div');
491 var html_el = document.createElement('div');
492 YUD.addClass(html_el, 'add-comment');
492 YUD.addClass(html_el, 'add-comment');
493 html_el.innerHTML = '<span class="ui-btn">{0}</span>'.format(label);
493 html_el.innerHTML = '<span class="ui-btn">{0}</span>'.format(label);
494
494
495 var add = new YAHOO.util.Element(html_el);
495 var add = new YAHOO.util.Element(html_el);
496 add.on('click', function(e) {
496 add.on('click', function(e) {
497 injectInlineForm(tr);
497 injectInlineForm(tr);
498 });
498 });
499 return add;
499 return add;
500 };
500 };
501
501
502 var getLineNo = function(tr) {
502 var getLineNo = function(tr) {
503 var line;
503 var line;
504 var o = tr.children[0].id.split('_');
504 var o = tr.children[0].id.split('_');
505 var n = tr.children[1].id.split('_');
505 var n = tr.children[1].id.split('_');
506
506
507 if (n.length >= 2) {
507 if (n.length >= 2) {
508 line = n[n.length-1];
508 line = n[n.length-1];
509 } else if (o.length >= 2) {
509 } else if (o.length >= 2) {
510 line = o[o.length-1];
510 line = o[o.length-1];
511 }
511 }
512
512
513 return line
513 return line
514 };
514 };
515
515
516 var placeAddButton = function(target_tr){
516 var placeAddButton = function(target_tr){
517 if(!target_tr){
517 if(!target_tr){
518 return
518 return
519 }
519 }
520 var last_node = target_tr;
520 var last_node = target_tr;
521 //scann
521 //scann
522 while (1){
522 while (1){
523 var n = last_node.nextElementSibling;
523 var n = last_node.nextElementSibling;
524 // next element are comments !
524 // next element are comments !
525 if(YUD.hasClass(n,'inline-comments')){
525 if(YUD.hasClass(n,'inline-comments')){
526 last_node = n;
526 last_node = n;
527 //also remove the comment button from previos
527 //also remove the comment button from previos
528 var comment_add_buttons = last_node.getElementsByClassName('add-comment');
528 var comment_add_buttons = last_node.getElementsByClassName('add-comment');
529 for(var i=0;i<comment_add_buttons.length;i++){
529 for(var i=0;i<comment_add_buttons.length;i++){
530 var b = comment_add_buttons[i];
530 var b = comment_add_buttons[i];
531 b.parentNode.removeChild(b);
531 b.parentNode.removeChild(b);
532 }
532 }
533 }
533 }
534 else{
534 else{
535 break;
535 break;
536 }
536 }
537 }
537 }
538
538
539 var add = createInlineAddButton(target_tr);
539 var add = createInlineAddButton(target_tr);
540 // get the comment div
540 // get the comment div
541 var comment_block = last_node.getElementsByClassName('comment')[0];
541 var comment_block = last_node.getElementsByClassName('comment')[0];
542 // attach add button
542 // attach add button
543 YUD.insertAfter(add,comment_block);
543 YUD.insertAfter(add,comment_block);
544 }
544 }
545
545
546 /**
546 /**
547 * Places the inline comment into the changeset block in proper line position
547 * Places the inline comment into the changeset block in proper line position
548 */
548 */
549 var placeInline = function(target_container,lineno,html){
549 var placeInline = function(target_container,lineno,html){
550 var lineid = "{0}_{1}".format(target_container,lineno);
550 var lineid = "{0}_{1}".format(target_container,lineno);
551 var target_line = YUD.get(lineid);
551 var target_line = YUD.get(lineid);
552 var comment = new YAHOO.util.Element(tableTr('inline-comments',html))
552 var comment = new YAHOO.util.Element(tableTr('inline-comments',html))
553
553
554 // check if there are comments already !
554 // check if there are comments already !
555 var parent = target_line.parentNode;
555 var parent = target_line.parentNode;
556 var root_parent = parent;
556 var root_parent = parent;
557 while (1){
557 while (1){
558 var n = parent.nextElementSibling;
558 var n = parent.nextElementSibling;
559 // next element are comments !
559 // next element are comments !
560 if(YUD.hasClass(n,'inline-comments')){
560 if(YUD.hasClass(n,'inline-comments')){
561 parent = n;
561 parent = n;
562 }
562 }
563 else{
563 else{
564 break;
564 break;
565 }
565 }
566 }
566 }
567 // put in the comment at the bottom
567 // put in the comment at the bottom
568 YUD.insertAfter(comment,parent);
568 YUD.insertAfter(comment,parent);
569
569
570 // scann nodes, and attach add button to last one
570 // scann nodes, and attach add button to last one
571 placeAddButton(root_parent);
571 placeAddButton(root_parent);
572
572
573 return target_line;
573 return target_line;
574 }
574 }
575
575
576 /**
576 /**
577 * make a single inline comment and place it inside
577 * make a single inline comment and place it inside
578 */
578 */
579 var renderInlineComment = function(json_data){
579 var renderInlineComment = function(json_data){
580 try{
580 try{
581 var html = json_data['rendered_text'];
581 var html = json_data['rendered_text'];
582 var lineno = json_data['line_no'];
582 var lineno = json_data['line_no'];
583 var target_id = json_data['target_id'];
583 var target_id = json_data['target_id'];
584 placeInline(target_id, lineno, html);
584 placeInline(target_id, lineno, html);
585
585
586 }catch(e){
586 }catch(e){
587 console.log(e);
587 console.log(e);
588 }
588 }
589 }
589 }
590
590
591 /**
591 /**
592 * Iterates over all the inlines, and places them inside proper blocks of data
592 * Iterates over all the inlines, and places them inside proper blocks of data
593 */
593 */
594 var renderInlineComments = function(file_comments){
594 var renderInlineComments = function(file_comments){
595 for (f in file_comments){
595 for (f in file_comments){
596 // holding all comments for a FILE
596 // holding all comments for a FILE
597 var box = file_comments[f];
597 var box = file_comments[f];
598
598
599 var target_id = YUD.getAttribute(box,'target_id');
599 var target_id = YUD.getAttribute(box,'target_id');
600 // actually comments with line numbers
600 // actually comments with line numbers
601 var comments = box.children;
601 var comments = box.children;
602 for(var i=0; i<comments.length; i++){
602 for(var i=0; i<comments.length; i++){
603 var data = {
603 var data = {
604 'rendered_text': comments[i].outerHTML,
604 'rendered_text': comments[i].outerHTML,
605 'line_no': YUD.getAttribute(comments[i],'line'),
605 'line_no': YUD.getAttribute(comments[i],'line'),
606 'target_id': target_id
606 'target_id': target_id
607 }
607 }
608 renderInlineComment(data);
608 renderInlineComment(data);
609 }
609 }
610 }
610 }
611 }
611 }
612
612
613
613
614 var fileBrowserListeners = function(current_url, node_list_url, url_base,
614 var fileBrowserListeners = function(current_url, node_list_url, url_base){
615 truncated_lbl, nomatch_lbl){
615
616 var current_url_branch = +"?branch=__BRANCH__";
616 var current_url_branch = +"?branch=__BRANCH__";
617 var url = url_base;
617 var url = url_base;
618 var node_url = node_list_url;
618 var node_url = node_list_url;
619
619
620 YUE.on('stay_at_branch','click',function(e){
620 YUE.on('stay_at_branch','click',function(e){
621 if(e.target.checked){
621 if(e.target.checked){
622 var uri = current_url_branch;
622 var uri = current_url_branch;
623 uri = uri.replace('__BRANCH__',e.target.value);
623 uri = uri.replace('__BRANCH__',e.target.value);
624 window.location = uri;
624 window.location = uri;
625 }
625 }
626 else{
626 else{
627 window.location = current_url;
627 window.location = current_url;
628 }
628 }
629 })
629 })
630
630
631 var n_filter = YUD.get('node_filter');
631 var n_filter = YUD.get('node_filter');
632 var F = YAHOO.namespace('node_filter');
632 var F = YAHOO.namespace('node_filter');
633
633
634 F.filterTimeout = null;
634 F.filterTimeout = null;
635 var nodes = null;
635 var nodes = null;
636
636
637 F.initFilter = function(){
637 F.initFilter = function(){
638 YUD.setStyle('node_filter_box_loading','display','');
638 YUD.setStyle('node_filter_box_loading','display','');
639 YUD.setStyle('search_activate_id','display','none');
639 YUD.setStyle('search_activate_id','display','none');
640 YUD.setStyle('add_node_id','display','none');
640 YUD.setStyle('add_node_id','display','none');
641 YUC.initHeader('X-PARTIAL-XHR',true);
641 YUC.initHeader('X-PARTIAL-XHR',true);
642 YUC.asyncRequest('GET',url,{
642 YUC.asyncRequest('GET',url,{
643 success:function(o){
643 success:function(o){
644 nodes = JSON.parse(o.responseText);
644 nodes = JSON.parse(o.responseText).nodes;
645 YUD.setStyle('node_filter_box_loading','display','none');
645 YUD.setStyle('node_filter_box_loading','display','none');
646 YUD.setStyle('node_filter_box','display','');
646 YUD.setStyle('node_filter_box','display','');
647 n_filter.focus();
647 n_filter.focus();
648 if(YUD.hasClass(n_filter,'init')){
648 if(YUD.hasClass(n_filter,'init')){
649 n_filter.value = '';
649 n_filter.value = '';
650 YUD.removeClass(n_filter,'init');
650 YUD.removeClass(n_filter,'init');
651 }
651 }
652 },
652 },
653 failure:function(o){
653 failure:function(o){
654 console.log('failed to load');
654 console.log('failed to load');
655 }
655 }
656 },null);
656 },null);
657 }
657 }
658
658
659 F.updateFilter = function(e) {
659 F.updateFilter = function(e) {
660
660
661 return function(){
661 return function(){
662 // Reset timeout
662 // Reset timeout
663 F.filterTimeout = null;
663 F.filterTimeout = null;
664 var query = e.target.value.toLowerCase();
664 var query = e.target.value.toLowerCase();
665 var match = [];
665 var match = [];
666 var matches = 0;
666 var matches = 0;
667 var matches_max = 20;
667 var matches_max = 20;
668 if (query != ""){
668 if (query != ""){
669 for(var i=0;i<nodes.length;i++){
669 for(var i=0;i<nodes.length;i++){
670
670
671 var pos = nodes[i].name.toLowerCase().indexOf(query)
671 var pos = nodes[i].name.toLowerCase().indexOf(query)
672 if(query && pos != -1){
672 if(query && pos != -1){
673
673
674 matches++
674 matches++
675 //show only certain amount to not kill browser
675 //show only certain amount to not kill browser
676 if (matches > matches_max){
676 if (matches > matches_max){
677 break;
677 break;
678 }
678 }
679
679
680 var n = nodes[i].name;
680 var n = nodes[i].name;
681 var t = nodes[i].type;
681 var t = nodes[i].type;
682 var n_hl = n.substring(0,pos)
682 var n_hl = n.substring(0,pos)
683 +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
683 +"<b>{0}</b>".format(n.substring(pos,pos+query.length))
684 +n.substring(pos+query.length)
684 +n.substring(pos+query.length)
685 match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,node_url.replace('__FPATH__',n),n_hl));
685 match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,node_url.replace('__FPATH__',n),n_hl));
686 }
686 }
687 if(match.length >= matches_max){
687 if(match.length >= matches_max){
688 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(truncated_lbl));
688 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['search truncated']));
689 }
689 }
690
691 }
690 }
692 }
691 }
693 if(query != ""){
692 if(query != ""){
694 YUD.setStyle('tbody','display','none');
693 YUD.setStyle('tbody','display','none');
695 YUD.setStyle('tbody_filtered','display','');
694 YUD.setStyle('tbody_filtered','display','');
696
695
697 if (match.length==0){
696 if (match.length==0){
698 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(nomatch_lbl));
697 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['no matching files']));
699 }
698 }
700
699
701 YUD.get('tbody_filtered').innerHTML = match.join("");
700 YUD.get('tbody_filtered').innerHTML = match.join("");
702 }
701 }
703 else{
702 else{
704 YUD.setStyle('tbody','display','');
703 YUD.setStyle('tbody','display','');
705 YUD.setStyle('tbody_filtered','display','none');
704 YUD.setStyle('tbody_filtered','display','none');
706 }
705 }
707
706
708 }
707 }
709 };
708 };
710
709
711 YUE.on(YUD.get('filter_activate'),'click',function(){
710 YUE.on(YUD.get('filter_activate'),'click',function(){
712 F.initFilter();
711 F.initFilter();
713 })
712 })
714 YUE.on(n_filter,'click',function(){
713 YUE.on(n_filter,'click',function(){
715 if(YUD.hasClass(n_filter,'init')){
714 if(YUD.hasClass(n_filter,'init')){
716 n_filter.value = '';
715 n_filter.value = '';
717 YUD.removeClass(n_filter,'init');
716 YUD.removeClass(n_filter,'init');
718 }
717 }
719 });
718 });
720 YUE.on(n_filter,'keyup',function(e){
719 YUE.on(n_filter,'keyup',function(e){
721 clearTimeout(F.filterTimeout);
720 clearTimeout(F.filterTimeout);
722 F.filterTimeout = setTimeout(F.updateFilter(e),600);
721 F.filterTimeout = setTimeout(F.updateFilter(e),600);
723 });
722 });
724 };
723 };
725
724
726
725
727 var initCodeMirror = function(textAreadId,resetUrl){
726 var initCodeMirror = function(textAreadId,resetUrl){
728 var myCodeMirror = CodeMirror.fromTextArea(YUD.get(textAreadId),{
727 var myCodeMirror = CodeMirror.fromTextArea(YUD.get(textAreadId),{
729 mode: "null",
728 mode: "null",
730 lineNumbers:true
729 lineNumbers:true
731 });
730 });
732 YUE.on('reset','click',function(e){
731 YUE.on('reset','click',function(e){
733 window.location=resetUrl
732 window.location=resetUrl
734 });
733 });
735
734
736 YUE.on('file_enable','click',function(){
735 YUE.on('file_enable','click',function(){
737 YUD.setStyle('editor_container','display','');
736 YUD.setStyle('editor_container','display','');
738 YUD.setStyle('upload_file_container','display','none');
737 YUD.setStyle('upload_file_container','display','none');
739 YUD.setStyle('filename_container','display','');
738 YUD.setStyle('filename_container','display','');
740 });
739 });
741
740
742 YUE.on('upload_file_enable','click',function(){
741 YUE.on('upload_file_enable','click',function(){
743 YUD.setStyle('editor_container','display','none');
742 YUD.setStyle('editor_container','display','none');
744 YUD.setStyle('upload_file_container','display','');
743 YUD.setStyle('upload_file_container','display','');
745 YUD.setStyle('filename_container','display','none');
744 YUD.setStyle('filename_container','display','none');
746 });
745 });
747 };
746 };
748
747
749
748
750
749
751 var getIdentNode = function(n){
750 var getIdentNode = function(n){
752 //iterate thru nodes untill matched interesting node !
751 //iterate thru nodes untill matched interesting node !
753
752
754 if (typeof n == 'undefined'){
753 if (typeof n == 'undefined'){
755 return -1
754 return -1
756 }
755 }
757
756
758 if(typeof n.id != "undefined" && n.id.match('L[0-9]+')){
757 if(typeof n.id != "undefined" && n.id.match('L[0-9]+')){
759 return n
758 return n
760 }
759 }
761 else{
760 else{
762 return getIdentNode(n.parentNode);
761 return getIdentNode(n.parentNode);
763 }
762 }
764 };
763 };
765
764
766 var getSelectionLink = function(selection_link_label) {
765 var getSelectionLink = function(selection_link_label) {
767 return function(){
766 return function(){
768 //get selection from start/to nodes
767 //get selection from start/to nodes
769 if (typeof window.getSelection != "undefined") {
768 if (typeof window.getSelection != "undefined") {
770 s = window.getSelection();
769 s = window.getSelection();
771
770
772 from = getIdentNode(s.anchorNode);
771 from = getIdentNode(s.anchorNode);
773 till = getIdentNode(s.focusNode);
772 till = getIdentNode(s.focusNode);
774
773
775 f_int = parseInt(from.id.replace('L',''));
774 f_int = parseInt(from.id.replace('L',''));
776 t_int = parseInt(till.id.replace('L',''));
775 t_int = parseInt(till.id.replace('L',''));
777
776
778 if (f_int > t_int){
777 if (f_int > t_int){
779 //highlight from bottom
778 //highlight from bottom
780 offset = -35;
779 offset = -35;
781 ranges = [t_int,f_int];
780 ranges = [t_int,f_int];
782
781
783 }
782 }
784 else{
783 else{
785 //highligth from top
784 //highligth from top
786 offset = 35;
785 offset = 35;
787 ranges = [f_int,t_int];
786 ranges = [f_int,t_int];
788 }
787 }
789
788
790 if (ranges[0] != ranges[1]){
789 if (ranges[0] != ranges[1]){
791 if(YUD.get('linktt') == null){
790 if(YUD.get('linktt') == null){
792 hl_div = document.createElement('div');
791 hl_div = document.createElement('div');
793 hl_div.id = 'linktt';
792 hl_div.id = 'linktt';
794 }
793 }
795 anchor = '#L'+ranges[0]+'-'+ranges[1];
794 anchor = '#L'+ranges[0]+'-'+ranges[1];
796 hl_div.innerHTML = '';
795 hl_div.innerHTML = '';
797 l = document.createElement('a');
796 l = document.createElement('a');
798 l.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
797 l.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
799 l.innerHTML = selection_link_label;
798 l.innerHTML = selection_link_label;
800 hl_div.appendChild(l);
799 hl_div.appendChild(l);
801
800
802 YUD.get('body').appendChild(hl_div);
801 YUD.get('body').appendChild(hl_div);
803
802
804 xy = YUD.getXY(till.id);
803 xy = YUD.getXY(till.id);
805
804
806 YUD.addClass('linktt','yui-tt');
805 YUD.addClass('linktt','yui-tt');
807 YUD.setStyle('linktt','top',xy[1]+offset+'px');
806 YUD.setStyle('linktt','top',xy[1]+offset+'px');
808 YUD.setStyle('linktt','left',xy[0]+'px');
807 YUD.setStyle('linktt','left',xy[0]+'px');
809 YUD.setStyle('linktt','visibility','visible');
808 YUD.setStyle('linktt','visibility','visible');
810 }
809 }
811 else{
810 else{
812 YUD.setStyle('linktt','visibility','hidden');
811 YUD.setStyle('linktt','visibility','hidden');
813 }
812 }
814 }
813 }
815 }
814 }
816 };
815 };
817
816
818 var deleteNotification = function(url, notification_id,callbacks){
817 var deleteNotification = function(url, notification_id,callbacks){
819 var callback = {
818 var callback = {
820 success:function(o){
819 success:function(o){
821 var obj = YUD.get(String("notification_"+notification_id));
820 var obj = YUD.get(String("notification_"+notification_id));
822 if(obj.parentNode !== undefined){
821 if(obj.parentNode !== undefined){
823 obj.parentNode.removeChild(obj);
822 obj.parentNode.removeChild(obj);
824 }
823 }
825 _run_callbacks(callbacks);
824 _run_callbacks(callbacks);
826 },
825 },
827 failure:function(o){
826 failure:function(o){
828 alert("error");
827 alert("error");
829 },
828 },
830 };
829 };
831 var postData = '_method=delete';
830 var postData = '_method=delete';
832 var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
831 var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
833 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl,
832 var request = YAHOO.util.Connect.asyncRequest('POST', sUrl,
834 callback, postData);
833 callback, postData);
835 };
834 };
836
835
837
836
838 /** MEMBERS AUTOCOMPLETE WIDGET **/
837 /** MEMBERS AUTOCOMPLETE WIDGET **/
839
838
840 var MembersAutoComplete = function (users_list, groups_list) {
839 var MembersAutoComplete = function (users_list, groups_list) {
841 var myUsers = users_list;
840 var myUsers = users_list;
842 var myGroups = groups_list;
841 var myGroups = groups_list;
843
842
844 // Define a custom search function for the DataSource of users
843 // Define a custom search function for the DataSource of users
845 var matchUsers = function (sQuery) {
844 var matchUsers = function (sQuery) {
846 // Case insensitive matching
845 // Case insensitive matching
847 var query = sQuery.toLowerCase();
846 var query = sQuery.toLowerCase();
848 var i = 0;
847 var i = 0;
849 var l = myUsers.length;
848 var l = myUsers.length;
850 var matches = [];
849 var matches = [];
851
850
852 // Match against each name of each contact
851 // Match against each name of each contact
853 for (; i < l; i++) {
852 for (; i < l; i++) {
854 contact = myUsers[i];
853 contact = myUsers[i];
855 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
854 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
856 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
855 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
857 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
856 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
858 matches[matches.length] = contact;
857 matches[matches.length] = contact;
859 }
858 }
860 }
859 }
861 return matches;
860 return matches;
862 };
861 };
863
862
864 // Define a custom search function for the DataSource of usersGroups
863 // Define a custom search function for the DataSource of usersGroups
865 var matchGroups = function (sQuery) {
864 var matchGroups = function (sQuery) {
866 // Case insensitive matching
865 // Case insensitive matching
867 var query = sQuery.toLowerCase();
866 var query = sQuery.toLowerCase();
868 var i = 0;
867 var i = 0;
869 var l = myGroups.length;
868 var l = myGroups.length;
870 var matches = [];
869 var matches = [];
871
870
872 // Match against each name of each contact
871 // Match against each name of each contact
873 for (; i < l; i++) {
872 for (; i < l; i++) {
874 matched_group = myGroups[i];
873 matched_group = myGroups[i];
875 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
874 if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
876 matches[matches.length] = matched_group;
875 matches[matches.length] = matched_group;
877 }
876 }
878 }
877 }
879 return matches;
878 return matches;
880 };
879 };
881
880
882 //match all
881 //match all
883 var matchAll = function (sQuery) {
882 var matchAll = function (sQuery) {
884 u = matchUsers(sQuery);
883 u = matchUsers(sQuery);
885 g = matchGroups(sQuery);
884 g = matchGroups(sQuery);
886 return u.concat(g);
885 return u.concat(g);
887 };
886 };
888
887
889 // DataScheme for members
888 // DataScheme for members
890 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
889 var memberDS = new YAHOO.util.FunctionDataSource(matchAll);
891 memberDS.responseSchema = {
890 memberDS.responseSchema = {
892 fields: ["id", "fname", "lname", "nname", "grname", "grmembers", "gravatar_lnk"]
891 fields: ["id", "fname", "lname", "nname", "grname", "grmembers", "gravatar_lnk"]
893 };
892 };
894
893
895 // DataScheme for owner
894 // DataScheme for owner
896 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
895 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
897 ownerDS.responseSchema = {
896 ownerDS.responseSchema = {
898 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
897 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
899 };
898 };
900
899
901 // Instantiate AutoComplete for perms
900 // Instantiate AutoComplete for perms
902 var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
901 var membersAC = new YAHOO.widget.AutoComplete("perm_new_member_name", "perm_container", memberDS);
903 membersAC.useShadow = false;
902 membersAC.useShadow = false;
904 membersAC.resultTypeList = false;
903 membersAC.resultTypeList = false;
905
904
906 // Instantiate AutoComplete for owner
905 // Instantiate AutoComplete for owner
907 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
906 var ownerAC = new YAHOO.widget.AutoComplete("user", "owner_container", ownerDS);
908 ownerAC.useShadow = false;
907 ownerAC.useShadow = false;
909 ownerAC.resultTypeList = false;
908 ownerAC.resultTypeList = false;
910
909
911
910
912 // Helper highlight function for the formatter
911 // Helper highlight function for the formatter
913 var highlightMatch = function (full, snippet, matchindex) {
912 var highlightMatch = function (full, snippet, matchindex) {
914 return full.substring(0, matchindex)
913 return full.substring(0, matchindex)
915 + "<span class='match'>"
914 + "<span class='match'>"
916 + full.substr(matchindex, snippet.length)
915 + full.substr(matchindex, snippet.length)
917 + "</span>" + full.substring(matchindex + snippet.length);
916 + "</span>" + full.substring(matchindex + snippet.length);
918 };
917 };
919
918
920 // Custom formatter to highlight the matching letters
919 // Custom formatter to highlight the matching letters
921 var custom_formatter = function (oResultData, sQuery, sResultMatch) {
920 var custom_formatter = function (oResultData, sQuery, sResultMatch) {
922 var query = sQuery.toLowerCase();
921 var query = sQuery.toLowerCase();
923 var _gravatar = function(res, em, group){
922 var _gravatar = function(res, em, group){
924 if (group !== undefined){
923 if (group !== undefined){
925 em = '/images/icons/group.png'
924 em = '/images/icons/group.png'
926 }
925 }
927 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
926 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
928 return tmpl.format(em,res)
927 return tmpl.format(em,res)
929 }
928 }
930 // group
929 // group
931 if (oResultData.grname != undefined) {
930 if (oResultData.grname != undefined) {
932 var grname = oResultData.grname;
931 var grname = oResultData.grname;
933 var grmembers = oResultData.grmembers;
932 var grmembers = oResultData.grmembers;
934 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
933 var grnameMatchIndex = grname.toLowerCase().indexOf(query);
935 var grprefix = "{0}: ".format(_TM['Group']);
934 var grprefix = "{0}: ".format(_TM['Group']);
936 var grsuffix = " (" + grmembers + " )";
935 var grsuffix = " (" + grmembers + " )";
937 var grsuffix = " ({0} {1})".format(grmembers, _TM['members']);
936 var grsuffix = " ({0} {1})".format(grmembers, _TM['members']);
938
937
939 if (grnameMatchIndex > -1) {
938 if (grnameMatchIndex > -1) {
940 return _gravatar(grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix,null,true);
939 return _gravatar(grprefix + highlightMatch(grname, query, grnameMatchIndex) + grsuffix,null,true);
941 }
940 }
942 return _gravatar(grprefix + oResultData.grname + grsuffix, null,true);
941 return _gravatar(grprefix + oResultData.grname + grsuffix, null,true);
943 // Users
942 // Users
944 } else if (oResultData.nname != undefined) {
943 } else if (oResultData.nname != undefined) {
945 var fname = oResultData.fname || "";
944 var fname = oResultData.fname || "";
946 var lname = oResultData.lname || "";
945 var lname = oResultData.lname || "";
947 var nname = oResultData.nname;
946 var nname = oResultData.nname;
948
947
949 // Guard against null value
948 // Guard against null value
950 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
949 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
951 lnameMatchIndex = lname.toLowerCase().indexOf(query),
950 lnameMatchIndex = lname.toLowerCase().indexOf(query),
952 nnameMatchIndex = nname.toLowerCase().indexOf(query),
951 nnameMatchIndex = nname.toLowerCase().indexOf(query),
953 displayfname, displaylname, displaynname;
952 displayfname, displaylname, displaynname;
954
953
955 if (fnameMatchIndex > -1) {
954 if (fnameMatchIndex > -1) {
956 displayfname = highlightMatch(fname, query, fnameMatchIndex);
955 displayfname = highlightMatch(fname, query, fnameMatchIndex);
957 } else {
956 } else {
958 displayfname = fname;
957 displayfname = fname;
959 }
958 }
960
959
961 if (lnameMatchIndex > -1) {
960 if (lnameMatchIndex > -1) {
962 displaylname = highlightMatch(lname, query, lnameMatchIndex);
961 displaylname = highlightMatch(lname, query, lnameMatchIndex);
963 } else {
962 } else {
964 displaylname = lname;
963 displaylname = lname;
965 }
964 }
966
965
967 if (nnameMatchIndex > -1) {
966 if (nnameMatchIndex > -1) {
968 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
967 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
969 } else {
968 } else {
970 displaynname = nname ? "(" + nname + ")" : "";
969 displaynname = nname ? "(" + nname + ")" : "";
971 }
970 }
972
971
973 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
972 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
974 } else {
973 } else {
975 return '';
974 return '';
976 }
975 }
977 };
976 };
978 membersAC.formatResult = custom_formatter;
977 membersAC.formatResult = custom_formatter;
979 ownerAC.formatResult = custom_formatter;
978 ownerAC.formatResult = custom_formatter;
980
979
981 var myHandler = function (sType, aArgs) {
980 var myHandler = function (sType, aArgs) {
982
981
983 var myAC = aArgs[0]; // reference back to the AC instance
982 var myAC = aArgs[0]; // reference back to the AC instance
984 var elLI = aArgs[1]; // reference to the selected LI element
983 var elLI = aArgs[1]; // reference to the selected LI element
985 var oData = aArgs[2]; // object literal of selected item's result data
984 var oData = aArgs[2]; // object literal of selected item's result data
986 //fill the autocomplete with value
985 //fill the autocomplete with value
987 if (oData.nname != undefined) {
986 if (oData.nname != undefined) {
988 //users
987 //users
989 myAC.getInputEl().value = oData.nname;
988 myAC.getInputEl().value = oData.nname;
990 YUD.get('perm_new_member_type').value = 'user';
989 YUD.get('perm_new_member_type').value = 'user';
991 } else {
990 } else {
992 //groups
991 //groups
993 myAC.getInputEl().value = oData.grname;
992 myAC.getInputEl().value = oData.grname;
994 YUD.get('perm_new_member_type').value = 'users_group';
993 YUD.get('perm_new_member_type').value = 'users_group';
995 }
994 }
996 };
995 };
997
996
998 membersAC.itemSelectEvent.subscribe(myHandler);
997 membersAC.itemSelectEvent.subscribe(myHandler);
999 if(ownerAC.itemSelectEvent){
998 if(ownerAC.itemSelectEvent){
1000 ownerAC.itemSelectEvent.subscribe(myHandler);
999 ownerAC.itemSelectEvent.subscribe(myHandler);
1001 }
1000 }
1002
1001
1003 return {
1002 return {
1004 memberDS: memberDS,
1003 memberDS: memberDS,
1005 ownerDS: ownerDS,
1004 ownerDS: ownerDS,
1006 membersAC: membersAC,
1005 membersAC: membersAC,
1007 ownerAC: ownerAC,
1006 ownerAC: ownerAC,
1008 };
1007 };
1009 }
1008 }
1010
1009
1011
1010
1012 var MentionsAutoComplete = function (divid, cont, users_list, groups_list) {
1011 var MentionsAutoComplete = function (divid, cont, users_list, groups_list) {
1013 var myUsers = users_list;
1012 var myUsers = users_list;
1014 var myGroups = groups_list;
1013 var myGroups = groups_list;
1015
1014
1016 // Define a custom search function for the DataSource of users
1015 // Define a custom search function for the DataSource of users
1017 var matchUsers = function (sQuery) {
1016 var matchUsers = function (sQuery) {
1018 var org_sQuery = sQuery;
1017 var org_sQuery = sQuery;
1019 if(this.mentionQuery == null){
1018 if(this.mentionQuery == null){
1020 return []
1019 return []
1021 }
1020 }
1022 sQuery = this.mentionQuery;
1021 sQuery = this.mentionQuery;
1023 // Case insensitive matching
1022 // Case insensitive matching
1024 var query = sQuery.toLowerCase();
1023 var query = sQuery.toLowerCase();
1025 var i = 0;
1024 var i = 0;
1026 var l = myUsers.length;
1025 var l = myUsers.length;
1027 var matches = [];
1026 var matches = [];
1028
1027
1029 // Match against each name of each contact
1028 // Match against each name of each contact
1030 for (; i < l; i++) {
1029 for (; i < l; i++) {
1031 contact = myUsers[i];
1030 contact = myUsers[i];
1032 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1031 if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
1033 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1032 ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
1034 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1033 ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
1035 matches[matches.length] = contact;
1034 matches[matches.length] = contact;
1036 }
1035 }
1037 }
1036 }
1038 return matches
1037 return matches
1039 };
1038 };
1040
1039
1041 //match all
1040 //match all
1042 var matchAll = function (sQuery) {
1041 var matchAll = function (sQuery) {
1043 u = matchUsers(sQuery);
1042 u = matchUsers(sQuery);
1044 return u
1043 return u
1045 };
1044 };
1046
1045
1047 // DataScheme for owner
1046 // DataScheme for owner
1048 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1047 var ownerDS = new YAHOO.util.FunctionDataSource(matchUsers);
1049
1048
1050 ownerDS.responseSchema = {
1049 ownerDS.responseSchema = {
1051 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1050 fields: ["id", "fname", "lname", "nname", "gravatar_lnk"]
1052 };
1051 };
1053
1052
1054 // Instantiate AutoComplete for mentions
1053 // Instantiate AutoComplete for mentions
1055 var ownerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
1054 var ownerAC = new YAHOO.widget.AutoComplete(divid, cont, ownerDS);
1056 ownerAC.useShadow = false;
1055 ownerAC.useShadow = false;
1057 ownerAC.resultTypeList = false;
1056 ownerAC.resultTypeList = false;
1058 ownerAC.suppressInputUpdate = true;
1057 ownerAC.suppressInputUpdate = true;
1059
1058
1060 // Helper highlight function for the formatter
1059 // Helper highlight function for the formatter
1061 var highlightMatch = function (full, snippet, matchindex) {
1060 var highlightMatch = function (full, snippet, matchindex) {
1062 return full.substring(0, matchindex)
1061 return full.substring(0, matchindex)
1063 + "<span class='match'>"
1062 + "<span class='match'>"
1064 + full.substr(matchindex, snippet.length)
1063 + full.substr(matchindex, snippet.length)
1065 + "</span>" + full.substring(matchindex + snippet.length);
1064 + "</span>" + full.substring(matchindex + snippet.length);
1066 };
1065 };
1067
1066
1068 // Custom formatter to highlight the matching letters
1067 // Custom formatter to highlight the matching letters
1069 ownerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
1068 ownerAC.formatResult = function (oResultData, sQuery, sResultMatch) {
1070 var org_sQuery = sQuery;
1069 var org_sQuery = sQuery;
1071 if(this.dataSource.mentionQuery != null){
1070 if(this.dataSource.mentionQuery != null){
1072 sQuery = this.dataSource.mentionQuery;
1071 sQuery = this.dataSource.mentionQuery;
1073 }
1072 }
1074
1073
1075 var query = sQuery.toLowerCase();
1074 var query = sQuery.toLowerCase();
1076 var _gravatar = function(res, em, group){
1075 var _gravatar = function(res, em, group){
1077 if (group !== undefined){
1076 if (group !== undefined){
1078 em = '/images/icons/group.png'
1077 em = '/images/icons/group.png'
1079 }
1078 }
1080 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1079 tmpl = '<div class="ac-container-wrap"><img class="perm-gravatar-ac" src="{0}"/>{1}</div>'
1081 return tmpl.format(em,res)
1080 return tmpl.format(em,res)
1082 }
1081 }
1083 if (oResultData.nname != undefined) {
1082 if (oResultData.nname != undefined) {
1084 var fname = oResultData.fname || "";
1083 var fname = oResultData.fname || "";
1085 var lname = oResultData.lname || "";
1084 var lname = oResultData.lname || "";
1086 var nname = oResultData.nname;
1085 var nname = oResultData.nname;
1087
1086
1088 // Guard against null value
1087 // Guard against null value
1089 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1088 var fnameMatchIndex = fname.toLowerCase().indexOf(query),
1090 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1089 lnameMatchIndex = lname.toLowerCase().indexOf(query),
1091 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1090 nnameMatchIndex = nname.toLowerCase().indexOf(query),
1092 displayfname, displaylname, displaynname;
1091 displayfname, displaylname, displaynname;
1093
1092
1094 if (fnameMatchIndex > -1) {
1093 if (fnameMatchIndex > -1) {
1095 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1094 displayfname = highlightMatch(fname, query, fnameMatchIndex);
1096 } else {
1095 } else {
1097 displayfname = fname;
1096 displayfname = fname;
1098 }
1097 }
1099
1098
1100 if (lnameMatchIndex > -1) {
1099 if (lnameMatchIndex > -1) {
1101 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1100 displaylname = highlightMatch(lname, query, lnameMatchIndex);
1102 } else {
1101 } else {
1103 displaylname = lname;
1102 displaylname = lname;
1104 }
1103 }
1105
1104
1106 if (nnameMatchIndex > -1) {
1105 if (nnameMatchIndex > -1) {
1107 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1106 displaynname = "(" + highlightMatch(nname, query, nnameMatchIndex) + ")";
1108 } else {
1107 } else {
1109 displaynname = nname ? "(" + nname + ")" : "";
1108 displaynname = nname ? "(" + nname + ")" : "";
1110 }
1109 }
1111
1110
1112 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1111 return _gravatar(displayfname + " " + displaylname + " " + displaynname, oResultData.gravatar_lnk);
1113 } else {
1112 } else {
1114 return '';
1113 return '';
1115 }
1114 }
1116 };
1115 };
1117
1116
1118 if(ownerAC.itemSelectEvent){
1117 if(ownerAC.itemSelectEvent){
1119 ownerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
1118 ownerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
1120
1119
1121 var myAC = aArgs[0]; // reference back to the AC instance
1120 var myAC = aArgs[0]; // reference back to the AC instance
1122 var elLI = aArgs[1]; // reference to the selected LI element
1121 var elLI = aArgs[1]; // reference to the selected LI element
1123 var oData = aArgs[2]; // object literal of selected item's result data
1122 var oData = aArgs[2]; // object literal of selected item's result data
1124 //fill the autocomplete with value
1123 //fill the autocomplete with value
1125 if (oData.nname != undefined) {
1124 if (oData.nname != undefined) {
1126 //users
1125 //users
1127 //Replace the mention name with replaced
1126 //Replace the mention name with replaced
1128 var re = new RegExp();
1127 var re = new RegExp();
1129 var org = myAC.getInputEl().value;
1128 var org = myAC.getInputEl().value;
1130 var chunks = myAC.dataSource.chunks
1129 var chunks = myAC.dataSource.chunks
1131 // replace middle chunk(the search term) with actuall match
1130 // replace middle chunk(the search term) with actuall match
1132 chunks[1] = chunks[1].replace('@'+myAC.dataSource.mentionQuery,
1131 chunks[1] = chunks[1].replace('@'+myAC.dataSource.mentionQuery,
1133 '@'+oData.nname+' ');
1132 '@'+oData.nname+' ');
1134 myAC.getInputEl().value = chunks.join('')
1133 myAC.getInputEl().value = chunks.join('')
1135 YUD.get(myAC.getInputEl()).focus(); // Y U NO WORK !?
1134 YUD.get(myAC.getInputEl()).focus(); // Y U NO WORK !?
1136 } else {
1135 } else {
1137 //groups
1136 //groups
1138 myAC.getInputEl().value = oData.grname;
1137 myAC.getInputEl().value = oData.grname;
1139 YUD.get('perm_new_member_type').value = 'users_group';
1138 YUD.get('perm_new_member_type').value = 'users_group';
1140 }
1139 }
1141 });
1140 });
1142 }
1141 }
1143
1142
1144 // in this keybuffer we will gather current value of search !
1143 // in this keybuffer we will gather current value of search !
1145 // since we need to get this just when someone does `@` then we do the
1144 // since we need to get this just when someone does `@` then we do the
1146 // search
1145 // search
1147 ownerAC.dataSource.chunks = [];
1146 ownerAC.dataSource.chunks = [];
1148 ownerAC.dataSource.mentionQuery = null;
1147 ownerAC.dataSource.mentionQuery = null;
1149
1148
1150 ownerAC.get_mention = function(msg, max_pos) {
1149 ownerAC.get_mention = function(msg, max_pos) {
1151 var org = msg;
1150 var org = msg;
1152 var re = new RegExp('(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)$')
1151 var re = new RegExp('(?:^@|\s@)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+)$')
1153 var chunks = [];
1152 var chunks = [];
1154
1153
1155
1154
1156 // cut first chunk until curret pos
1155 // cut first chunk until curret pos
1157 var to_max = msg.substr(0, max_pos);
1156 var to_max = msg.substr(0, max_pos);
1158 var at_pos = Math.max(0,to_max.lastIndexOf('@')-1);
1157 var at_pos = Math.max(0,to_max.lastIndexOf('@')-1);
1159 var msg2 = to_max.substr(at_pos);
1158 var msg2 = to_max.substr(at_pos);
1160
1159
1161 chunks.push(org.substr(0,at_pos))// prefix chunk
1160 chunks.push(org.substr(0,at_pos))// prefix chunk
1162 chunks.push(msg2) // search chunk
1161 chunks.push(msg2) // search chunk
1163 chunks.push(org.substr(max_pos)) // postfix chunk
1162 chunks.push(org.substr(max_pos)) // postfix chunk
1164
1163
1165 // clean up msg2 for filtering and regex match
1164 // clean up msg2 for filtering and regex match
1166 var msg2 = msg2.lstrip(' ').lstrip('\n');
1165 var msg2 = msg2.lstrip(' ').lstrip('\n');
1167
1166
1168 if(re.test(msg2)){
1167 if(re.test(msg2)){
1169 var unam = re.exec(msg2)[1];
1168 var unam = re.exec(msg2)[1];
1170 return [unam, chunks];
1169 return [unam, chunks];
1171 }
1170 }
1172 return [null, null];
1171 return [null, null];
1173 };
1172 };
1174 ownerAC.textboxKeyUpEvent.subscribe(function(type, args){
1173 ownerAC.textboxKeyUpEvent.subscribe(function(type, args){
1175
1174
1176 var ac_obj = args[0];
1175 var ac_obj = args[0];
1177 var currentMessage = args[1];
1176 var currentMessage = args[1];
1178 var currentCaretPosition = args[0]._elTextbox.selectionStart;
1177 var currentCaretPosition = args[0]._elTextbox.selectionStart;
1179
1178
1180 var unam = ownerAC.get_mention(currentMessage, currentCaretPosition);
1179 var unam = ownerAC.get_mention(currentMessage, currentCaretPosition);
1181 var curr_search = null;
1180 var curr_search = null;
1182 if(unam[0]){
1181 if(unam[0]){
1183 curr_search = unam[0];
1182 curr_search = unam[0];
1184 }
1183 }
1185
1184
1186 ownerAC.dataSource.chunks = unam[1];
1185 ownerAC.dataSource.chunks = unam[1];
1187 ownerAC.dataSource.mentionQuery = curr_search;
1186 ownerAC.dataSource.mentionQuery = curr_search;
1188
1187
1189 })
1188 })
1190
1189
1191 return {
1190 return {
1192 ownerDS: ownerDS,
1191 ownerDS: ownerDS,
1193 ownerAC: ownerAC,
1192 ownerAC: ownerAC,
1194 };
1193 };
1195 }
1194 }
1196
1195
1197
1196
1198 /**
1197 /**
1199 * QUICK REPO MENU
1198 * QUICK REPO MENU
1200 */
1199 */
1201 var quick_repo_menu = function(){
1200 var quick_repo_menu = function(){
1202 YUE.on(YUQ('.quick_repo_menu'),'mouseenter',function(e){
1201 YUE.on(YUQ('.quick_repo_menu'),'mouseenter',function(e){
1203 var menu = e.currentTarget.firstElementChild.firstElementChild;
1202 var menu = e.currentTarget.firstElementChild.firstElementChild;
1204 if(YUD.hasClass(menu,'hidden')){
1203 if(YUD.hasClass(menu,'hidden')){
1205 YUD.replaceClass(e.currentTarget,'hidden', 'active');
1204 YUD.replaceClass(e.currentTarget,'hidden', 'active');
1206 YUD.replaceClass(menu, 'hidden', 'active');
1205 YUD.replaceClass(menu, 'hidden', 'active');
1207 }
1206 }
1208 })
1207 })
1209 YUE.on(YUQ('.quick_repo_menu'),'mouseleave',function(e){
1208 YUE.on(YUQ('.quick_repo_menu'),'mouseleave',function(e){
1210 var menu = e.currentTarget.firstElementChild.firstElementChild;
1209 var menu = e.currentTarget.firstElementChild.firstElementChild;
1211 if(YUD.hasClass(menu,'active')){
1210 if(YUD.hasClass(menu,'active')){
1212 YUD.replaceClass(e.currentTarget, 'active', 'hidden');
1211 YUD.replaceClass(e.currentTarget, 'active', 'hidden');
1213 YUD.replaceClass(menu, 'active', 'hidden');
1212 YUD.replaceClass(menu, 'active', 'hidden');
1214 }
1213 }
1215 })
1214 })
1216 };
1215 };
1217
1216
1218
1217
1219 /**
1218 /**
1220 * TABLE SORTING
1219 * TABLE SORTING
1221 */
1220 */
1222
1221
1223 // returns a node from given html;
1222 // returns a node from given html;
1224 var fromHTML = function(html){
1223 var fromHTML = function(html){
1225 var _html = document.createElement('element');
1224 var _html = document.createElement('element');
1226 _html.innerHTML = html;
1225 _html.innerHTML = html;
1227 return _html;
1226 return _html;
1228 }
1227 }
1229 var get_rev = function(node){
1228 var get_rev = function(node){
1230 var n = node.firstElementChild.firstElementChild;
1229 var n = node.firstElementChild.firstElementChild;
1231
1230
1232 if (n===null){
1231 if (n===null){
1233 return -1
1232 return -1
1234 }
1233 }
1235 else{
1234 else{
1236 out = n.firstElementChild.innerHTML.split(':')[0].replace('r','');
1235 out = n.firstElementChild.innerHTML.split(':')[0].replace('r','');
1237 return parseInt(out);
1236 return parseInt(out);
1238 }
1237 }
1239 }
1238 }
1240
1239
1241 var get_name = function(node){
1240 var get_name = function(node){
1242 var name = node.firstElementChild.children[2].innerHTML;
1241 var name = node.firstElementChild.children[2].innerHTML;
1243 return name
1242 return name
1244 }
1243 }
1245 var get_group_name = function(node){
1244 var get_group_name = function(node){
1246 var name = node.firstElementChild.children[1].innerHTML;
1245 var name = node.firstElementChild.children[1].innerHTML;
1247 return name
1246 return name
1248 }
1247 }
1249 var get_date = function(node){
1248 var get_date = function(node){
1250 var date_ = node.firstElementChild.innerHTML;
1249 var date_ = node.firstElementChild.innerHTML;
1251 return date_
1250 return date_
1252 }
1251 }
1253
1252
1254 var revisionSort = function(a, b, desc, field) {
1253 var revisionSort = function(a, b, desc, field) {
1255
1254
1256 var a_ = fromHTML(a.getData(field));
1255 var a_ = fromHTML(a.getData(field));
1257 var b_ = fromHTML(b.getData(field));
1256 var b_ = fromHTML(b.getData(field));
1258
1257
1259 // extract revisions from string nodes
1258 // extract revisions from string nodes
1260 a_ = get_rev(a_)
1259 a_ = get_rev(a_)
1261 b_ = get_rev(b_)
1260 b_ = get_rev(b_)
1262
1261
1263 var comp = YAHOO.util.Sort.compare;
1262 var comp = YAHOO.util.Sort.compare;
1264 var compState = comp(a_, b_, desc);
1263 var compState = comp(a_, b_, desc);
1265 return compState;
1264 return compState;
1266 };
1265 };
1267 var ageSort = function(a, b, desc, field) {
1266 var ageSort = function(a, b, desc, field) {
1268 var a_ = a.getData(field);
1267 var a_ = a.getData(field);
1269 var b_ = b.getData(field);
1268 var b_ = b.getData(field);
1270
1269
1271 var comp = YAHOO.util.Sort.compare;
1270 var comp = YAHOO.util.Sort.compare;
1272 var compState = comp(a_, b_, desc);
1271 var compState = comp(a_, b_, desc);
1273 return compState;
1272 return compState;
1274 };
1273 };
1275
1274
1276 var nameSort = function(a, b, desc, field) {
1275 var nameSort = function(a, b, desc, field) {
1277 var a_ = fromHTML(a.getData(field));
1276 var a_ = fromHTML(a.getData(field));
1278 var b_ = fromHTML(b.getData(field));
1277 var b_ = fromHTML(b.getData(field));
1279
1278
1280 // extract name from table
1279 // extract name from table
1281 a_ = get_name(a_)
1280 a_ = get_name(a_)
1282 b_ = get_name(b_)
1281 b_ = get_name(b_)
1283
1282
1284 var comp = YAHOO.util.Sort.compare;
1283 var comp = YAHOO.util.Sort.compare;
1285 var compState = comp(a_, b_, desc);
1284 var compState = comp(a_, b_, desc);
1286 return compState;
1285 return compState;
1287 };
1286 };
1288
1287
1289 var permNameSort = function(a, b, desc, field) {
1288 var permNameSort = function(a, b, desc, field) {
1290 var a_ = fromHTML(a.getData(field));
1289 var a_ = fromHTML(a.getData(field));
1291 var b_ = fromHTML(b.getData(field));
1290 var b_ = fromHTML(b.getData(field));
1292 // extract name from table
1291 // extract name from table
1293
1292
1294 a_ = a_.children[0].innerHTML;
1293 a_ = a_.children[0].innerHTML;
1295 b_ = b_.children[0].innerHTML;
1294 b_ = b_.children[0].innerHTML;
1296
1295
1297 var comp = YAHOO.util.Sort.compare;
1296 var comp = YAHOO.util.Sort.compare;
1298 var compState = comp(a_, b_, desc);
1297 var compState = comp(a_, b_, desc);
1299 return compState;
1298 return compState;
1300 };
1299 };
1301
1300
1302 var groupNameSort = function(a, b, desc, field) {
1301 var groupNameSort = function(a, b, desc, field) {
1303 var a_ = fromHTML(a.getData(field));
1302 var a_ = fromHTML(a.getData(field));
1304 var b_ = fromHTML(b.getData(field));
1303 var b_ = fromHTML(b.getData(field));
1305
1304
1306 // extract name from table
1305 // extract name from table
1307 a_ = get_group_name(a_)
1306 a_ = get_group_name(a_)
1308 b_ = get_group_name(b_)
1307 b_ = get_group_name(b_)
1309
1308
1310 var comp = YAHOO.util.Sort.compare;
1309 var comp = YAHOO.util.Sort.compare;
1311 var compState = comp(a_, b_, desc);
1310 var compState = comp(a_, b_, desc);
1312 return compState;
1311 return compState;
1313 };
1312 };
1314 var dateSort = function(a, b, desc, field) {
1313 var dateSort = function(a, b, desc, field) {
1315 var a_ = fromHTML(a.getData(field));
1314 var a_ = fromHTML(a.getData(field));
1316 var b_ = fromHTML(b.getData(field));
1315 var b_ = fromHTML(b.getData(field));
1317
1316
1318 // extract name from table
1317 // extract name from table
1319 a_ = get_date(a_)
1318 a_ = get_date(a_)
1320 b_ = get_date(b_)
1319 b_ = get_date(b_)
1321
1320
1322 var comp = YAHOO.util.Sort.compare;
1321 var comp = YAHOO.util.Sort.compare;
1323 var compState = comp(a_, b_, desc);
1322 var compState = comp(a_, b_, desc);
1324 return compState;
1323 return compState;
1325 }; No newline at end of file
1324 };
@@ -1,157 +1,159 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html>
2 <!DOCTYPE html>
3 <html xmlns="http://www.w3.org/1999/xhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml">
4 <head>
4 <head>
5 <title>${self.title()}</title>
5 <title>${self.title()}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta name="robots" content="index, nofollow"/>
7 <meta name="robots" content="index, nofollow"/>
8 <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
8 <link rel="icon" href="${h.url('/images/icons/database_gear.png')}" type="image/png" />
9
9
10 ## CSS ###
10 ## CSS ###
11 <%def name="css()">
11 <%def name="css()">
12 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen"/>
12 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen"/>
13 <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css')}"/>
13 <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css')}"/>
14 ## EXTRA FOR CSS
14 ## EXTRA FOR CSS
15 ${self.css_extra()}
15 ${self.css_extra()}
16 </%def>
16 </%def>
17 <%def name="css_extra()">
17 <%def name="css_extra()">
18 </%def>
18 </%def>
19
19
20 ${self.css()}
20 ${self.css()}
21
21
22 %if c.ga_code:
22 %if c.ga_code:
23 <!-- Analytics -->
23 <!-- Analytics -->
24 <script type="text/javascript">
24 <script type="text/javascript">
25 var _gaq = _gaq || [];
25 var _gaq = _gaq || [];
26 _gaq.push(['_setAccount', '${c.ga_code}']);
26 _gaq.push(['_setAccount', '${c.ga_code}']);
27 _gaq.push(['_trackPageview']);
27 _gaq.push(['_trackPageview']);
28
28
29 (function() {
29 (function() {
30 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
30 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
31 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
31 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
32 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
32 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
33 })();
33 })();
34 </script>
34 </script>
35 %endif
35 %endif
36
36
37 ## JAVASCRIPT ##
37 ## JAVASCRIPT ##
38 <%def name="js()">
38 <%def name="js()">
39 <script type="text/javascript">
39 <script type="text/javascript">
40 //JS translations map
40 //JS translations map
41 var TRANSLATION_MAP = {
41 var TRANSLATION_MAP = {
42 'add another comment':'${_("add another comment")}',
42 'add another comment':'${_("add another comment")}',
43 'Stop following this repository':"${_('Stop following this repository')}",
43 'Stop following this repository':"${_('Stop following this repository')}",
44 'Start following this repository':"${_('Start following this repository')}",
44 'Start following this repository':"${_('Start following this repository')}",
45 'Group':"${_('Group')}",
45 'Group':"${_('Group')}",
46 'members':"${_('members')}"
46 'members':"${_('members')}",
47 'search truncated': "${_('search truncated')}",
48 'no matching files': "${_('no matching files')}"
47
49
48 };
50 };
49 var _TM = TRANSLATION_MAP;
51 var _TM = TRANSLATION_MAP;
50 </script>
52 </script>
51 <script type="text/javascript" src="${h.url('/js/yui.2.9.js')}"></script>
53 <script type="text/javascript" src="${h.url('/js/yui.2.9.js')}"></script>
52 <!--[if lt IE 9]>
54 <!--[if lt IE 9]>
53 <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
55 <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
54 <![endif]-->
56 <![endif]-->
55 <script type="text/javascript" src="${h.url('/js/yui.flot.js')}"></script>
57 <script type="text/javascript" src="${h.url('/js/yui.flot.js')}"></script>
56 <script type="text/javascript" src="${h.url('/js/rhodecode.js')}"></script>
58 <script type="text/javascript" src="${h.url('/js/rhodecode.js')}"></script>
57 ## EXTRA FOR JS
59 ## EXTRA FOR JS
58 ${self.js_extra()}
60 ${self.js_extra()}
59
61
60 <script type="text/javascript">
62 <script type="text/javascript">
61 var follow_base_url = "${h.url('toggle_following')}";
63 var follow_base_url = "${h.url('toggle_following')}";
62
64
63 var onSuccessFollow = function(target){
65 var onSuccessFollow = function(target){
64 var f = YUD.get(target.id);
66 var f = YUD.get(target.id);
65 var f_cnt = YUD.get('current_followers_count');
67 var f_cnt = YUD.get('current_followers_count');
66
68
67 if(f.getAttribute('class')=='follow'){
69 if(f.getAttribute('class')=='follow'){
68 f.setAttribute('class','following');
70 f.setAttribute('class','following');
69 f.setAttribute('title',_TM['Stop following this repository']);
71 f.setAttribute('title',_TM['Stop following this repository']);
70
72
71 if(f_cnt){
73 if(f_cnt){
72 var cnt = Number(f_cnt.innerHTML)+1;
74 var cnt = Number(f_cnt.innerHTML)+1;
73 f_cnt.innerHTML = cnt;
75 f_cnt.innerHTML = cnt;
74 }
76 }
75 }
77 }
76 else{
78 else{
77 f.setAttribute('class','follow');
79 f.setAttribute('class','follow');
78 f.setAttribute('title',_TM['Start following this repository']);
80 f.setAttribute('title',_TM['Start following this repository']);
79 if(f_cnt){
81 if(f_cnt){
80 var cnt = Number(f_cnt.innerHTML)+1;
82 var cnt = Number(f_cnt.innerHTML)+1;
81 f_cnt.innerHTML = cnt;
83 f_cnt.innerHTML = cnt;
82 }
84 }
83 }
85 }
84 }
86 }
85
87
86 var toggleFollowingUser = function(target,fallows_user_id,token,user_id){
88 var toggleFollowingUser = function(target,fallows_user_id,token,user_id){
87 args = 'follows_user_id='+fallows_user_id;
89 args = 'follows_user_id='+fallows_user_id;
88 args+= '&amp;auth_token='+token;
90 args+= '&amp;auth_token='+token;
89 if(user_id != undefined){
91 if(user_id != undefined){
90 args+="&amp;user_id="+user_id;
92 args+="&amp;user_id="+user_id;
91 }
93 }
92 YUC.asyncRequest('POST',follow_base_url,{
94 YUC.asyncRequest('POST',follow_base_url,{
93 success:function(o){
95 success:function(o){
94 onSuccessFollow(target);
96 onSuccessFollow(target);
95 }
97 }
96 },args);
98 },args);
97 return false;
99 return false;
98 }
100 }
99
101
100 var toggleFollowingRepo = function(target,fallows_repo_id,token,user_id){
102 var toggleFollowingRepo = function(target,fallows_repo_id,token,user_id){
101
103
102 args = 'follows_repo_id='+fallows_repo_id;
104 args = 'follows_repo_id='+fallows_repo_id;
103 args+= '&amp;auth_token='+token;
105 args+= '&amp;auth_token='+token;
104 if(user_id != undefined){
106 if(user_id != undefined){
105 args+="&amp;user_id="+user_id;
107 args+="&amp;user_id="+user_id;
106 }
108 }
107 YUC.asyncRequest('POST',follow_base_url,{
109 YUC.asyncRequest('POST',follow_base_url,{
108 success:function(o){
110 success:function(o){
109 onSuccessFollow(target);
111 onSuccessFollow(target);
110 }
112 }
111 },args);
113 },args);
112 return false;
114 return false;
113 }
115 }
114 YUE.onDOMReady(function(){
116 YUE.onDOMReady(function(){
115 tooltip_activate();
117 tooltip_activate();
116 show_more_event();
118 show_more_event();
117
119
118 YUE.on('quick_login_link','click',function(e){
120 YUE.on('quick_login_link','click',function(e){
119 // make sure we don't redirect
121 // make sure we don't redirect
120 YUE.preventDefault(e);
122 YUE.preventDefault(e);
121
123
122 if(YUD.hasClass('quick_login_link','enabled')){
124 if(YUD.hasClass('quick_login_link','enabled')){
123 YUD.setStyle('quick_login','display','none');
125 YUD.setStyle('quick_login','display','none');
124 YUD.removeClass('quick_login_link','enabled');
126 YUD.removeClass('quick_login_link','enabled');
125 }
127 }
126 else{
128 else{
127 YUD.setStyle('quick_login','display','');
129 YUD.setStyle('quick_login','display','');
128 YUD.addClass('quick_login_link','enabled');
130 YUD.addClass('quick_login_link','enabled');
129 var usr = YUD.get('username');
131 var usr = YUD.get('username');
130 if(usr){
132 if(usr){
131 usr.focus();
133 usr.focus();
132 }
134 }
133 }
135 }
134 });
136 });
135 })
137 })
136 </script>
138 </script>
137 </%def>
139 </%def>
138 <%def name="js_extra()"></%def>
140 <%def name="js_extra()"></%def>
139 ${self.js()}
141 ${self.js()}
140 <%def name="head_extra()"></%def>
142 <%def name="head_extra()"></%def>
141 ${self.head_extra()}
143 ${self.head_extra()}
142 </head>
144 </head>
143 <body id="body">
145 <body id="body">
144 ## IE hacks
146 ## IE hacks
145 <!--[if IE 7]>
147 <!--[if IE 7]>
146 <script>YUD.addClass(document.body,'ie7')</script>
148 <script>YUD.addClass(document.body,'ie7')</script>
147 <![endif]-->
149 <![endif]-->
148 <!--[if IE 8]>
150 <!--[if IE 8]>
149 <script>YUD.addClass(document.body,'ie8')</script>
151 <script>YUD.addClass(document.body,'ie8')</script>
150 <![endif]-->
152 <![endif]-->
151 <!--[if IE 9]>
153 <!--[if IE 9]>
152 <script>YUD.addClass(document.body,'ie9')</script>
154 <script>YUD.addClass(document.body,'ie9')</script>
153 <![endif]-->
155 <![endif]-->
154
156
155 ${next.body()}
157 ${next.body()}
156 </body>
158 </body>
157 </html>
159 </html>
@@ -1,48 +1,46 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 <script type="text/javascript">
39 <script type="text/javascript">
40 var YPJAX_TITLE = "${c.repo_name} ${_('Files')} - ${c.rhodecode_name}";
40 var YPJAX_TITLE = "${c.repo_name} ${_('Files')} - ${c.rhodecode_name}";
41 var current_url = "${h.url.current()}";
41 var current_url = "${h.url.current()}";
42 var node_list_url = '${h.url("files_home",repo_name=c.repo_name,revision=c.changeset.raw_id,f_path='__FPATH__')}';
42 var node_list_url = '${h.url("files_home",repo_name=c.repo_name,revision=c.changeset.raw_id,f_path='__FPATH__')}';
43 var url_base = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.file.path)}';
43 var url_base = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.file.path)}';
44 var truncated_lbl = "${_('search truncated')}";
44 fileBrowserListeners(current_url, node_list_url, url_base);
45 var nomatch_lbl = "${_('no matching files')}";
46 fileBrowserListeners(current_url, node_list_url, url_base, truncated_lbl, nomatch_lbl);
47 </script>
45 </script>
48 </%def>
46 </%def>
General Comments 0
You need to be logged in to leave comments. Login now