##// END OF EJS Templates
fixed some unicode problems with git file path
marcink -
r3792:63adb3d5 beta
parent child Browse files
Show More
@@ -1,551 +1,554 b''
1 1 import re
2 2 from itertools import chain
3 3 from dulwich import objects
4 4 from subprocess import Popen, PIPE
5 5 import rhodecode
6 6 from rhodecode.lib.vcs.conf import settings
7 7 from rhodecode.lib.vcs.exceptions import RepositoryError
8 8 from rhodecode.lib.vcs.exceptions import ChangesetError
9 9 from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError
10 10 from rhodecode.lib.vcs.exceptions import VCSError
11 11 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
12 12 from rhodecode.lib.vcs.exceptions import ImproperArchiveTypeError
13 13 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
14 14 from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, \
15 15 RemovedFileNode, SubModuleNode, ChangedFileNodesGenerator,\
16 16 AddedFileNodesGenerator, RemovedFileNodesGenerator
17 17 from rhodecode.lib.vcs.utils import safe_unicode
18 18 from rhodecode.lib.vcs.utils import date_fromtimestamp
19 19 from rhodecode.lib.vcs.utils.lazy import LazyProperty
20 from rhodecode.lib.utils2 import safe_int
20 from rhodecode.lib.utils2 import safe_int, safe_str
21 21
22 22
23 23 class GitChangeset(BaseChangeset):
24 24 """
25 25 Represents state of the repository at single revision.
26 26 """
27 27
28 28 def __init__(self, repository, revision):
29 29 self._stat_modes = {}
30 30 self.repository = repository
31 31
32 32 try:
33 33 commit = self.repository._repo.get_object(revision)
34 34 if isinstance(commit, objects.Tag):
35 35 revision = commit.object[1]
36 36 commit = self.repository._repo.get_object(commit.object[1])
37 37 except KeyError:
38 38 raise RepositoryError("Cannot get object with id %s" % revision)
39 39 self.raw_id = revision
40 40 self.id = self.raw_id
41 41 self.short_id = self.raw_id[:12]
42 42 self._commit = commit
43 43
44 44 self._tree_id = commit.tree
45 45 self._committer_property = 'committer'
46 46 self._author_property = 'author'
47 47 self._date_property = 'commit_time'
48 48 self._date_tz_property = 'commit_timezone'
49 49 self.revision = repository.revisions.index(revision)
50 50
51 51 self.message = safe_unicode(commit.message)
52 52
53 53 self.nodes = {}
54 54 self._paths = {}
55 55
56 56 @LazyProperty
57 57 def committer(self):
58 58 return safe_unicode(getattr(self._commit, self._committer_property))
59 59
60 60 @LazyProperty
61 61 def author(self):
62 62 return safe_unicode(getattr(self._commit, self._author_property))
63 63
64 64 @LazyProperty
65 65 def date(self):
66 66 return date_fromtimestamp(getattr(self._commit, self._date_property),
67 67 getattr(self._commit, self._date_tz_property))
68 68
69 69 @LazyProperty
70 70 def _timestamp(self):
71 71 return getattr(self._commit, self._date_property)
72 72
73 73 @LazyProperty
74 74 def status(self):
75 75 """
76 76 Returns modified, added, removed, deleted files for current changeset
77 77 """
78 78 return self.changed, self.added, self.removed
79 79
80 80 @LazyProperty
81 81 def tags(self):
82 82 _tags = []
83 83 for tname, tsha in self.repository.tags.iteritems():
84 84 if tsha == self.raw_id:
85 85 _tags.append(tname)
86 86 return _tags
87 87
88 88 @LazyProperty
89 89 def branch(self):
90 90
91 91 heads = self.repository._heads(reverse=False)
92 92
93 93 ref = heads.get(self.raw_id)
94 94 if ref:
95 95 return safe_unicode(ref)
96 96
97 97 def _fix_path(self, path):
98 98 """
99 99 Paths are stored without trailing slash so we need to get rid off it if
100 100 needed.
101 101 """
102 102 if path.endswith('/'):
103 103 path = path.rstrip('/')
104 104 return path
105 105
106 106 def _get_id_for_path(self, path):
107 107
108 108 # FIXME: Please, spare a couple of minutes and make those codes cleaner;
109 109 if not path in self._paths:
110 110 path = path.strip('/')
111 111 # set root tree
112 112 tree = self.repository._repo[self._tree_id]
113 113 if path == '':
114 114 self._paths[''] = tree.id
115 115 return tree.id
116 116 splitted = path.split('/')
117 117 dirs, name = splitted[:-1], splitted[-1]
118 118 curdir = ''
119 119
120 120 # initially extract things from root dir
121 121 for item, stat, id in tree.iteritems():
122 122 if curdir:
123 123 name = '/'.join((curdir, item))
124 124 else:
125 125 name = item
126 126 self._paths[name] = id
127 127 self._stat_modes[name] = stat
128 128
129 129 for dir in dirs:
130 130 if curdir:
131 131 curdir = '/'.join((curdir, dir))
132 132 else:
133 133 curdir = dir
134 134 dir_id = None
135 135 for item, stat, id in tree.iteritems():
136 136 if dir == item:
137 137 dir_id = id
138 138 if dir_id:
139 139 # Update tree
140 140 tree = self.repository._repo[dir_id]
141 141 if not isinstance(tree, objects.Tree):
142 142 raise ChangesetError('%s is not a directory' % curdir)
143 143 else:
144 144 raise ChangesetError('%s have not been found' % curdir)
145 145
146 146 # cache all items from the given traversed tree
147 147 for item, stat, id in tree.iteritems():
148 148 if curdir:
149 149 name = '/'.join((curdir, item))
150 150 else:
151 151 name = item
152 152 self._paths[name] = id
153 153 self._stat_modes[name] = stat
154 154 if not path in self._paths:
155 155 raise NodeDoesNotExistError("There is no file nor directory "
156 156 "at the given path '%s' at revision %s"
157 157 % (path, self.short_id))
158 158 return self._paths[path]
159 159
160 160 def _get_kind(self, path):
161 161 obj = self.repository._repo[self._get_id_for_path(path)]
162 162 if isinstance(obj, objects.Blob):
163 163 return NodeKind.FILE
164 164 elif isinstance(obj, objects.Tree):
165 165 return NodeKind.DIR
166 166
167 167 def _get_filectx(self, path):
168 168 path = self._fix_path(path)
169 169 if self._get_kind(path) != NodeKind.FILE:
170 170 raise ChangesetError("File does not exist for revision %s at "
171 171 " '%s'" % (self.raw_id, path))
172 172 return path
173 173
174 174 def _get_file_nodes(self):
175 175 return chain(*(t[2] for t in self.walk()))
176 176
177 177 @LazyProperty
178 178 def parents(self):
179 179 """
180 180 Returns list of parents changesets.
181 181 """
182 182 return [self.repository.get_changeset(parent)
183 183 for parent in self._commit.parents]
184 184
185 185 @LazyProperty
186 186 def children(self):
187 187 """
188 188 Returns list of children changesets.
189 189 """
190 190 rev_filter = _git_path = rhodecode.CONFIG.get('git_rev_filter',
191 191 '--all').strip()
192 192 so, se = self.repository.run_git_command(
193 193 "rev-list %s --children | grep '^%s'" % (rev_filter, self.raw_id)
194 194 )
195 195
196 196 children = []
197 197 for l in so.splitlines():
198 198 childs = l.split(' ')[1:]
199 199 children.extend(childs)
200 200 return [self.repository.get_changeset(cs) for cs in children]
201 201
202 202 def next(self, branch=None):
203 203
204 204 if branch and self.branch != branch:
205 205 raise VCSError('Branch option used on changeset not belonging '
206 206 'to that branch')
207 207
208 208 def _next(changeset, branch):
209 209 try:
210 210 next_ = changeset.revision + 1
211 211 next_rev = changeset.repository.revisions[next_]
212 212 except IndexError:
213 213 raise ChangesetDoesNotExistError
214 214 cs = changeset.repository.get_changeset(next_rev)
215 215
216 216 if branch and branch != cs.branch:
217 217 return _next(cs, branch)
218 218
219 219 return cs
220 220
221 221 return _next(self, branch)
222 222
223 223 def prev(self, branch=None):
224 224 if branch and self.branch != branch:
225 225 raise VCSError('Branch option used on changeset not belonging '
226 226 'to that branch')
227 227
228 228 def _prev(changeset, branch):
229 229 try:
230 230 prev_ = changeset.revision - 1
231 231 if prev_ < 0:
232 232 raise IndexError
233 233 prev_rev = changeset.repository.revisions[prev_]
234 234 except IndexError:
235 235 raise ChangesetDoesNotExistError
236 236
237 237 cs = changeset.repository.get_changeset(prev_rev)
238 238
239 239 if branch and branch != cs.branch:
240 240 return _prev(cs, branch)
241 241
242 242 return cs
243 243
244 244 return _prev(self, branch)
245 245
246 246 def diff(self, ignore_whitespace=True, context=3):
247 247 rev1 = self.parents[0] if self.parents else self.repository.EMPTY_CHANGESET
248 248 rev2 = self
249 249 return ''.join(self.repository.get_diff(rev1, rev2,
250 250 ignore_whitespace=ignore_whitespace,
251 251 context=context))
252 252
253 253 def get_file_mode(self, path):
254 254 """
255 255 Returns stat mode of the file at the given ``path``.
256 256 """
257 257 # ensure path is traversed
258 258 self._get_id_for_path(path)
259 259 return self._stat_modes[path]
260 260
261 261 def get_file_content(self, path):
262 262 """
263 263 Returns content of the file at given ``path``.
264 264 """
265 265 id = self._get_id_for_path(path)
266 266 blob = self.repository._repo[id]
267 267 return blob.as_pretty_string()
268 268
269 269 def get_file_size(self, path):
270 270 """
271 271 Returns size of the file at given ``path``.
272 272 """
273 273 id = self._get_id_for_path(path)
274 274 blob = self.repository._repo[id]
275 275 return blob.raw_length()
276 276
277 277 def get_file_changeset(self, path):
278 278 """
279 279 Returns last commit of the file at the given ``path``.
280 280 """
281 281 return self.get_file_history(path, limit=1)[0]
282 282
283 283 def get_file_history(self, path, limit=None):
284 284 """
285 285 Returns history of file as reversed list of ``Changeset`` objects for
286 286 which file at given ``path`` has been modified.
287 287
288 288 TODO: This function now uses os underlying 'git' and 'grep' commands
289 289 which is generally not good. Should be replaced with algorithm
290 290 iterating commits.
291 291 """
292 self._get_filectx(path)
293 cs_id = safe_str(self.id)
294 f_path = safe_str(path)
292 295
293 self._get_filectx(path)
294 296 if limit:
295 297 cmd = 'log -n %s --pretty="format: %%H" -s -p %s -- "%s"' % (
296 safe_int(limit, 0), self.id, path
298 safe_int(limit, 0), cs_id, f_path
297 299 )
300
298 301 else:
299 302 cmd = 'log --pretty="format: %%H" -s -p %s -- "%s"' % (
300 self.id, path
303 cs_id, f_path
301 304 )
302 305 so, se = self.repository.run_git_command(cmd)
303 306 ids = re.findall(r'[0-9a-fA-F]{40}', so)
304 307 return [self.repository.get_changeset(id) for id in ids]
305 308
306 309 def get_file_history_2(self, path):
307 310 """
308 311 Returns history of file as reversed list of ``Changeset`` objects for
309 312 which file at given ``path`` has been modified.
310 313
311 314 """
312 315 self._get_filectx(path)
313 316 from dulwich.walk import Walker
314 317 include = [self.id]
315 318 walker = Walker(self.repository._repo.object_store, include,
316 319 paths=[path], max_entries=1)
317 320 return [self.repository.get_changeset(sha)
318 321 for sha in (x.commit.id for x in walker)]
319 322
320 323 def get_file_annotate(self, path):
321 324 """
322 325 Returns a generator of four element tuples with
323 326 lineno, sha, changeset lazy loader and line
324 327
325 328 TODO: This function now uses os underlying 'git' command which is
326 329 generally not good. Should be replaced with algorithm iterating
327 330 commits.
328 331 """
329 332 cmd = 'blame -l --root -r %s -- "%s"' % (self.id, path)
330 333 # -l ==> outputs long shas (and we need all 40 characters)
331 334 # --root ==> doesn't put '^' character for bounderies
332 335 # -r sha ==> blames for the given revision
333 336 so, se = self.repository.run_git_command(cmd)
334 337
335 338 for i, blame_line in enumerate(so.split('\n')[:-1]):
336 339 ln_no = i + 1
337 340 sha, line = re.split(r' ', blame_line, 1)
338 341 yield (ln_no, sha, lambda: self.repository.get_changeset(sha), line)
339 342
340 343 def fill_archive(self, stream=None, kind='tgz', prefix=None,
341 344 subrepos=False):
342 345 """
343 346 Fills up given stream.
344 347
345 348 :param stream: file like object.
346 349 :param kind: one of following: ``zip``, ``tgz`` or ``tbz2``.
347 350 Default: ``tgz``.
348 351 :param prefix: name of root directory in archive.
349 352 Default is repository name and changeset's raw_id joined with dash
350 353 (``repo-tip.<KIND>``).
351 354 :param subrepos: include subrepos in this archive.
352 355
353 356 :raise ImproperArchiveTypeError: If given kind is wrong.
354 357 :raise VcsError: If given stream is None
355 358
356 359 """
357 360 allowed_kinds = settings.ARCHIVE_SPECS.keys()
358 361 if kind not in allowed_kinds:
359 362 raise ImproperArchiveTypeError('Archive kind not supported use one'
360 363 'of %s', allowed_kinds)
361 364
362 365 if prefix is None:
363 366 prefix = '%s-%s' % (self.repository.name, self.short_id)
364 367 elif prefix.startswith('/'):
365 368 raise VCSError("Prefix cannot start with leading slash")
366 369 elif prefix.strip() == '':
367 370 raise VCSError("Prefix cannot be empty")
368 371
369 372 if kind == 'zip':
370 373 frmt = 'zip'
371 374 else:
372 375 frmt = 'tar'
373 376 _git_path = rhodecode.CONFIG.get('git_path', 'git')
374 377 cmd = '%s archive --format=%s --prefix=%s/ %s' % (_git_path,
375 378 frmt, prefix, self.raw_id)
376 379 if kind == 'tgz':
377 380 cmd += ' | gzip -9'
378 381 elif kind == 'tbz2':
379 382 cmd += ' | bzip2 -9'
380 383
381 384 if stream is None:
382 385 raise VCSError('You need to pass in a valid stream for filling'
383 386 ' with archival data')
384 387 popen = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True,
385 388 cwd=self.repository.path)
386 389
387 390 buffer_size = 1024 * 8
388 391 chunk = popen.stdout.read(buffer_size)
389 392 while chunk:
390 393 stream.write(chunk)
391 394 chunk = popen.stdout.read(buffer_size)
392 395 # Make sure all descriptors would be read
393 396 popen.communicate()
394 397
395 398 def get_nodes(self, path):
396 399 if self._get_kind(path) != NodeKind.DIR:
397 400 raise ChangesetError("Directory does not exist for revision %s at "
398 401 " '%s'" % (self.revision, path))
399 402 path = self._fix_path(path)
400 403 id = self._get_id_for_path(path)
401 404 tree = self.repository._repo[id]
402 405 dirnodes = []
403 406 filenodes = []
404 407 als = self.repository.alias
405 408 for name, stat, id in tree.iteritems():
406 409 if objects.S_ISGITLINK(stat):
407 410 dirnodes.append(SubModuleNode(name, url=None, changeset=id,
408 411 alias=als))
409 412 continue
410 413
411 414 obj = self.repository._repo.get_object(id)
412 415 if path != '':
413 416 obj_path = '/'.join((path, name))
414 417 else:
415 418 obj_path = name
416 419 if obj_path not in self._stat_modes:
417 420 self._stat_modes[obj_path] = stat
418 421 if isinstance(obj, objects.Tree):
419 422 dirnodes.append(DirNode(obj_path, changeset=self))
420 423 elif isinstance(obj, objects.Blob):
421 424 filenodes.append(FileNode(obj_path, changeset=self, mode=stat))
422 425 else:
423 426 raise ChangesetError("Requested object should be Tree "
424 427 "or Blob, is %r" % type(obj))
425 428 nodes = dirnodes + filenodes
426 429 for node in nodes:
427 430 if not node.path in self.nodes:
428 431 self.nodes[node.path] = node
429 432 nodes.sort()
430 433 return nodes
431 434
432 435 def get_node(self, path):
433 436 if isinstance(path, unicode):
434 437 path = path.encode('utf-8')
435 438 path = self._fix_path(path)
436 439 if not path in self.nodes:
437 440 try:
438 441 id_ = self._get_id_for_path(path)
439 442 except ChangesetError:
440 443 raise NodeDoesNotExistError("Cannot find one of parents' "
441 444 "directories for a given path: %s" % path)
442 445
443 446 _GL = lambda m: m and objects.S_ISGITLINK(m)
444 447 if _GL(self._stat_modes.get(path)):
445 448 node = SubModuleNode(path, url=None, changeset=id_,
446 449 alias=self.repository.alias)
447 450 else:
448 451 obj = self.repository._repo.get_object(id_)
449 452
450 453 if isinstance(obj, objects.Tree):
451 454 if path == '':
452 455 node = RootNode(changeset=self)
453 456 else:
454 457 node = DirNode(path, changeset=self)
455 458 node._tree = obj
456 459 elif isinstance(obj, objects.Blob):
457 460 node = FileNode(path, changeset=self)
458 461 node._blob = obj
459 462 else:
460 463 raise NodeDoesNotExistError("There is no file nor directory "
461 464 "at the given path '%s' at revision %s"
462 465 % (path, self.short_id))
463 466 # cache node
464 467 self.nodes[path] = node
465 468 return self.nodes[path]
466 469
467 470 @LazyProperty
468 471 def affected_files(self):
469 472 """
470 473 Get's a fast accessible file changes for given changeset
471 474 """
472 475 a, m, d = self._changes_cache
473 476 return list(a.union(m).union(d))
474 477
475 478 @LazyProperty
476 479 def _diff_name_status(self):
477 480 output = []
478 481 for parent in self.parents:
479 482 cmd = 'diff --name-status %s %s --encoding=utf8' % (parent.raw_id,
480 483 self.raw_id)
481 484 so, se = self.repository.run_git_command(cmd)
482 485 output.append(so.strip())
483 486 return '\n'.join(output)
484 487
485 488 @LazyProperty
486 489 def _changes_cache(self):
487 490 added = set()
488 491 modified = set()
489 492 deleted = set()
490 493 _r = self.repository._repo
491 494
492 495 parents = self.parents
493 496 if not self.parents:
494 497 parents = [EmptyChangeset()]
495 498 for parent in parents:
496 499 if isinstance(parent, EmptyChangeset):
497 500 oid = None
498 501 else:
499 502 oid = _r[parent.raw_id].tree
500 503 changes = _r.object_store.tree_changes(oid, _r[self.raw_id].tree)
501 504 for (oldpath, newpath), (_, _), (_, _) in changes:
502 505 if newpath and oldpath:
503 506 modified.add(newpath)
504 507 elif newpath and not oldpath:
505 508 added.add(newpath)
506 509 elif not newpath and oldpath:
507 510 deleted.add(oldpath)
508 511 return added, modified, deleted
509 512
510 513 def _get_paths_for_status(self, status):
511 514 """
512 515 Returns sorted list of paths for given ``status``.
513 516
514 517 :param status: one of: *added*, *modified* or *deleted*
515 518 """
516 519 a, m, d = self._changes_cache
517 520 return sorted({
518 521 'added': list(a),
519 522 'modified': list(m),
520 523 'deleted': list(d)}[status]
521 524 )
522 525
523 526 @LazyProperty
524 527 def added(self):
525 528 """
526 529 Returns list of added ``FileNode`` objects.
527 530 """
528 531 if not self.parents:
529 532 return list(self._get_file_nodes())
530 533 return AddedFileNodesGenerator([n for n in
531 534 self._get_paths_for_status('added')], self)
532 535
533 536 @LazyProperty
534 537 def changed(self):
535 538 """
536 539 Returns list of modified ``FileNode`` objects.
537 540 """
538 541 if not self.parents:
539 542 return []
540 543 return ChangedFileNodesGenerator([n for n in
541 544 self._get_paths_for_status('modified')], self)
542 545
543 546 @LazyProperty
544 547 def removed(self):
545 548 """
546 549 Returns list of removed ``FileNode`` objects.
547 550 """
548 551 if not self.parents:
549 552 return []
550 553 return RemovedFileNodesGenerator([n for n in
551 554 self._get_paths_for_status('deleted')], self)
@@ -1,163 +1,163 b''
1 1 <%inherit file="/base/base.html"/>
2 2
3 3 <%def name="title(*args)">
4 4 ${_('%s Files') % c.repo_name}
5 5 %if hasattr(c,'file'):
6 &middot; ${c.file.path or '\\'}
6 &middot; ${h.safe_unicode(c.file.path) or '\\'}
7 7 %endif
8 8 &middot; ${c.rhodecode_name}
9 9 </%def>
10 10
11 11 <%def name="breadcrumbs_links()">
12 12 ${_('Files')}
13 13 %if c.file:
14 14 @ ${h.show_id(c.changeset)}
15 15 %endif
16 16 </%def>
17 17
18 18 <%def name="page_nav()">
19 19 ${self.menu('repositories')}
20 20 </%def>
21 21
22 22 <%def name="main()">
23 23 ${self.context_bar('files')}
24 24 <div class="box">
25 25 <!-- box / title -->
26 26 <div class="title">
27 27 ${self.breadcrumbs()}
28 28 <ul class="links">
29 29 <li>
30 30 <span style="text-transform: uppercase;"><a href="#">${_('Branch')}: ${c.changeset.branch}</a></span>
31 31 </li>
32 32 </ul>
33 33 </div>
34 34 <div class="table">
35 35 <div id="files_data">
36 36 <%include file='files_ypjax.html'/>
37 37 </div>
38 38 </div>
39 39 </div>
40 40
41 41 <script type="text/javascript">
42 42 var CACHE = {};
43 43 var CACHE_EXPIRE = 5*60*1000; //cache for 5*60s
44 44 //used to construct links from the search list
45 45 var url_base = '${h.url("files_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
46 46 //send the nodelist request to this url
47 47 var node_list_url = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
48 48 // send the node history requst to this url
49 49 var node_history_url = '${h.url("files_history_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
50 50
51 51 var ypjax_links = function(){
52 52 YUE.on(YUQ('.ypjax-link'), 'click',function(e){
53 53
54 54 //don't do ypjax on middle click
55 55 if(e.which == 2 || !History.enabled){
56 56 return true;
57 57 }
58 58
59 59 var el = e.currentTarget;
60 60 var url = el.href;
61 61
62 62 var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}';
63 63 _base_url = _base_url.replace('//','/')
64 64
65 65 //extract rev and the f_path from url.
66 66 parts = url.split(_base_url)
67 67 if(parts.length != 2){
68 68 return false;
69 69 }
70 70
71 71 var parts2 = parts[1].split('/');
72 72 var rev = parts2.shift(); // pop the first element which is the revision
73 73 var f_path = parts2.join('/');
74 74
75 75 //page title make this consistent with title() mako function on top
76 76 var title = "${_('%s Files') % c.repo_name}" + " &middot; " + (f_path || '\\') + " &middot; " + "${c.rhodecode_name}";
77 77
78 78 var _node_list_url = node_list_url.replace('__REV__',rev).replace('__FPATH__', f_path);
79 79 var _url_base = url_base.replace('__REV__',rev);
80 80
81 81 // Change our States and save some data for handling events
82 82 var data = {url:url,title:title, url_base:_url_base,
83 83 node_list_url:_node_list_url, rev:rev, f_path:f_path};
84 84 History.pushState(data, title, url);
85 85
86 86 //now we're sure that we can do ypjax things
87 87 YUE.preventDefault(e);
88 88 return false;
89 89 });
90 90 }
91 91
92 92 var callbacks = function(State){
93 93 ypjax_links();
94 94 tooltip_activate();
95 95 fileBrowserListeners(State.url, State.data.node_list_url, State.data.url_base);
96 96
97 97 if(YUD.get('hlcode')){
98 98 YUE.on('hlcode', 'mouseup', getSelectionLink);
99 99 }
100 100 //console.log(State);
101 101 if(YUD.get('load_node_history')){
102 102 //remove all listeners due to problems of history state
103 103 YUE.removeListener('load_node_history', 'click');
104 104 YUE.on('load_node_history', 'click', function(e){
105 105 var _url = node_history_url.replace('__REV__',State.data.rev).replace('__FPATH__', State.data.f_path);
106 106 ypjax(_url, 'node_history', function(o){
107 107 tooltip_activate();
108 108 })
109 109 });
110 110 }
111 111 // Inform Google Analytics of the change
112 112 if ( typeof window.pageTracker !== 'undefined' ) {
113 113 window.pageTracker._trackPageview(State.url);
114 114 }
115 115 }
116 116
117 117 YUE.onDOMReady(function(){
118 118 ypjax_links();
119 119 var container = 'files_data';
120 120 //Bind to StateChange Event
121 121 History.Adapter.bind(window,'statechange',function(){
122 122 var State = History.getState();
123 123 cache_key = State.url;
124 124 //check if we have this request in cache maybe ?
125 125 var _cache_obj = CACHE[cache_key];
126 126 var _cur_time = new Date().getTime();
127 127 // get from cache if it's there and not yet expired !
128 128 if(_cache_obj !== undefined && _cache_obj[0] > _cur_time){
129 129 YUD.get(container).innerHTML=_cache_obj[1];
130 130 YUD.setStyle(container,'opacity','1.0');
131 131
132 132 //callbacks after ypjax call
133 133 callbacks(State);
134 134 }
135 135 else{
136 136 ypjax(State.url,container,function(o){
137 137 //callbacks after ypjax call
138 138 callbacks(State);
139 139 if (o !== undefined){
140 140 //store our request in cache
141 141 var _expire_on = new Date().getTime()+CACHE_EXPIRE;
142 142 CACHE[cache_key] = [_expire_on, o.responseText];
143 143 }
144 144 });
145 145 }
146 146 });
147 147
148 148 // init the search filter
149 149 var _State = {
150 150 url: "${h.url.current()}",
151 151 data: {
152 152 node_list_url: node_list_url.replace('__REV__',"${c.changeset.raw_id}").replace('__FPATH__', "${h.safe_unicode(c.file.path)}"),
153 153 url_base: url_base.replace('__REV__',"${c.changeset.raw_id}"),
154 154 rev:"${c.changeset.raw_id}",
155 155 f_path: "${h.safe_unicode(c.file.path)}"
156 156 }
157 157 }
158 158 fileBrowserListeners(_State.url, _State.data.node_list_url, _State.data.url_base);
159 159 });
160 160
161 161 </script>
162 162
163 163 </%def>
General Comments 0
You need to be logged in to leave comments. Login now