Merge lp:~mwhudson/loggerhead/ajaxy-revision-page into lp:loggerhead
- ajaxy-revision-page
- Merge into trunk-rich
Proposed by
Michael Hudson-Doyle
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~mwhudson/loggerhead/ajaxy-revision-page |
Merge into: | lp:loggerhead |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~mwhudson/loggerhead/ajaxy-revision-page |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paul Hummer (community) | Approve | ||
Review via email: mp+4569@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote : | # |
Revision history for this message
Paul Hummer (rockstar) wrote : | # |
This is very sexy!
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'loggerhead/apps/branch.py' |
2 | --- loggerhead/apps/branch.py 2009-03-13 05:36:26 +0000 |
3 | +++ loggerhead/apps/branch.py 2009-03-17 00:02:21 +0000 |
4 | @@ -11,15 +11,16 @@ |
5 | from paste import httpexceptions |
6 | |
7 | from loggerhead.apps import static_app |
8 | +from loggerhead.controllers.annotate_ui import AnnotateUI |
9 | +from loggerhead.controllers.atom_ui import AtomUI |
10 | from loggerhead.controllers.changelog_ui import ChangeLogUI |
11 | +from loggerhead.controllers.diff_ui import DiffUI |
12 | +from loggerhead.controllers.download_ui import DownloadUI |
13 | +from loggerhead.controllers.filediff_ui import FileDiffUI |
14 | from loggerhead.controllers.inventory_ui import InventoryUI |
15 | -from loggerhead.controllers.annotate_ui import AnnotateUI |
16 | from loggerhead.controllers.revision_ui import RevisionUI |
17 | from loggerhead.controllers.revlog_ui import RevLogUI |
18 | -from loggerhead.controllers.atom_ui import AtomUI |
19 | -from loggerhead.controllers.download_ui import DownloadUI |
20 | from loggerhead.controllers.search_ui import SearchUI |
21 | -from loggerhead.controllers.diff_ui import DiffUI |
22 | from loggerhead.history import History |
23 | from loggerhead import util |
24 | |
25 | @@ -79,15 +80,16 @@ |
26 | return self._static_url_base + path |
27 | |
28 | controllers_dict = { |
29 | + '+filediff': FileDiffUI, |
30 | + '+revlog': RevLogUI, |
31 | 'annotate': AnnotateUI, |
32 | + 'atom': AtomUI, |
33 | 'changes': ChangeLogUI, |
34 | + 'diff': DiffUI, |
35 | + 'download': DownloadUI, |
36 | 'files': InventoryUI, |
37 | 'revision': RevisionUI, |
38 | - '+revlog': RevLogUI, |
39 | - 'download': DownloadUI, |
40 | - 'atom': AtomUI, |
41 | 'search': SearchUI, |
42 | - 'diff': DiffUI, |
43 | } |
44 | |
45 | def last_updated(self): |
46 | |
47 | === added file 'loggerhead/controllers/filediff_ui.py' |
48 | --- loggerhead/controllers/filediff_ui.py 1970-01-01 00:00:00 +0000 |
49 | +++ loggerhead/controllers/filediff_ui.py 2009-03-17 06:43:34 +0000 |
50 | @@ -0,0 +1,97 @@ |
51 | +from StringIO import StringIO |
52 | +import urllib |
53 | + |
54 | +from bzrlib import diff |
55 | +from bzrlib import errors |
56 | + |
57 | +from loggerhead import util |
58 | +from loggerhead.controllers import TemplatedBranchView |
59 | + |
60 | +def _process_diff(difftext): |
61 | + chunks = [] |
62 | + chunk = None |
63 | + for line in difftext.splitlines(): |
64 | + if len(line) == 0: |
65 | + continue |
66 | + if line.startswith('+++ ') or line.startswith('--- '): |
67 | + continue |
68 | + if line.startswith('@@ '): |
69 | + # new chunk |
70 | + if chunk is not None: |
71 | + chunks.append(chunk) |
72 | + chunk = util.Container() |
73 | + chunk.diff = [] |
74 | + split_lines = line.split(' ')[1:3] |
75 | + lines = [int(x.split(',')[0][1:]) for x in split_lines] |
76 | + old_lineno = lines[0] |
77 | + new_lineno = lines[1] |
78 | + elif line.startswith(' '): |
79 | + chunk.diff.append(util.Container(old_lineno=old_lineno, |
80 | + new_lineno=new_lineno, |
81 | + type='context', |
82 | + line=line[1:])) |
83 | + old_lineno += 1 |
84 | + new_lineno += 1 |
85 | + elif line.startswith('+'): |
86 | + chunk.diff.append(util.Container(old_lineno=None, |
87 | + new_lineno=new_lineno, |
88 | + type='insert', line=line[1:])) |
89 | + new_lineno += 1 |
90 | + elif line.startswith('-'): |
91 | + chunk.diff.append(util.Container(old_lineno=old_lineno, |
92 | + new_lineno=None, |
93 | + type='delete', line=line[1:])) |
94 | + old_lineno += 1 |
95 | + else: |
96 | + chunk.diff.append(util.Container(old_lineno=None, |
97 | + new_lineno=None, |
98 | + type='unknown', |
99 | + line=repr(line))) |
100 | + if chunk is not None: |
101 | + chunks.append(chunk) |
102 | + return chunks |
103 | + |
104 | + |
105 | +def diff_chunks_for_file(file_id, old_tree, new_tree): |
106 | + try: |
107 | + old_lines = old_tree.get_file_lines(file_id) |
108 | + except errors.NoSuchId: |
109 | + old_lines = [] |
110 | + try: |
111 | + new_lines = new_tree.get_file_lines(file_id) |
112 | + except errors.NoSuchId: |
113 | + new_lines = [] |
114 | + buffer = StringIO() |
115 | + if old_lines != new_lines: |
116 | + try: |
117 | + diff.internal_diff('', old_lines, '', new_lines, buffer) |
118 | + except errors.BinaryFile: |
119 | + difftext = '' |
120 | + else: |
121 | + difftext = buffer.getvalue() |
122 | + else: |
123 | + difftext = '' |
124 | + |
125 | + return _process_diff(difftext) |
126 | + |
127 | + |
128 | +class FileDiffUI(TemplatedBranchView): |
129 | + |
130 | + template_path = 'loggerhead.templates.filediff' |
131 | + |
132 | + def get_values(self, path, kwargs, headers): |
133 | + history = self._history |
134 | + |
135 | + revid = urllib.unquote(self.args[0]) |
136 | + compare_revid = urllib.unquote(self.args[1]) |
137 | + file_id = urllib.unquote(self.args[2]) |
138 | + |
139 | + repository = self._history._branch.repository |
140 | + old_tree, new_tree = repository.revision_trees([compare_revid, revid]) |
141 | + |
142 | + chunks = diff_chunks_for_file(file_id, old_tree, new_tree) |
143 | + |
144 | + return { |
145 | + 'util': util, |
146 | + 'chunks': chunks, |
147 | + } |
148 | |
149 | === modified file 'loggerhead/controllers/revision_ui.py' |
150 | --- loggerhead/controllers/revision_ui.py 2009-03-17 02:19:20 +0000 |
151 | +++ loggerhead/controllers/revision_ui.py 2009-03-17 06:43:34 +0000 |
152 | @@ -17,70 +17,26 @@ |
153 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
154 | # |
155 | |
156 | -from StringIO import StringIO |
157 | - |
158 | -import bzrlib.diff |
159 | -from bzrlib import errors |
160 | +import simplejson |
161 | +import urllib |
162 | |
163 | from paste.httpexceptions import HTTPServerError |
164 | |
165 | from loggerhead import util |
166 | from loggerhead.controllers import TemplatedBranchView |
167 | +from loggerhead.controllers.filediff_ui import diff_chunks_for_file |
168 | from loggerhead.history import rich_filename |
169 | |
170 | |
171 | DEFAULT_LINE_COUNT_LIMIT = 3000 |
172 | |
173 | +def dq(p): |
174 | + return urllib.quote(urllib.quote(p, safe='')) |
175 | |
176 | class RevisionUI(TemplatedBranchView): |
177 | |
178 | template_path = 'loggerhead.templates.revision' |
179 | |
180 | - def _process_diff(self, diff): |
181 | - # doesn't really need to be a method; could be static. |
182 | - chunks = [] |
183 | - chunk = None |
184 | - for line in diff.splitlines(): |
185 | - if len(line) == 0: |
186 | - continue |
187 | - if line.startswith('+++ ') or line.startswith('--- '): |
188 | - continue |
189 | - if line.startswith('@@ '): |
190 | - # new chunk |
191 | - if chunk is not None: |
192 | - chunks.append(chunk) |
193 | - chunk = util.Container() |
194 | - chunk.diff = [] |
195 | - split_lines = line.split(' ')[1:3] |
196 | - lines = [int(x.split(',')[0][1:]) for x in split_lines] |
197 | - old_lineno = lines[0] |
198 | - new_lineno = lines[1] |
199 | - elif line.startswith(' '): |
200 | - chunk.diff.append(util.Container(old_lineno=old_lineno, |
201 | - new_lineno=new_lineno, |
202 | - type='context', |
203 | - line=line[1:])) |
204 | - old_lineno += 1 |
205 | - new_lineno += 1 |
206 | - elif line.startswith('+'): |
207 | - chunk.diff.append(util.Container(old_lineno=None, |
208 | - new_lineno=new_lineno, |
209 | - type='insert', line=line[1:])) |
210 | - new_lineno += 1 |
211 | - elif line.startswith('-'): |
212 | - chunk.diff.append(util.Container(old_lineno=old_lineno, |
213 | - new_lineno=None, |
214 | - type='delete', line=line[1:])) |
215 | - old_lineno += 1 |
216 | - else: |
217 | - chunk.diff.append(util.Container(old_lineno=None, |
218 | - new_lineno=None, |
219 | - type='unknown', |
220 | - line=repr(line))) |
221 | - if chunk is not None: |
222 | - chunks.append(chunk) |
223 | - return chunks |
224 | - |
225 | def _parse_diffs(self, old_tree, new_tree, delta, specific_path): |
226 | """ |
227 | Return a list of processed diffs, in the format:: |
228 | @@ -98,57 +54,36 @@ |
229 | ), |
230 | ) |
231 | """ |
232 | + if specific_path: |
233 | + fid = new_tree.path2id(specific_path) |
234 | + kind = new_tree.kind(fid) |
235 | + chunks=diff_chunks_for_file(fid, old_tree, new_tree) |
236 | + return [util.Container( |
237 | + filename=rich_filename(specific_path, kind), file_id=fid, |
238 | + chunks=chunks)] |
239 | + |
240 | process = [] |
241 | out = [] |
242 | |
243 | - def include_specific_path(path): |
244 | - return specific_path == path |
245 | - def include_all_paths(path): |
246 | - return True |
247 | - if specific_path: |
248 | - include_path = include_specific_path |
249 | - else: |
250 | - include_path = include_all_paths |
251 | - |
252 | for old_path, new_path, fid, \ |
253 | kind, text_modified, meta_modified in delta.renamed: |
254 | - if text_modified and include_path(new_path): |
255 | - process.append((old_path, new_path, fid, kind)) |
256 | + if text_modified: |
257 | + process.append((new_path, fid, kind)) |
258 | for path, fid, kind, text_modified, meta_modified in delta.modified: |
259 | - if include_path(path): |
260 | - process.append((path, path, fid, kind)) |
261 | + process.append((path, fid, kind)) |
262 | for path, fid, kind in delta.added: |
263 | - if kind == 'file' and include_path(path): |
264 | - process.append((path, path, fid, kind)) |
265 | + if kind == 'file': |
266 | + process.append((path, fid, kind)) |
267 | for path, fid, kind in delta.removed: |
268 | - if kind == 'file' and include_path(path): |
269 | - process.append((path, path, fid, kind)) |
270 | - |
271 | - process.sort(key=lambda x:x[1]) |
272 | - |
273 | - for old_path, new_path, fid, kind in process: |
274 | - try: |
275 | - old_lines = old_tree.get_file_lines(fid) |
276 | - except errors.NoSuchId: |
277 | - old_lines = [] |
278 | - try: |
279 | - new_lines = new_tree.get_file_lines(fid) |
280 | - except errors.NoSuchId: |
281 | - new_lines = [] |
282 | - buffer = StringIO() |
283 | - if old_lines != new_lines: |
284 | - try: |
285 | - bzrlib.diff.internal_diff(old_path, old_lines, |
286 | - new_path, new_lines, buffer) |
287 | - except bzrlib.errors.BinaryFile: |
288 | - diff = '' |
289 | - else: |
290 | - diff = buffer.getvalue() |
291 | - else: |
292 | - diff = '' |
293 | + if kind == 'file': |
294 | + process.append((path, fid, kind)) |
295 | + |
296 | + process.sort() |
297 | + |
298 | + for new_path, fid, kind in process: |
299 | out.append(util.Container( |
300 | filename=rich_filename(new_path, kind), file_id=fid, |
301 | - chunks=self._process_diff(diff))) |
302 | + chunks=[])) |
303 | |
304 | return out |
305 | |
306 | @@ -200,6 +135,20 @@ |
307 | if path in ('', '/'): |
308 | path = None |
309 | change.changes, diffs = self.get_changes_with_diff(change, compare_revid, path) |
310 | + link_data = {} |
311 | + path_to_id = {} |
312 | + if compare_revid is None: |
313 | + if change.parents: |
314 | + cr = change.parents[0].revid |
315 | + else: |
316 | + cr = 'null:' |
317 | + else: |
318 | + cr = compare_revid |
319 | + for i, item in enumerate(diffs): |
320 | + item.index = i |
321 | + link_data['diff-' + str(i)] = '%s/%s/%s' % ( |
322 | + dq(revid), dq(cr), dq(item.file_id)) |
323 | + path_to_id[item.filename] = 'diff-' + str(i) |
324 | # add parent & merge-point branch-nick info, in case it's useful |
325 | h.get_branch_nicks([change]) |
326 | |
327 | @@ -215,7 +164,10 @@ |
328 | 'revid': revid, |
329 | 'change': change, |
330 | 'diffs': diffs, |
331 | + 'link_data': simplejson.dumps(link_data), |
332 | 'specific_path': path, |
333 | + 'json_specific_path': simplejson.dumps(path), |
334 | + 'path_to_id': simplejson.dumps(path_to_id), |
335 | 'start_revid': start_revid, |
336 | 'filter_file_id': filter_file_id, |
337 | 'util': util, |
338 | |
339 | === modified file 'loggerhead/static/javascript/custom.js' |
340 | --- loggerhead/static/javascript/custom.js 2009-03-16 03:22:02 +0000 |
341 | +++ loggerhead/static/javascript/custom.js 2009-03-17 04:26:28 +0000 |
342 | @@ -86,6 +86,7 @@ |
343 | this.expand_icon = config.expand_icon; |
344 | this.source = config.source; |
345 | this.loading = config.loading; |
346 | + this.node_process = config.node_process; |
347 | } |
348 | |
349 | function get_height(node) { |
350 | @@ -99,17 +100,19 @@ |
351 | return height; |
352 | } |
353 | |
354 | -Collapsable.prototype._load_finished = function(tid, res) |
355 | +Collapsable.prototype._load_finished = function(tid, res, args) |
356 | { |
357 | var newNode = Y.Node.create(res.responseText.split('\n').splice(1).join('')); |
358 | + if (this.node_process) |
359 | + this.node_process(newNode); |
360 | this.source_target.ancestor().replaceChild(newNode, this.source_target); |
361 | this.source_target = null; |
362 | this.source = null; |
363 | this.loading.setStyle('display', 'none'); |
364 | - this.open(); |
365 | + this.open(args[0]); |
366 | }; |
367 | |
368 | -Collapsable.prototype.open = function() |
369 | +Collapsable.prototype.open = function(callback) |
370 | { |
371 | if (this.source) { |
372 | this.loading.setStyle('display', 'block'); |
373 | @@ -117,6 +120,7 @@ |
374 | this.source, |
375 | { |
376 | on: {complete: this._load_finished}, |
377 | + arguments: [callback], |
378 | context: this |
379 | }); |
380 | return; |
381 | @@ -146,7 +150,7 @@ |
382 | duration: 0.2 |
383 | }); |
384 | |
385 | - anim.on('end', this.openComplete, this); |
386 | + anim.on('end', this.openComplete, this, callback); |
387 | container.setStyle('marginBottom', close_height - open_height); |
388 | if (this.close_node) { |
389 | this.close_node.setStyle('display', 'none'); |
390 | @@ -156,8 +160,9 @@ |
391 | anim.run(); |
392 | }; |
393 | |
394 | -Collapsable.prototype.openComplete = function() |
395 | +Collapsable.prototype.openComplete = function(evt, callback) |
396 | { |
397 | + if (callback) callback(); |
398 | this.is_open = true; |
399 | }; |
400 | |
401 | |
402 | === modified file 'loggerhead/static/javascript/diff.js' |
403 | --- loggerhead/static/javascript/diff.js 2009-03-16 21:53:23 +0000 |
404 | +++ loggerhead/static/javascript/diff.js 2009-03-17 06:51:29 +0000 |
405 | @@ -87,13 +87,14 @@ |
406 | |
407 | function toggle_unified_sbs(event) { |
408 | event.preventDefault(); |
409 | + var pts = Y.all(".pseudotable"); |
410 | if (unified) { |
411 | - Y.all(".pseudotable").each(make_sbs); |
412 | + pts && pts.each(make_sbs); |
413 | unified = false; |
414 | Y.get("#toggle_unified_sbs").set('innerHTML', "Show unified diffs"); |
415 | } |
416 | else { |
417 | - Y.all(".pseudotable").each(make_unified); |
418 | + pts && pts.each(make_unified); |
419 | unified = true; |
420 | Y.get("#toggle_unified_sbs").set('innerHTML', "Show diffs side-by-side"); |
421 | } |
422 | @@ -103,7 +104,7 @@ |
423 | |
424 | function toggle_expand_all_revisionview(action) |
425 | { |
426 | - var diffs = Y.all('.diffBox'); |
427 | + var diffs = Y.all('.diff'); |
428 | if (diffs == null) return; |
429 | diffs.each( |
430 | function(item, i) |
431 | @@ -142,24 +143,61 @@ |
432 | '#collapse_all a' |
433 | ); |
434 | |
435 | +function node_process(node) { |
436 | + if (!unified) { |
437 | + node.get('children').filter('.pseudotable').each(make_sbs); |
438 | + } |
439 | +} |
440 | + |
441 | +function zoom_to_diff (path) { |
442 | + var collapsable = Y.get('#' + path_to_id[path]).collapsable; |
443 | + if (!collapsable.is_open) { |
444 | + collapsable.open( |
445 | + function () { |
446 | + window.location.hash = '#' + path; |
447 | + }); |
448 | + } |
449 | +} |
450 | + |
451 | Y.on( |
452 | "domready", function () { |
453 | Y.all(".show_if_js").removeClass("show_if_js"); |
454 | - var diffs = Y.all('.diffBox'); |
455 | + Y.all("#list-files a").on( |
456 | + 'click', |
457 | + function (e) { |
458 | + e.preventDefault(); |
459 | + var path = decodeURIComponent(e.target.get('href').split('#')[1]); |
460 | + window.location.hash = '#' + path; |
461 | + zoom_to_diff(path); |
462 | + }); |
463 | + var diffs = Y.all('.diff'); |
464 | if (diffs == null) return; |
465 | diffs.each( |
466 | function(item, i) |
467 | { |
468 | - item.query('.expand_diff').on('click', function() { collapsable.toggle(); }); |
469 | + var source_url = null; |
470 | + if (!specific_path) |
471 | + source_url = global_path + '+filediff/' + link_data[item.get('id')]; |
472 | + item.query('.the-link').on( |
473 | + 'click', |
474 | + function(e) { |
475 | + e.preventDefault(); |
476 | + collapsable.toggle(); |
477 | + }); |
478 | var collapsable = new Collapsable( |
479 | { |
480 | expand_icon: item.query('.expand_diff'), |
481 | - open_node: item.ancestor().query('.diffinfo'), |
482 | + open_node: item.query('.diffinfo'), |
483 | close_node: null, |
484 | - source: null, |
485 | - source_target: null, |
486 | - is_open: true |
487 | + source: source_url, |
488 | + source_target: item.query('.source_target'), |
489 | + is_open: specific_path != null, |
490 | + loading: item.query('.loading'), |
491 | + node_process: node_process |
492 | }); |
493 | item.collapsable=collapsable; |
494 | }); |
495 | + if (window.location.hash && !specific_path) { |
496 | + zoom_to_diff(window.location.hash.substring(1)); |
497 | + } |
498 | }); |
499 | |
500 | === modified file 'loggerhead/templatefunctions.py' |
501 | --- loggerhead/templatefunctions.py 2009-03-07 07:29:26 +0000 |
502 | +++ loggerhead/templatefunctions.py 2009-03-17 06:32:25 +0000 |
503 | @@ -38,20 +38,20 @@ |
504 | |
505 | |
506 | @templatefunc |
507 | -def file_change_summary(url, entry, link_style='normal', currently_showing=None): |
508 | - if link_style == 'fragment': |
509 | +def file_change_summary(url, entry, style='normal', currently_showing=None): |
510 | + if style == 'fragment': |
511 | def file_link(filename): |
512 | - if currently_showing: |
513 | - if filename == currently_showing: |
514 | - return '<b><a href="#%s">%s</a></b>' % ( |
515 | - cgi.escape(filename), cgi.escape(filename)) |
516 | - else: |
517 | - return revision_link(url, entry.revno, filename) |
518 | + if currently_showing and filename == currently_showing: |
519 | + return '<b><a href="#%s">%s</a></b>' % ( |
520 | + cgi.escape(filename), cgi.escape(filename)) |
521 | else: |
522 | - return '<a href="#%s">%s</a>' % ( |
523 | - cgi.escape(filename), cgi.escape(filename)) |
524 | + return revision_link( |
525 | + url, entry.revno, filename, '#' + filename) |
526 | else: |
527 | - file_link = lambda filename: revision_link(url, entry.revno, filename) |
528 | + def file_link(filename): |
529 | + return '<a href="%s%s" title="View changes to %s in revision %s">%s</a>'%( |
530 | + url(['/revision', entry.revno]), '#' + filename, cgi.escape(filename), |
531 | + cgi.escape(entry.revno), cgi.escape(filename)) |
532 | return _pt('revisionfilechanges').expand( |
533 | url=url, entry=entry, file_link=file_link, |
534 | currently_showing=currently_showing, **templatefunctions) |
535 | @@ -120,7 +120,7 @@ |
536 | url(['/annotate', revno, path]), cgi.escape(path), cgi.escape(path)) |
537 | |
538 | @templatefunc |
539 | -def revision_link(url, revno, path): |
540 | - return '<a href="%s" title="View changes to %s in revision %s">%s</a>'%( |
541 | - url(['/revision', revno, path]), cgi.escape(path), cgi.escape(revno), |
542 | - cgi.escape(path)) |
543 | +def revision_link(url, revno, path, frag=''): |
544 | + return '<a href="%s%s" title="View changes to %s in revision %s">%s</a>'%( |
545 | + url(['/revision', revno, path]), frag, cgi.escape(path), |
546 | + cgi.escape(revno), cgi.escape(path)) |
547 | |
548 | === added file 'loggerhead/templates/filediff.pt' |
549 | --- loggerhead/templates/filediff.pt 1970-01-01 00:00:00 +0000 |
550 | +++ loggerhead/templates/filediff.pt 2009-03-17 00:02:21 +0000 |
551 | @@ -0,0 +1,25 @@ |
552 | +<div class="diffinfo"> |
553 | + <div class="pseudotable unified" |
554 | + tal:repeat="chunk chunks"> |
555 | + |
556 | + <tal:block condition="not:repeat/chunk/start"> |
557 | + <div class="pseudorow context-row"> |
558 | + <div class="lineNumber separate"></div> |
559 | + <div class="lineNumber second separate"></div> |
560 | + <div class="code separate"></div> |
561 | + <div class="clear"><!-- --></div> |
562 | + </div> |
563 | + </tal:block> |
564 | + |
565 | + <div tal:repeat="line chunk/diff" |
566 | + tal:attributes="class string:pseudorow ${line/type}-row"> |
567 | + <div class="lineNumber first" |
568 | + tal:content="structure python:util.fill_div(line.old_lineno)"></div> |
569 | + <div class="lineNumber second" |
570 | + tal:content="structure python:util.fill_div(line.new_lineno)"></div> |
571 | + <div tal:attributes="class string:code ${line/type}" |
572 | + tal:content="structure python:util.fill_div(util.html_clean(line.line))"></div> |
573 | + <div class="clear"><!-- --></div> |
574 | + </div> |
575 | + </div> |
576 | +</div> |
577 | |
578 | === modified file 'loggerhead/templates/revision.pt' |
579 | --- loggerhead/templates/revision.pt 2009-03-16 06:44:50 +0000 |
580 | +++ loggerhead/templates/revision.pt 2009-03-17 03:49:33 +0000 |
581 | @@ -11,6 +11,11 @@ |
582 | tal:attributes="href python:branch.static_url('/static/css/diff.css')"/> |
583 | <script type="text/javascript" |
584 | tal:attributes="src python:branch.static_url('/static/javascript/diff.js')"></script> |
585 | + <script type="text/javascript"> |
586 | + var link_data = <tal:b content="link_data" />; |
587 | + var specific_path = <tal:b content="json_specific_path" />; |
588 | + var path_to_id = <tal:b content="path_to_id" />; |
589 | + </script> |
590 | </metal:block> |
591 | </head> |
592 | |
593 | @@ -92,14 +97,16 @@ |
594 | </tal:we-are-comparing> |
595 | |
596 | <tal:revision-info replace="structure python:revisioninfo(url, branch, change, 'fragment', specific_path)" /> |
597 | - <p class="expand" id="expand_all" style="display:none;"><a href="#"> |
598 | - <img tal:attributes="src python:branch.static_url('/static/images/treeCollapsed.png')" |
599 | - alt="expand all" /> expand all</a> |
600 | - </p> |
601 | - <p class="expand show_if_js" id="collapse_all"><a href="#"> |
602 | - <img tal:attributes="src python:branch.static_url('/static/images/treeExpanded.png')" |
603 | - alt="collapse all" /> collapse all</a> |
604 | - </p> |
605 | + <tal:specific-path condition="not:specific_path"> |
606 | + <p class="expand show_if_js" id="expand_all"><a href="#"> |
607 | + <img tal:attributes="src python:branch.static_url('/static/images/treeCollapsed.png')" |
608 | + alt="expand all" /> expand all</a> |
609 | + </p> |
610 | + <p class="expand" id="collapse_all" style="display:none;"><a href="#"> |
611 | + <img tal:attributes="src python:branch.static_url('/static/images/treeExpanded.png')" |
612 | + alt="collapse all" /> collapse all</a> |
613 | + </p> |
614 | + </tal:specific-path> |
615 | <!-- Table --> |
616 | <p class="expand show_if_js"><a id="toggle_unified_sbs" href="#">Show diffs side-by-side</a></p> |
617 | <p class="codin"><img tal:attributes="src python:branch.static_url('/static/images/newCode.gif')" alt="added" /> added</p> |
618 | @@ -110,22 +117,34 @@ |
619 | |
620 | <div metal:fill-slot="content"> |
621 | <div class="diff" |
622 | - tal:repeat="item diffs"> |
623 | + tal:repeat="item diffs" tal:attributes="id string:diff-${item/index}"> |
624 | |
625 | - <div class="diffBox"> |
626 | - <img tal:attributes="src python:branch.static_url('/static/images/treeExpanded.png'); |
627 | - title python:branch.static_url('/static/images/treeCollapsed.png'); |
628 | - alt python:branch.static_url('/static/images/treeExpanded.png')" |
629 | - class="expand_diff" /> |
630 | + <div class="diffBox"> |
631 | <a tal:attributes="href python:url(['/revision', change.revno, item.filename], clear=1); |
632 | id string:${item/filename}; |
633 | title string:View changes to ${item/filename} only" |
634 | - tal:content="item/filename"> |
635 | + class="the-link"> |
636 | + <img tal:attributes="src python:branch.static_url('/static/images/treeCollapsed.png'); |
637 | + title python:branch.static_url('/static/images/treeCollapsed.png'); |
638 | + alt python:branch.static_url('/static/images/treeExpanded.png')" |
639 | + class="expand_diff" tal:condition="not:specific_path" /> |
640 | + <img tal:attributes="src python:branch.static_url('/static/images/treeExpanded.png'); |
641 | + title python:branch.static_url('/static/images/treeCollapsed.png'); |
642 | + alt python:branch.static_url('/static/images/treeExpanded.png')" |
643 | + class="expand_diff" tal:condition="specific_path" /> |
644 | + <tal:b content="item/filename" /> |
645 | </a> |
646 | </div> |
647 | <div style="overflow: hidden"> |
648 | <div class="container"> |
649 | - <div class="diffinfo"> |
650 | + <div class="loading" style="display:none"> |
651 | + <img tal:attributes="src python:branch.static_url('/static/images/spinner.gif')" /> |
652 | + </div> |
653 | + <div class="diffinfo" tal:condition="not:specific_path"> |
654 | + <div class="source_target" > |
655 | + </div> |
656 | + </div> |
657 | + <div class="diffinfo" tal:condition="specific_path"> |
658 | <div class="pseudotable unified" |
659 | tal:repeat="chunk item/chunks"> |
660 |
Hi Reviewer,
The main change this branch makes is to make the default revision page not show any diffs by default and having them loaded by the wonders of xhr.
I've put some effort in to making sure non-js users have a decent experience -- instead of xhr-ing a diff, when scripting is disabled the user is taken to a page that just contains the the diff for the file.
The code, particularly in revision_ui.py, is now much less than clear. I'll fix that in the next branch tomorrow -- basically if you think the new behaviour is good, I can then clean up the innards without changing behaviour tomorrow (perhaps it would have been better to clean up the innards then clean up the behaviour, but oh well).