diffs: added diff navigation to improve UX when browisng the full context diffs.
This commit is contained in:
parent
9cadf302eb
commit
012f801f16
8 changed files with 658 additions and 6 deletions
|
|
@ -998,6 +998,21 @@ input.filediff-collapse-state {
|
|||
|
||||
/**** END COMMENTS ****/
|
||||
|
||||
|
||||
.nav-chunk {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
margin-top: -17px;
|
||||
}
|
||||
|
||||
.nav-chunk.selected {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
#diff_nav {
|
||||
color: @grey3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
91
rhodecode/public/js/src/plugins/jquery.scrollstop.js
Normal file
91
rhodecode/public/js/src/plugins/jquery.scrollstop.js
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// jQuery Scrollstop Plugin v1.2.0
|
||||
// https://github.com/ssorallen/jquery-scrollstop
|
||||
|
||||
(function (factory) {
|
||||
// UMD[2] wrapper for jQuery plugins to work in AMD or in CommonJS.
|
||||
//
|
||||
// [2] https://github.com/umdjs/umd
|
||||
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['jquery'], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node/CommonJS
|
||||
module.exports = factory(require('jquery'));
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
// $.event.dispatch was undocumented and was deprecated in jQuery 1.7[1]. It
|
||||
// was replaced by $.event.handle in jQuery 1.9.
|
||||
//
|
||||
// Use the first of the available functions to support jQuery <1.8.
|
||||
//
|
||||
// [1] https://github.com/jquery/jquery-migrate/blob/master/src/event.js#L25
|
||||
var dispatch = $.event.dispatch || $.event.handle;
|
||||
|
||||
var special = $.event.special,
|
||||
uid1 = 'D' + (+new Date()),
|
||||
uid2 = 'D' + (+new Date() + 1);
|
||||
|
||||
special.scrollstart = {
|
||||
setup: function(data) {
|
||||
var _data = $.extend({
|
||||
latency: special.scrollstop.latency
|
||||
}, data);
|
||||
|
||||
var timer,
|
||||
handler = function(evt) {
|
||||
var _self = this,
|
||||
_args = arguments;
|
||||
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
} else {
|
||||
evt.type = 'scrollstart';
|
||||
dispatch.apply(_self, _args);
|
||||
}
|
||||
|
||||
timer = setTimeout(function() {
|
||||
timer = null;
|
||||
}, _data.latency);
|
||||
};
|
||||
|
||||
$(this).bind('scroll', handler).data(uid1, handler);
|
||||
},
|
||||
teardown: function() {
|
||||
$(this).unbind('scroll', $(this).data(uid1));
|
||||
}
|
||||
};
|
||||
|
||||
special.scrollstop = {
|
||||
latency: 250,
|
||||
setup: function(data) {
|
||||
var _data = $.extend({
|
||||
latency: special.scrollstop.latency
|
||||
}, data);
|
||||
|
||||
var timer,
|
||||
handler = function(evt) {
|
||||
var _self = this,
|
||||
_args = arguments;
|
||||
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
|
||||
timer = setTimeout(function() {
|
||||
timer = null;
|
||||
evt.type = 'scrollstop';
|
||||
dispatch.apply(_self, _args);
|
||||
}, _data.latency);
|
||||
};
|
||||
|
||||
$(this).bind('scroll', handler).data(uid2, handler);
|
||||
},
|
||||
teardown: function() {
|
||||
$(this).unbind('scroll', $(this).data(uid2));
|
||||
}
|
||||
};
|
||||
}));
|
||||
171
rhodecode/public/js/src/plugins/jquery.within-viewport.js
Normal file
171
rhodecode/public/js/src/plugins/jquery.within-viewport.js
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* Within Viewport jQuery Plugin
|
||||
*
|
||||
* @description Companion plugin for withinviewport.js - determines whether an element is completely within the browser viewport
|
||||
* @author Craig Patik, http://patik.com/
|
||||
* @version 2.1.2
|
||||
* @date 2019-08-16
|
||||
*/
|
||||
(function ($) {
|
||||
/**
|
||||
* $.withinviewport()
|
||||
* @description jQuery method
|
||||
* @param {Object} [settings] optional settings
|
||||
* @return {Collection} Contains all elements that were within the viewport
|
||||
*/
|
||||
$.fn.withinviewport = function (settings) {
|
||||
var opts;
|
||||
var elems;
|
||||
|
||||
if (typeof settings === 'string') {
|
||||
settings = {
|
||||
sides: settings
|
||||
};
|
||||
}
|
||||
|
||||
opts = $.extend({}, settings, {
|
||||
sides: 'all'
|
||||
});
|
||||
elems = [];
|
||||
|
||||
this.each(function () {
|
||||
if (withinviewport(this, opts)) {
|
||||
elems.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
return $(elems);
|
||||
};
|
||||
|
||||
// Main custom selector
|
||||
$.extend($.expr[':'], {
|
||||
'within-viewport': function (element) {
|
||||
return withinviewport(element, 'all');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Optional enhancements and shortcuts
|
||||
*
|
||||
* @description Uncomment or comment these pieces as they apply to your project and coding preferences
|
||||
*/
|
||||
|
||||
// Shorthand jQuery methods
|
||||
|
||||
$.fn.withinviewporttop = function (settings) {
|
||||
var opts;
|
||||
var elems;
|
||||
|
||||
if (typeof settings === 'string') {
|
||||
settings = {
|
||||
sides: settings
|
||||
};
|
||||
}
|
||||
|
||||
opts = $.extend({}, settings, {
|
||||
sides: 'top'
|
||||
});
|
||||
elems = [];
|
||||
|
||||
this.each(function () {
|
||||
if (withinviewport(this, opts)) {
|
||||
elems.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
return $(elems);
|
||||
};
|
||||
|
||||
$.fn.withinviewportright = function (settings) {
|
||||
var opts;
|
||||
var elems;
|
||||
|
||||
if (typeof settings === 'string') {
|
||||
settings = {
|
||||
sides: settings
|
||||
};
|
||||
}
|
||||
|
||||
opts = $.extend({}, settings, {
|
||||
sides: 'right'
|
||||
});
|
||||
elems = [];
|
||||
|
||||
this.each(function () {
|
||||
if (withinviewport(this, opts)) {
|
||||
elems.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
return $(elems);
|
||||
};
|
||||
|
||||
$.fn.withinviewportbottom = function (settings) {
|
||||
var opts;
|
||||
var elems;
|
||||
|
||||
if (typeof settings === 'string') {
|
||||
settings = {
|
||||
sides: settings
|
||||
};
|
||||
}
|
||||
|
||||
opts = $.extend({}, settings, {
|
||||
sides: 'bottom'
|
||||
});
|
||||
elems = [];
|
||||
|
||||
this.each(function () {
|
||||
if (withinviewport(this, opts)) {
|
||||
elems.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
return $(elems);
|
||||
};
|
||||
|
||||
$.fn.withinviewportleft = function (settings) {
|
||||
var opts;
|
||||
var elems;
|
||||
|
||||
if (typeof settings === 'string') {
|
||||
settings = {
|
||||
sides: settings
|
||||
};
|
||||
}
|
||||
|
||||
opts = $.extend({}, settings, {
|
||||
sides: 'left'
|
||||
});
|
||||
elems = [];
|
||||
|
||||
this.each(function () {
|
||||
if (withinviewport(this, opts)) {
|
||||
elems.push(this);
|
||||
}
|
||||
});
|
||||
|
||||
return $(elems);
|
||||
};
|
||||
|
||||
// Custom jQuery selectors
|
||||
$.extend($.expr[':'], {
|
||||
'within-viewport-top': function (element) {
|
||||
return withinviewport(element, 'top');
|
||||
},
|
||||
'within-viewport-right': function (element) {
|
||||
return withinviewport(element, 'right');
|
||||
},
|
||||
'within-viewport-bottom': function (element) {
|
||||
return withinviewport(element, 'bottom');
|
||||
},
|
||||
'within-viewport-left': function (element) {
|
||||
return withinviewport(element, 'left');
|
||||
}
|
||||
// Example custom selector:
|
||||
//,
|
||||
// 'within-viewport-top-left-45': function (element) {
|
||||
// return withinviewport(element, {sides:'top left', top: 45, left: 45});
|
||||
// }
|
||||
});
|
||||
}(jQuery));
|
||||
235
rhodecode/public/js/src/plugins/within_viewport.js
Normal file
235
rhodecode/public/js/src/plugins/within_viewport.js
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/**
|
||||
* Within Viewport
|
||||
*
|
||||
* @description Determines whether an element is completely within the browser viewport
|
||||
* @author Craig Patik, http://patik.com/
|
||||
* @version 2.1.2
|
||||
* @date 2019-08-16
|
||||
*/
|
||||
(function (root, name, factory) {
|
||||
// AMD
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], factory);
|
||||
}
|
||||
// Node and CommonJS-like environments
|
||||
else if (typeof module !== 'undefined' && typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
}
|
||||
// Browser global
|
||||
else {
|
||||
root[name] = factory();
|
||||
}
|
||||
}(this, 'withinviewport', function () {
|
||||
var canUseWindowDimensions = typeof window !== 'undefined' && window.innerHeight !== undefined; // IE 8 and lower fail this
|
||||
|
||||
/**
|
||||
* Determines whether an element is within the viewport
|
||||
* @param {Object} elem DOM Element (required)
|
||||
* @param {Object} options Optional settings
|
||||
* @return {Boolean} Whether the element was completely within the viewport
|
||||
*/
|
||||
var withinviewport = function withinviewport(elem, options) {
|
||||
var result = false;
|
||||
var metadata = {};
|
||||
var config = {};
|
||||
var settings;
|
||||
var isWithin;
|
||||
var isContainerTheWindow;
|
||||
var elemBoundingRect;
|
||||
var containerBoundingRect;
|
||||
var containerScrollTop;
|
||||
var containerScrollLeft;
|
||||
var scrollBarWidths = [0, 0];
|
||||
var sideNamesPattern;
|
||||
var sides;
|
||||
var side;
|
||||
var i;
|
||||
|
||||
// If invoked by the jQuery plugin, get the actual DOM element
|
||||
if (typeof jQuery !== 'undefined' && elem instanceof jQuery) {
|
||||
elem = elem.get(0);
|
||||
}
|
||||
|
||||
if (typeof elem !== 'object' || elem.nodeType !== 1) {
|
||||
throw new Error('First argument must be an element');
|
||||
}
|
||||
|
||||
// Look for inline settings on the element
|
||||
if (elem.getAttribute('data-withinviewport-settings') && window.JSON) {
|
||||
metadata = JSON.parse(elem.getAttribute('data-withinviewport-settings'));
|
||||
}
|
||||
|
||||
// Settings argument may be a simple string (`top`, `right`, etc)
|
||||
if (typeof options === 'string') {
|
||||
settings = {
|
||||
sides: options
|
||||
};
|
||||
} else {
|
||||
settings = options || {};
|
||||
}
|
||||
|
||||
// Build configuration from defaults and user-provided settings and metadata
|
||||
config.container = settings.container || metadata.container || withinviewport.defaults.container || window;
|
||||
config.sides = settings.sides || metadata.sides || withinviewport.defaults.sides || 'all';
|
||||
config.top = settings.top || metadata.top || withinviewport.defaults.top || 0;
|
||||
config.right = settings.right || metadata.right || withinviewport.defaults.right || 0;
|
||||
config.bottom = settings.bottom || metadata.bottom || withinviewport.defaults.bottom || 0;
|
||||
config.left = settings.left || metadata.left || withinviewport.defaults.left || 0;
|
||||
|
||||
// Extract the DOM node from a jQuery collection
|
||||
if (typeof jQuery !== 'undefined' && config.container instanceof jQuery) {
|
||||
config.container = config.container.get(0);
|
||||
}
|
||||
|
||||
// Use the window as the container if the user specified the body or a non-element
|
||||
if (config.container === document.body || config.container.nodeType !== 1) {
|
||||
config.container = window;
|
||||
}
|
||||
|
||||
isContainerTheWindow = (config.container === window);
|
||||
|
||||
// Element testing methods
|
||||
isWithin = {
|
||||
// Element is below the top edge of the viewport
|
||||
top: function _isWithin_top() {
|
||||
if (isContainerTheWindow) {
|
||||
return (elemBoundingRect.top >= config.top);
|
||||
} else {
|
||||
return (elemBoundingRect.top >= containerScrollTop - (containerScrollTop - containerBoundingRect.top) + config.top);
|
||||
}
|
||||
},
|
||||
|
||||
// Element is to the left of the right edge of the viewport
|
||||
right: function _isWithin_right() {
|
||||
// Note that `elemBoundingRect.right` is the distance from the *left* of the viewport to the element's far right edge
|
||||
|
||||
if (isContainerTheWindow) {
|
||||
return (elemBoundingRect.right <= (containerBoundingRect.right + containerScrollLeft) - config.right);
|
||||
} else {
|
||||
return (elemBoundingRect.right <= containerBoundingRect.right - scrollBarWidths[0] - config.right);
|
||||
}
|
||||
},
|
||||
|
||||
// Element is above the bottom edge of the viewport
|
||||
bottom: function _isWithin_bottom() {
|
||||
var containerHeight = 0;
|
||||
|
||||
if (isContainerTheWindow) {
|
||||
if (canUseWindowDimensions) {
|
||||
containerHeight = config.container.innerHeight;
|
||||
} else if (document && document.documentElement) {
|
||||
containerHeight = document.documentElement.clientHeight;
|
||||
}
|
||||
} else {
|
||||
containerHeight = containerBoundingRect.bottom;
|
||||
}
|
||||
|
||||
// Note that `elemBoundingRect.bottom` is the distance from the *top* of the viewport to the element's bottom edge
|
||||
return (elemBoundingRect.bottom <= containerHeight - scrollBarWidths[1] - config.bottom);
|
||||
},
|
||||
|
||||
// Element is to the right of the left edge of the viewport
|
||||
left: function _isWithin_left() {
|
||||
if (isContainerTheWindow) {
|
||||
return (elemBoundingRect.left >= config.left);
|
||||
} else {
|
||||
return (elemBoundingRect.left >= containerScrollLeft - (containerScrollLeft - containerBoundingRect.left) + config.left);
|
||||
}
|
||||
},
|
||||
|
||||
// Element is within all four boundaries
|
||||
all: function _isWithin_all() {
|
||||
// Test each boundary in order of efficiency and likeliness to be false. This way we can avoid running all four functions on most elements.
|
||||
// 1. Top: Quickest to calculate + most likely to be false
|
||||
// 2. Bottom: Note quite as quick to calculate, but also very likely to be false
|
||||
// 3-4. Left and right are both equally unlikely to be false since most sites only scroll vertically, but left is faster to calculate
|
||||
return (isWithin.top() && isWithin.bottom() && isWithin.left() && isWithin.right());
|
||||
}
|
||||
};
|
||||
|
||||
// Get the element's bounding rectangle with respect to the viewport
|
||||
elemBoundingRect = elem.getBoundingClientRect();
|
||||
|
||||
// Get viewport dimensions and offsets
|
||||
if (isContainerTheWindow) {
|
||||
containerBoundingRect = document.documentElement.getBoundingClientRect();
|
||||
containerScrollTop = document.body.scrollTop;
|
||||
containerScrollLeft = window.scrollX || document.body.scrollLeft;
|
||||
} else {
|
||||
containerBoundingRect = config.container.getBoundingClientRect();
|
||||
containerScrollTop = config.container.scrollTop;
|
||||
containerScrollLeft = config.container.scrollLeft;
|
||||
}
|
||||
|
||||
// Don't count the space consumed by scrollbars
|
||||
if (containerScrollLeft) {
|
||||
scrollBarWidths[0] = 18;
|
||||
}
|
||||
|
||||
if (containerScrollTop) {
|
||||
scrollBarWidths[1] = 16;
|
||||
}
|
||||
|
||||
// Test the element against each side of the viewport that was requested
|
||||
sideNamesPattern = /^top$|^right$|^bottom$|^left$|^all$/;
|
||||
|
||||
// Loop through all of the sides
|
||||
sides = config.sides.split(' ');
|
||||
i = sides.length;
|
||||
|
||||
while (i--) {
|
||||
side = sides[i].toLowerCase();
|
||||
|
||||
if (sideNamesPattern.test(side)) {
|
||||
if (isWithin[side]()) {
|
||||
result = true;
|
||||
} else {
|
||||
result = false;
|
||||
|
||||
// Quit as soon as the first failure is found
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// Default settings
|
||||
withinviewport.prototype.defaults = {
|
||||
container: typeof document !== 'undefined' ? document.body : {},
|
||||
sides: 'all',
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0
|
||||
};
|
||||
|
||||
withinviewport.defaults = withinviewport.prototype.defaults;
|
||||
|
||||
/**
|
||||
* Optional enhancements and shortcuts
|
||||
*
|
||||
* @description Uncomment or comment these pieces as they apply to your project and coding preferences
|
||||
*/
|
||||
|
||||
// Shortcut methods for each side of the viewport
|
||||
// Example: `withinviewport.top(elem)` is the same as `withinviewport(elem, 'top')`
|
||||
withinviewport.prototype.top = function _withinviewport_top(element) {
|
||||
return withinviewport(element, 'top');
|
||||
};
|
||||
|
||||
withinviewport.prototype.right = function _withinviewport_right(element) {
|
||||
return withinviewport(element, 'right');
|
||||
};
|
||||
|
||||
withinviewport.prototype.bottom = function _withinviewport_bottom(element) {
|
||||
return withinviewport(element, 'bottom');
|
||||
};
|
||||
|
||||
withinviewport.prototype.left = function _withinviewport_left(element) {
|
||||
return withinviewport(element, 'left');
|
||||
};
|
||||
|
||||
return withinviewport;
|
||||
}));
|
||||
Loading…
Add table
Add a link
Reference in a new issue