Show More
@@ -0,0 +1,91 b'' | |||
|
1 | // jQuery Scrollstop Plugin v1.2.0 | |
|
2 | // https://github.com/ssorallen/jquery-scrollstop | |
|
3 | ||
|
4 | (function (factory) { | |
|
5 | // UMD[2] wrapper for jQuery plugins to work in AMD or in CommonJS. | |
|
6 | // | |
|
7 | // [2] https://github.com/umdjs/umd | |
|
8 | ||
|
9 | if (typeof define === 'function' && define.amd) { | |
|
10 | // AMD. Register as an anonymous module. | |
|
11 | define(['jquery'], factory); | |
|
12 | } else if (typeof exports === 'object') { | |
|
13 | // Node/CommonJS | |
|
14 | module.exports = factory(require('jquery')); | |
|
15 | } else { | |
|
16 | // Browser globals | |
|
17 | factory(jQuery); | |
|
18 | } | |
|
19 | }(function ($) { | |
|
20 | // $.event.dispatch was undocumented and was deprecated in jQuery 1.7[1]. It | |
|
21 | // was replaced by $.event.handle in jQuery 1.9. | |
|
22 | // | |
|
23 | // Use the first of the available functions to support jQuery <1.8. | |
|
24 | // | |
|
25 | // [1] https://github.com/jquery/jquery-migrate/blob/master/src/event.js#L25 | |
|
26 | var dispatch = $.event.dispatch || $.event.handle; | |
|
27 | ||
|
28 | var special = $.event.special, | |
|
29 | uid1 = 'D' + (+new Date()), | |
|
30 | uid2 = 'D' + (+new Date() + 1); | |
|
31 | ||
|
32 | special.scrollstart = { | |
|
33 | setup: function(data) { | |
|
34 | var _data = $.extend({ | |
|
35 | latency: special.scrollstop.latency | |
|
36 | }, data); | |
|
37 | ||
|
38 | var timer, | |
|
39 | handler = function(evt) { | |
|
40 | var _self = this, | |
|
41 | _args = arguments; | |
|
42 | ||
|
43 | if (timer) { | |
|
44 | clearTimeout(timer); | |
|
45 | } else { | |
|
46 | evt.type = 'scrollstart'; | |
|
47 | dispatch.apply(_self, _args); | |
|
48 | } | |
|
49 | ||
|
50 | timer = setTimeout(function() { | |
|
51 | timer = null; | |
|
52 | }, _data.latency); | |
|
53 | }; | |
|
54 | ||
|
55 | $(this).bind('scroll', handler).data(uid1, handler); | |
|
56 | }, | |
|
57 | teardown: function() { | |
|
58 | $(this).unbind('scroll', $(this).data(uid1)); | |
|
59 | } | |
|
60 | }; | |
|
61 | ||
|
62 | special.scrollstop = { | |
|
63 | latency: 250, | |
|
64 | setup: function(data) { | |
|
65 | var _data = $.extend({ | |
|
66 | latency: special.scrollstop.latency | |
|
67 | }, data); | |
|
68 | ||
|
69 | var timer, | |
|
70 | handler = function(evt) { | |
|
71 | var _self = this, | |
|
72 | _args = arguments; | |
|
73 | ||
|
74 | if (timer) { | |
|
75 | clearTimeout(timer); | |
|
76 | } | |
|
77 | ||
|
78 | timer = setTimeout(function() { | |
|
79 | timer = null; | |
|
80 | evt.type = 'scrollstop'; | |
|
81 | dispatch.apply(_self, _args); | |
|
82 | }, _data.latency); | |
|
83 | }; | |
|
84 | ||
|
85 | $(this).bind('scroll', handler).data(uid2, handler); | |
|
86 | }, | |
|
87 | teardown: function() { | |
|
88 | $(this).unbind('scroll', $(this).data(uid2)); | |
|
89 | } | |
|
90 | }; | |
|
91 | })); |
@@ -0,0 +1,171 b'' | |||
|
1 | /** | |
|
2 | * Within Viewport jQuery Plugin | |
|
3 | * | |
|
4 | * @description Companion plugin for withinviewport.js - determines whether an element is completely within the browser viewport | |
|
5 | * @author Craig Patik, http://patik.com/ | |
|
6 | * @version 2.1.2 | |
|
7 | * @date 2019-08-16 | |
|
8 | */ | |
|
9 | (function ($) { | |
|
10 | /** | |
|
11 | * $.withinviewport() | |
|
12 | * @description jQuery method | |
|
13 | * @param {Object} [settings] optional settings | |
|
14 | * @return {Collection} Contains all elements that were within the viewport | |
|
15 | */ | |
|
16 | $.fn.withinviewport = function (settings) { | |
|
17 | var opts; | |
|
18 | var elems; | |
|
19 | ||
|
20 | if (typeof settings === 'string') { | |
|
21 | settings = { | |
|
22 | sides: settings | |
|
23 | }; | |
|
24 | } | |
|
25 | ||
|
26 | opts = $.extend({}, settings, { | |
|
27 | sides: 'all' | |
|
28 | }); | |
|
29 | elems = []; | |
|
30 | ||
|
31 | this.each(function () { | |
|
32 | if (withinviewport(this, opts)) { | |
|
33 | elems.push(this); | |
|
34 | } | |
|
35 | }); | |
|
36 | ||
|
37 | return $(elems); | |
|
38 | }; | |
|
39 | ||
|
40 | // Main custom selector | |
|
41 | $.extend($.expr[':'], { | |
|
42 | 'within-viewport': function (element) { | |
|
43 | return withinviewport(element, 'all'); | |
|
44 | } | |
|
45 | }); | |
|
46 | ||
|
47 | /** | |
|
48 | * Optional enhancements and shortcuts | |
|
49 | * | |
|
50 | * @description Uncomment or comment these pieces as they apply to your project and coding preferences | |
|
51 | */ | |
|
52 | ||
|
53 | // Shorthand jQuery methods | |
|
54 | ||
|
55 | $.fn.withinviewporttop = function (settings) { | |
|
56 | var opts; | |
|
57 | var elems; | |
|
58 | ||
|
59 | if (typeof settings === 'string') { | |
|
60 | settings = { | |
|
61 | sides: settings | |
|
62 | }; | |
|
63 | } | |
|
64 | ||
|
65 | opts = $.extend({}, settings, { | |
|
66 | sides: 'top' | |
|
67 | }); | |
|
68 | elems = []; | |
|
69 | ||
|
70 | this.each(function () { | |
|
71 | if (withinviewport(this, opts)) { | |
|
72 | elems.push(this); | |
|
73 | } | |
|
74 | }); | |
|
75 | ||
|
76 | return $(elems); | |
|
77 | }; | |
|
78 | ||
|
79 | $.fn.withinviewportright = function (settings) { | |
|
80 | var opts; | |
|
81 | var elems; | |
|
82 | ||
|
83 | if (typeof settings === 'string') { | |
|
84 | settings = { | |
|
85 | sides: settings | |
|
86 | }; | |
|
87 | } | |
|
88 | ||
|
89 | opts = $.extend({}, settings, { | |
|
90 | sides: 'right' | |
|
91 | }); | |
|
92 | elems = []; | |
|
93 | ||
|
94 | this.each(function () { | |
|
95 | if (withinviewport(this, opts)) { | |
|
96 | elems.push(this); | |
|
97 | } | |
|
98 | }); | |
|
99 | ||
|
100 | return $(elems); | |
|
101 | }; | |
|
102 | ||
|
103 | $.fn.withinviewportbottom = function (settings) { | |
|
104 | var opts; | |
|
105 | var elems; | |
|
106 | ||
|
107 | if (typeof settings === 'string') { | |
|
108 | settings = { | |
|
109 | sides: settings | |
|
110 | }; | |
|
111 | } | |
|
112 | ||
|
113 | opts = $.extend({}, settings, { | |
|
114 | sides: 'bottom' | |
|
115 | }); | |
|
116 | elems = []; | |
|
117 | ||
|
118 | this.each(function () { | |
|
119 | if (withinviewport(this, opts)) { | |
|
120 | elems.push(this); | |
|
121 | } | |
|
122 | }); | |
|
123 | ||
|
124 | return $(elems); | |
|
125 | }; | |
|
126 | ||
|
127 | $.fn.withinviewportleft = function (settings) { | |
|
128 | var opts; | |
|
129 | var elems; | |
|
130 | ||
|
131 | if (typeof settings === 'string') { | |
|
132 | settings = { | |
|
133 | sides: settings | |
|
134 | }; | |
|
135 | } | |
|
136 | ||
|
137 | opts = $.extend({}, settings, { | |
|
138 | sides: 'left' | |
|
139 | }); | |
|
140 | elems = []; | |
|
141 | ||
|
142 | this.each(function () { | |
|
143 | if (withinviewport(this, opts)) { | |
|
144 | elems.push(this); | |
|
145 | } | |
|
146 | }); | |
|
147 | ||
|
148 | return $(elems); | |
|
149 | }; | |
|
150 | ||
|
151 | // Custom jQuery selectors | |
|
152 | $.extend($.expr[':'], { | |
|
153 | 'within-viewport-top': function (element) { | |
|
154 | return withinviewport(element, 'top'); | |
|
155 | }, | |
|
156 | 'within-viewport-right': function (element) { | |
|
157 | return withinviewport(element, 'right'); | |
|
158 | }, | |
|
159 | 'within-viewport-bottom': function (element) { | |
|
160 | return withinviewport(element, 'bottom'); | |
|
161 | }, | |
|
162 | 'within-viewport-left': function (element) { | |
|
163 | return withinviewport(element, 'left'); | |
|
164 | } | |
|
165 | // Example custom selector: | |
|
166 | //, | |
|
167 | // 'within-viewport-top-left-45': function (element) { | |
|
168 | // return withinviewport(element, {sides:'top left', top: 45, left: 45}); | |
|
169 | // } | |
|
170 | }); | |
|
171 | }(jQuery)); No newline at end of file |
@@ -0,0 +1,235 b'' | |||
|
1 | /** | |
|
2 | * Within Viewport | |
|
3 | * | |
|
4 | * @description Determines whether an element is completely within the browser viewport | |
|
5 | * @author Craig Patik, http://patik.com/ | |
|
6 | * @version 2.1.2 | |
|
7 | * @date 2019-08-16 | |
|
8 | */ | |
|
9 | (function (root, name, factory) { | |
|
10 | // AMD | |
|
11 | if (typeof define === 'function' && define.amd) { | |
|
12 | define([], factory); | |
|
13 | } | |
|
14 | // Node and CommonJS-like environments | |
|
15 | else if (typeof module !== 'undefined' && typeof exports === 'object') { | |
|
16 | module.exports = factory(); | |
|
17 | } | |
|
18 | // Browser global | |
|
19 | else { | |
|
20 | root[name] = factory(); | |
|
21 | } | |
|
22 | }(this, 'withinviewport', function () { | |
|
23 | var canUseWindowDimensions = typeof window !== 'undefined' && window.innerHeight !== undefined; // IE 8 and lower fail this | |
|
24 | ||
|
25 | /** | |
|
26 | * Determines whether an element is within the viewport | |
|
27 | * @param {Object} elem DOM Element (required) | |
|
28 | * @param {Object} options Optional settings | |
|
29 | * @return {Boolean} Whether the element was completely within the viewport | |
|
30 | */ | |
|
31 | var withinviewport = function withinviewport(elem, options) { | |
|
32 | var result = false; | |
|
33 | var metadata = {}; | |
|
34 | var config = {}; | |
|
35 | var settings; | |
|
36 | var isWithin; | |
|
37 | var isContainerTheWindow; | |
|
38 | var elemBoundingRect; | |
|
39 | var containerBoundingRect; | |
|
40 | var containerScrollTop; | |
|
41 | var containerScrollLeft; | |
|
42 | var scrollBarWidths = [0, 0]; | |
|
43 | var sideNamesPattern; | |
|
44 | var sides; | |
|
45 | var side; | |
|
46 | var i; | |
|
47 | ||
|
48 | // If invoked by the jQuery plugin, get the actual DOM element | |
|
49 | if (typeof jQuery !== 'undefined' && elem instanceof jQuery) { | |
|
50 | elem = elem.get(0); | |
|
51 | } | |
|
52 | ||
|
53 | if (typeof elem !== 'object' || elem.nodeType !== 1) { | |
|
54 | throw new Error('First argument must be an element'); | |
|
55 | } | |
|
56 | ||
|
57 | // Look for inline settings on the element | |
|
58 | if (elem.getAttribute('data-withinviewport-settings') && window.JSON) { | |
|
59 | metadata = JSON.parse(elem.getAttribute('data-withinviewport-settings')); | |
|
60 | } | |
|
61 | ||
|
62 | // Settings argument may be a simple string (`top`, `right`, etc) | |
|
63 | if (typeof options === 'string') { | |
|
64 | settings = { | |
|
65 | sides: options | |
|
66 | }; | |
|
67 | } else { | |
|
68 | settings = options || {}; | |
|
69 | } | |
|
70 | ||
|
71 | // Build configuration from defaults and user-provided settings and metadata | |
|
72 | config.container = settings.container || metadata.container || withinviewport.defaults.container || window; | |
|
73 | config.sides = settings.sides || metadata.sides || withinviewport.defaults.sides || 'all'; | |
|
74 | config.top = settings.top || metadata.top || withinviewport.defaults.top || 0; | |
|
75 | config.right = settings.right || metadata.right || withinviewport.defaults.right || 0; | |
|
76 | config.bottom = settings.bottom || metadata.bottom || withinviewport.defaults.bottom || 0; | |
|
77 | config.left = settings.left || metadata.left || withinviewport.defaults.left || 0; | |
|
78 | ||
|
79 | // Extract the DOM node from a jQuery collection | |
|
80 | if (typeof jQuery !== 'undefined' && config.container instanceof jQuery) { | |
|
81 | config.container = config.container.get(0); | |
|
82 | } | |
|
83 | ||
|
84 | // Use the window as the container if the user specified the body or a non-element | |
|
85 | if (config.container === document.body || config.container.nodeType !== 1) { | |
|
86 | config.container = window; | |
|
87 | } | |
|
88 | ||
|
89 | isContainerTheWindow = (config.container === window); | |
|
90 | ||
|
91 | // Element testing methods | |
|
92 | isWithin = { | |
|
93 | // Element is below the top edge of the viewport | |
|
94 | top: function _isWithin_top() { | |
|
95 | if (isContainerTheWindow) { | |
|
96 | return (elemBoundingRect.top >= config.top); | |
|
97 | } else { | |
|
98 | return (elemBoundingRect.top >= containerScrollTop - (containerScrollTop - containerBoundingRect.top) + config.top); | |
|
99 | } | |
|
100 | }, | |
|
101 | ||
|
102 | // Element is to the left of the right edge of the viewport | |
|
103 | right: function _isWithin_right() { | |
|
104 | // Note that `elemBoundingRect.right` is the distance from the *left* of the viewport to the element's far right edge | |
|
105 | ||
|
106 | if (isContainerTheWindow) { | |
|
107 | return (elemBoundingRect.right <= (containerBoundingRect.right + containerScrollLeft) - config.right); | |
|
108 | } else { | |
|
109 | return (elemBoundingRect.right <= containerBoundingRect.right - scrollBarWidths[0] - config.right); | |
|
110 | } | |
|
111 | }, | |
|
112 | ||
|
113 | // Element is above the bottom edge of the viewport | |
|
114 | bottom: function _isWithin_bottom() { | |
|
115 | var containerHeight = 0; | |
|
116 | ||
|
117 | if (isContainerTheWindow) { | |
|
118 | if (canUseWindowDimensions) { | |
|
119 | containerHeight = config.container.innerHeight; | |
|
120 | } else if (document && document.documentElement) { | |
|
121 | containerHeight = document.documentElement.clientHeight; | |
|
122 | } | |
|
123 | } else { | |
|
124 | containerHeight = containerBoundingRect.bottom; | |
|
125 | } | |
|
126 | ||
|
127 | // Note that `elemBoundingRect.bottom` is the distance from the *top* of the viewport to the element's bottom edge | |
|
128 | return (elemBoundingRect.bottom <= containerHeight - scrollBarWidths[1] - config.bottom); | |
|
129 | }, | |
|
130 | ||
|
131 | // Element is to the right of the left edge of the viewport | |
|
132 | left: function _isWithin_left() { | |
|
133 | if (isContainerTheWindow) { | |
|
134 | return (elemBoundingRect.left >= config.left); | |
|
135 | } else { | |
|
136 | return (elemBoundingRect.left >= containerScrollLeft - (containerScrollLeft - containerBoundingRect.left) + config.left); | |
|
137 | } | |
|
138 | }, | |
|
139 | ||
|
140 | // Element is within all four boundaries | |
|
141 | all: function _isWithin_all() { | |
|
142 | // Test each boundary in order of efficiency and likeliness to be false. This way we can avoid running all four functions on most elements. | |
|
143 | // 1. Top: Quickest to calculate + most likely to be false | |
|
144 | // 2. Bottom: Note quite as quick to calculate, but also very likely to be false | |
|
145 | // 3-4. Left and right are both equally unlikely to be false since most sites only scroll vertically, but left is faster to calculate | |
|
146 | return (isWithin.top() && isWithin.bottom() && isWithin.left() && isWithin.right()); | |
|
147 | } | |
|
148 | }; | |
|
149 | ||
|
150 | // Get the element's bounding rectangle with respect to the viewport | |
|
151 | elemBoundingRect = elem.getBoundingClientRect(); | |
|
152 | ||
|
153 | // Get viewport dimensions and offsets | |
|
154 | if (isContainerTheWindow) { | |
|
155 | containerBoundingRect = document.documentElement.getBoundingClientRect(); | |
|
156 | containerScrollTop = document.body.scrollTop; | |
|
157 | containerScrollLeft = window.scrollX || document.body.scrollLeft; | |
|
158 | } else { | |
|
159 | containerBoundingRect = config.container.getBoundingClientRect(); | |
|
160 | containerScrollTop = config.container.scrollTop; | |
|
161 | containerScrollLeft = config.container.scrollLeft; | |
|
162 | } | |
|
163 | ||
|
164 | // Don't count the space consumed by scrollbars | |
|
165 | if (containerScrollLeft) { | |
|
166 | scrollBarWidths[0] = 18; | |
|
167 | } | |
|
168 | ||
|
169 | if (containerScrollTop) { | |
|
170 | scrollBarWidths[1] = 16; | |
|
171 | } | |
|
172 | ||
|
173 | // Test the element against each side of the viewport that was requested | |
|
174 | sideNamesPattern = /^top$|^right$|^bottom$|^left$|^all$/; | |
|
175 | ||
|
176 | // Loop through all of the sides | |
|
177 | sides = config.sides.split(' '); | |
|
178 | i = sides.length; | |
|
179 | ||
|
180 | while (i--) { | |
|
181 | side = sides[i].toLowerCase(); | |
|
182 | ||
|
183 | if (sideNamesPattern.test(side)) { | |
|
184 | if (isWithin[side]()) { | |
|
185 | result = true; | |
|
186 | } else { | |
|
187 | result = false; | |
|
188 | ||
|
189 | // Quit as soon as the first failure is found | |
|
190 | break; | |
|
191 | } | |
|
192 | } | |
|
193 | } | |
|
194 | ||
|
195 | return result; | |
|
196 | }; | |
|
197 | ||
|
198 | // Default settings | |
|
199 | withinviewport.prototype.defaults = { | |
|
200 | container: typeof document !== 'undefined' ? document.body : {}, | |
|
201 | sides: 'all', | |
|
202 | top: 0, | |
|
203 | right: 0, | |
|
204 | bottom: 0, | |
|
205 | left: 0 | |
|
206 | }; | |
|
207 | ||
|
208 | withinviewport.defaults = withinviewport.prototype.defaults; | |
|
209 | ||
|
210 | /** | |
|
211 | * Optional enhancements and shortcuts | |
|
212 | * | |
|
213 | * @description Uncomment or comment these pieces as they apply to your project and coding preferences | |
|
214 | */ | |
|
215 | ||
|
216 | // Shortcut methods for each side of the viewport | |
|
217 | // Example: `withinviewport.top(elem)` is the same as `withinviewport(elem, 'top')` | |
|
218 | withinviewport.prototype.top = function _withinviewport_top(element) { | |
|
219 | return withinviewport(element, 'top'); | |
|
220 | }; | |
|
221 | ||
|
222 | withinviewport.prototype.right = function _withinviewport_right(element) { | |
|
223 | return withinviewport(element, 'right'); | |
|
224 | }; | |
|
225 | ||
|
226 | withinviewport.prototype.bottom = function _withinviewport_bottom(element) { | |
|
227 | return withinviewport(element, 'bottom'); | |
|
228 | }; | |
|
229 | ||
|
230 | withinviewport.prototype.left = function _withinviewport_left(element) { | |
|
231 | return withinviewport(element, 'left'); | |
|
232 | }; | |
|
233 | ||
|
234 | return withinviewport; | |
|
235 | })); No newline at end of file |
@@ -51,9 +51,12 b'' | |||
|
51 | 51 | "<%= dirs.js.src %>/plugins/jquery.pjax.js", |
|
52 | 52 | "<%= dirs.js.src %>/plugins/jquery.dataTables.js", |
|
53 | 53 | "<%= dirs.js.src %>/plugins/flavoured_checkbox.js", |
|
54 | "<%= dirs.js.src %>/plugins/within_viewport.js", | |
|
54 | 55 | "<%= dirs.js.src %>/plugins/jquery.auto-grow-input.js", |
|
55 | 56 | "<%= dirs.js.src %>/plugins/jquery.autocomplete.js", |
|
56 | 57 | "<%= dirs.js.src %>/plugins/jquery.debounce.js", |
|
58 | "<%= dirs.js.src %>/plugins/jquery.scrollstop.js", | |
|
59 | "<%= dirs.js.src %>/plugins/jquery.within-viewport.js", | |
|
57 | 60 | "<%= dirs.js.node_modules %>/mark.js/dist/jquery.mark.min.js", |
|
58 | 61 | "<%= dirs.js.src %>/plugins/jquery.timeago.js", |
|
59 | 62 | "<%= dirs.js.src %>/plugins/jquery.timeago-extension.js", |
@@ -540,10 +540,11 b' class DiffSet(object):' | |||
|
540 | 540 | }) |
|
541 | 541 | |
|
542 | 542 | file_chunks = patch['chunks'][1:] |
|
543 | for hunk in file_chunks: | |
|
543 | for i, hunk in enumerate(file_chunks, 1): | |
|
544 | 544 | hunkbit = self.parse_hunk(hunk, source_file, target_file) |
|
545 | 545 | hunkbit.source_file_path = source_file_path |
|
546 | 546 | hunkbit.target_file_path = target_file_path |
|
547 | hunkbit.index = i | |
|
547 | 548 | filediff.hunks.append(hunkbit) |
|
548 | 549 | |
|
549 | 550 | # Simulate hunk on OPS type line which doesn't really contain any diff |
@@ -53,7 +53,7 b' from pygments.lexers import (' | |||
|
53 | 53 | get_lexer_by_name, get_lexer_for_filename, get_lexer_for_mimetype) |
|
54 | 54 | |
|
55 | 55 | from pyramid.threadlocal import get_current_request |
|
56 | ||
|
56 | from tempita import looper | |
|
57 | 57 | from webhelpers2.html import literal, HTML, escape |
|
58 | 58 | from webhelpers2.html._autolink import _auto_link_urls |
|
59 | 59 | from webhelpers2.html.tools import ( |
@@ -998,6 +998,21 b' input.filediff-collapse-state {' | |||
|
998 | 998 | |
|
999 | 999 | /**** END COMMENTS ****/ |
|
1000 | 1000 | |
|
1001 | ||
|
1002 | .nav-chunk { | |
|
1003 | position: absolute; | |
|
1004 | right: 20px; | |
|
1005 | margin-top: -17px; | |
|
1006 | } | |
|
1007 | ||
|
1008 | .nav-chunk.selected { | |
|
1009 | visibility: visible !important; | |
|
1010 | } | |
|
1011 | ||
|
1012 | #diff_nav { | |
|
1013 | color: @grey3; | |
|
1014 | } | |
|
1015 | ||
|
1001 | 1016 | } |
|
1002 | 1017 | |
|
1003 | 1018 |
@@ -314,6 +314,7 b" return '%s_%s_%i' % (h.md5_safe(commit+f" | |||
|
314 | 314 | ${hunk.section_header} |
|
315 | 315 | </td> |
|
316 | 316 | </tr> |
|
317 | ||
|
317 | 318 | ${render_hunk_lines(filediff, c.user_session_attrs["diffmode"], hunk, use_comments=use_comments, inline_comments=inline_comments, active_pattern_entries=active_pattern_entries)} |
|
318 | 319 | % endfor |
|
319 | 320 | |
@@ -657,21 +658,28 b' def get_comments_for(diff_type, comments' | |||
|
657 | 658 | %> |
|
658 | 659 | |
|
659 | 660 | <%def name="render_hunk_lines_sideside(filediff, hunk, use_comments=False, inline_comments=None, active_pattern_entries=None)"> |
|
660 | %for i, line in enumerate(hunk.sideside): | |
|
661 | ||
|
662 | <% chunk_count = 1 %> | |
|
663 | %for loop_obj, item in h.looper(hunk.sideside): | |
|
661 | 664 | <% |
|
665 | line = item | |
|
666 | i = loop_obj.index | |
|
667 | prev_line = loop_obj.previous | |
|
662 | 668 | old_line_anchor, new_line_anchor = None, None |
|
663 | 669 | |
|
664 | 670 | if line.original.lineno: |
|
665 | 671 | old_line_anchor = diff_line_anchor(filediff.raw_id, hunk.source_file_path, line.original.lineno, 'o') |
|
666 | 672 | if line.modified.lineno: |
|
667 | 673 | new_line_anchor = diff_line_anchor(filediff.raw_id, hunk.target_file_path, line.modified.lineno, 'n') |
|
674 | ||
|
675 | line_action = line.modified.action or line.original.action | |
|
676 | prev_line_action = prev_line and (prev_line.modified.action or prev_line.original.action) | |
|
668 | 677 | %> |
|
669 | 678 | |
|
670 | 679 | <tr class="cb-line"> |
|
671 | 680 | <td class="cb-data ${action_class(line.original.action)}" |
|
672 | 681 | data-line-no="${line.original.lineno}" |
|
673 | 682 | > |
|
674 | <div> | |
|
675 | 683 | |
|
676 | 684 | <% line_old_comments = None %> |
|
677 | 685 | %if line.original.get_comment_args: |
@@ -685,7 +693,6 b' def get_comments_for(diff_type, comments' | |||
|
685 | 693 | <i class="tooltip icon-comment" title="${_('comments: {}. Click to toggle them.').format(len(line_old_comments))}" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> |
|
686 | 694 | % endif |
|
687 | 695 | %endif |
|
688 | </div> | |
|
689 | 696 | </td> |
|
690 | 697 | <td class="cb-lineno ${action_class(line.original.action)}" |
|
691 | 698 | data-line-no="${line.original.lineno}" |
@@ -751,6 +758,12 b' def get_comments_for(diff_type, comments' | |||
|
751 | 758 | %if use_comments and line.modified.lineno and line_new_comments: |
|
752 | 759 | ${inline_comments_container(line_new_comments, active_pattern_entries=active_pattern_entries)} |
|
753 | 760 | %endif |
|
761 | % if line_action in ['+', '-'] and prev_line_action not in ['+', '-']: | |
|
762 | <div class="nav-chunk" style="visibility: hidden"> | |
|
763 | <i class="icon-eye" title="viewing diff hunk-${hunk.index}-${chunk_count}"></i> | |
|
764 | </div> | |
|
765 | <% chunk_count +=1 %> | |
|
766 | % endif | |
|
754 | 767 | </td> |
|
755 | 768 | </tr> |
|
756 | 769 | %endfor |
@@ -903,12 +916,21 b' def get_comments_for(diff_type, comments' | |||
|
903 | 916 | </div> |
|
904 | 917 | </div> |
|
905 | 918 | </div> |
|
906 | <div class="fpath-placeholder"> | |
|
919 | <div class="fpath-placeholder pull-left"> | |
|
907 | 920 | <i class="icon-file-text"></i> |
|
908 | 921 | <strong class="fpath-placeholder-text"> |
|
909 | 922 | Context file: |
|
910 | 923 | </strong> |
|
911 | 924 | </div> |
|
925 | <div class="pull-right noselect"> | |
|
926 | <span id="diff_nav">Loading diff...:</span> | |
|
927 | <span class="cursor-pointer" onclick="scrollToPrevChunk(); return false"> | |
|
928 | <i class="icon-angle-up"></i> | |
|
929 | </span> | |
|
930 | <span class="cursor-pointer" onclick="scrollToNextChunk(); return false"> | |
|
931 | <i class="icon-angle-down"></i> | |
|
932 | </span> | |
|
933 | </div> | |
|
912 | 934 | <div class="sidebar_inner_shadow"></div> |
|
913 | 935 | </div> |
|
914 | 936 | </div> |
@@ -1031,10 +1053,84 b' def get_comments_for(diff_type, comments' | |||
|
1031 | 1053 | e.preventDefault(); |
|
1032 | 1054 | }); |
|
1033 | 1055 | |
|
1056 | getCurrentChunk = function () { | |
|
1057 | ||
|
1058 | var chunksAll = $('.nav-chunk').filter(function () { | |
|
1059 | return $(this).parents('.filediff').prev().get(0).checked !== true | |
|
1060 | }) | |
|
1061 | var chunkSelected = $('.nav-chunk.selected'); | |
|
1062 | var initial = false; | |
|
1063 | ||
|
1064 | if (chunkSelected.length === 0) { | |
|
1065 | // no initial chunk selected, we pick first | |
|
1066 | chunkSelected = $(chunksAll.get(0)); | |
|
1067 | var initial = true; | |
|
1068 | } | |
|
1069 | ||
|
1070 | return { | |
|
1071 | 'all': chunksAll, | |
|
1072 | 'selected': chunkSelected, | |
|
1073 | 'initial': initial, | |
|
1074 | } | |
|
1075 | } | |
|
1076 | ||
|
1077 | animateDiffNavText = function () { | |
|
1078 | var $diffNav = $('#diff_nav') | |
|
1079 | ||
|
1080 | var callback = function () { | |
|
1081 | $diffNav.animate({'opacity': 1.00}, 200) | |
|
1082 | }; | |
|
1083 | $diffNav.animate({'opacity': 0.15}, 200, callback); | |
|
1084 | } | |
|
1085 | ||
|
1086 | scrollToChunk = function (moveBy) { | |
|
1087 | var chunk = getCurrentChunk(); | |
|
1088 | var all = chunk.all | |
|
1089 | var selected = chunk.selected | |
|
1090 | ||
|
1091 | var curPos = all.index(selected); | |
|
1092 | var newPos = curPos; | |
|
1093 | if (!chunk.initial) { | |
|
1094 | var newPos = curPos + moveBy; | |
|
1095 | } | |
|
1096 | ||
|
1097 | var curElem = all.get(newPos); | |
|
1098 | ||
|
1099 | if (curElem === undefined) { | |
|
1100 | // end or back | |
|
1101 | $('#diff_nav').html('No next diff element.') | |
|
1102 | animateDiffNavText() | |
|
1103 | return | |
|
1104 | } else if (newPos < 0) { | |
|
1105 | $('#diff_nav').html('No previous diff element.') | |
|
1106 | animateDiffNavText() | |
|
1107 | return | |
|
1108 | } else { | |
|
1109 | $('#diff_nav').html('Diff navigation:') | |
|
1110 | } | |
|
1111 | ||
|
1112 | curElem = $(curElem) | |
|
1113 | var offset = 100; | |
|
1114 | $(window).scrollTop(curElem.position().top - offset); | |
|
1115 | ||
|
1116 | //clear selection | |
|
1117 | all.removeClass('selected') | |
|
1118 | curElem.addClass('selected') | |
|
1119 | } | |
|
1120 | ||
|
1121 | scrollToPrevChunk = function () { | |
|
1122 | scrollToChunk(-1) | |
|
1123 | } | |
|
1124 | scrollToNextChunk = function () { | |
|
1125 | scrollToChunk(1) | |
|
1126 | } | |
|
1127 | ||
|
1034 | 1128 | </script> |
|
1035 | 1129 | % endif |
|
1036 | 1130 | |
|
1037 | 1131 | <script type="text/javascript"> |
|
1132 | $('#diff_nav').html('loading diff...') // wait until whole page is loaded | |
|
1133 | ||
|
1038 | 1134 | $(document).ready(function () { |
|
1039 | 1135 | |
|
1040 | 1136 | var contextPrefix = _gettext('Context file: '); |
@@ -1213,6 +1309,46 b' def get_comments_for(diff_type, comments' | |||
|
1213 | 1309 | $('.toggle-wide-diff').addClass('btn-active'); |
|
1214 | 1310 | updateSticky(); |
|
1215 | 1311 | } |
|
1312 | ||
|
1313 | // DIFF NAV // | |
|
1314 | ||
|
1315 | // element to detect scroll direction of | |
|
1316 | var $window = $(window); | |
|
1317 | ||
|
1318 | // initialize last scroll position | |
|
1319 | var lastScrollY = $window.scrollTop(); | |
|
1320 | ||
|
1321 | $window.on('resize scrollstop', {latency: 350}, function () { | |
|
1322 | var visibleChunks = $('.nav-chunk').withinviewport({top: 75}); | |
|
1323 | ||
|
1324 | // get current scroll position | |
|
1325 | var currentScrollY = $window.scrollTop(); | |
|
1326 | ||
|
1327 | // determine current scroll direction | |
|
1328 | if (currentScrollY > lastScrollY) { | |
|
1329 | var y = 'down' | |
|
1330 | } else if (currentScrollY !== lastScrollY) { | |
|
1331 | var y = 'up'; | |
|
1332 | } | |
|
1333 | ||
|
1334 | var pos = -1; // by default we use last element in viewport | |
|
1335 | if (y === 'down') { | |
|
1336 | pos = -1; | |
|
1337 | } else if (y === 'up') { | |
|
1338 | pos = 0; | |
|
1339 | } | |
|
1340 | ||
|
1341 | if (visibleChunks.length > 0) { | |
|
1342 | $('.nav-chunk').removeClass('selected'); | |
|
1343 | $(visibleChunks.get(pos)).addClass('selected'); | |
|
1344 | } | |
|
1345 | ||
|
1346 | // update last scroll position to current position | |
|
1347 | lastScrollY = currentScrollY; | |
|
1348 | ||
|
1349 | }); | |
|
1350 | $('#diff_nav').html('Diff navigation:') | |
|
1351 | ||
|
1216 | 1352 | }); |
|
1217 | 1353 | </script> |
|
1218 | 1354 |
General Comments 0
You need to be logged in to leave comments.
Login now