Skip to content

Commit d43ab69

Browse files
authored
[PYT-191] Refactor right side menu and update its styles (Lightning-AI#53)
1 parent 32d8915 commit d43ab69

File tree

9 files changed

+620
-306
lines changed

9 files changed

+620
-306
lines changed

js/_utilities.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
window.utilities = {
2+
scrollTop: function() {
3+
var supportPageOffset = window.pageXOffset !== undefined;
4+
var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
5+
var scrollLeft = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
6+
return supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
7+
},
8+
9+
// Modified from https://stackoverflow.com/a/27078401
10+
throttle: function(func, wait, options) {
11+
var context, args, result;
12+
var timeout = null;
13+
var previous = 0;
14+
if (!options) options = {};
15+
var later = function() {
16+
previous = options.leading === false ? 0 : Date.now();
17+
timeout = null;
18+
result = func.apply(context, args);
19+
if (!timeout) context = args = null;
20+
};
21+
return function() {
22+
var now = Date.now();
23+
if (!previous && options.leading === false) previous = now;
24+
var remaining = wait - (now - previous);
25+
context = this;
26+
args = arguments;
27+
if (remaining <= 0 || remaining > wait) {
28+
if (timeout) {
29+
clearTimeout(timeout);
30+
timeout = null;
31+
}
32+
previous = now;
33+
result = func.apply(context, args);
34+
if (!timeout) context = args = null;
35+
} else if (!timeout && options.trailing !== false) {
36+
timeout = setTimeout(later, remaining);
37+
}
38+
return result;
39+
};
40+
},
41+
42+
closest: function (el, selector) {
43+
var matchesFn;
44+
45+
// find vendor prefix
46+
['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
47+
if (typeof document.body[fn] == 'function') {
48+
matchesFn = fn;
49+
return true;
50+
}
51+
return false;
52+
});
53+
54+
var parent;
55+
56+
// traverse parents
57+
while (el) {
58+
parent = el.parentElement;
59+
if (parent && parent[matchesFn](selector)) {
60+
return parent;
61+
}
62+
el = parent;
63+
}
64+
65+
return null;
66+
},
67+
68+
// Modified from https://stackoverflow.com/a/18953277
69+
offset: function(elem) {
70+
if (!elem) {
71+
return;
72+
}
73+
74+
rect = elem.getBoundingClientRect();
75+
76+
// Make sure element is not hidden (display: none) or disconnected
77+
if (rect.width || rect.height || elem.getClientRects().length) {
78+
var doc = elem.ownerDocument;
79+
var docElem = doc.documentElement;
80+
81+
return {
82+
top: rect.top + window.pageYOffset - docElem.clientTop,
83+
left: rect.left + window.pageXOffset - docElem.clientLeft
84+
};
85+
}
86+
},
87+
88+
headersHeight: function() {
89+
return document.getElementById("header-holder").offsetHeight +
90+
document.getElementById("pytorch-page-level-bar").offsetHeight;
91+
}
92+
}

js/highlight-navigation.js

Lines changed: 51 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,71 @@
1-
// Modified from https://stackoverflow.com/a/27078401
2-
window.pyTorchThrottle = function(func, wait, options) {
3-
var context, args, result;
4-
var timeout = null;
5-
var previous = 0;
6-
if (!options) options = {};
7-
var later = function() {
8-
previous = options.leading === false ? 0 : Date.now();
9-
timeout = null;
10-
result = func.apply(context, args);
11-
if (!timeout) context = args = null;
12-
};
13-
return function() {
14-
var now = Date.now();
15-
if (!previous && options.leading === false) previous = now;
16-
var remaining = wait - (now - previous);
17-
context = this;
18-
args = arguments;
19-
if (remaining <= 0 || remaining > wait) {
20-
if (timeout) {
21-
clearTimeout(timeout);
22-
timeout = null;
23-
}
24-
previous = now;
25-
result = func.apply(context, args);
26-
if (!timeout) context = args = null;
27-
} else if (!timeout && options.trailing !== false) {
28-
timeout = setTimeout(later, remaining);
29-
}
30-
return result;
31-
};
32-
};
33-
341
// Modified from https://stackoverflow.com/a/32396543
352
window.highlightNavigation = {
36-
navigationListItems: $(".pytorch-right-menu li"),
37-
sections: $(
38-
$(".pytorch-article .section")
39-
.get()
40-
.reverse()
41-
),
3+
navigationListItems: document.querySelectorAll("#pytorch-right-menu li"),
4+
sections: document.querySelectorAll(".pytorch-article .section"),
425
sectionIdTonavigationLink: {},
436

447
bind: function() {
45-
// Don't show the "Shortcuts" text unless there are menu items
46-
if (highlightNavigation.navigationListItems.length > 1) {
47-
$(".pytorch-shortcuts-wrapper").show();
48-
}
8+
if (!sideMenus.displayRightMenu) {
9+
return;
10+
};
4911

50-
highlightNavigation.sections.each(function() {
51-
var id = $(this).attr("id");
52-
highlightNavigation.sectionIdTonavigationLink[id] = $(
53-
".pytorch-right-menu li a[href='#" + id + "']"
54-
);
55-
});
12+
for (var i = 0; i < highlightNavigation.sections.length; i++) {
13+
var id = highlightNavigation.sections[i].id;
14+
highlightNavigation.sectionIdTonavigationLink[id] =
15+
document.querySelectorAll('#pytorch-right-menu li a[href="#' + id + '"]')[0];
16+
}
5617

57-
$(window).scroll(pyTorchThrottle(highlightNavigation.highlight, 500));
18+
$(window).scroll(utilities.throttle(highlightNavigation.highlight, 100));
5819
},
5920

6021
highlight: function() {
61-
var scrollPosition = $(window).scrollTop();
62-
var offset = $(".header-holder").height() + $(".pytorch-page-level-bar").height() + 25;
22+
var rightMenu = document.getElementById("pytorch-right-menu");
6323

64-
highlightNavigation.sections.each(function() {
65-
var currentSection = $(this);
66-
var sectionTop = currentSection.offset().top;
24+
// If right menu is not on the screen don't bother
25+
if (rightMenu.offsetWidth === 0 && rightMenu.offsetHeight === 0) {
26+
return;
27+
}
6728

68-
if (scrollPosition >= sectionTop - offset) {
69-
var id = currentSection.attr("id");
70-
var $navigationLink = highlightNavigation.sectionIdTonavigationLink[id];
71-
var $navigationListItem = $navigationLink.closest("li");
29+
var scrollPosition = utilities.scrollTop();
30+
var OFFSET_TOP_PADDING = 25;
31+
var offset = document.getElementById("header-holder").offsetHeight +
32+
document.getElementById("pytorch-page-level-bar").offsetHeight +
33+
OFFSET_TOP_PADDING;
7234

73-
if (!$navigationListItem.hasClass("active")) {
74-
highlightNavigation.navigationListItems.removeClass("active");
75-
$(".pytorch-right-menu-active-dot").remove();
35+
var sections = highlightNavigation.sections;
7636

77-
if ($navigationLink.is(":visible")) {
78-
$navigationListItem.addClass("active");
79-
$navigationListItem.prepend("<div class=\"pytorch-right-menu-active-dot\"></div>");
37+
for (var i = (sections.length - 1); i >= 0; i--) {
38+
var currentSection = sections[i];
39+
var sectionTop = utilities.offset(currentSection).top;
40+
41+
if (scrollPosition >= sectionTop - offset) {
42+
var navigationLink = highlightNavigation.sectionIdTonavigationLink[currentSection.id];
43+
var navigationListItem = utilities.closest(navigationLink, "li");
44+
45+
if (navigationListItem && !navigationListItem.classList.contains("active")) {
46+
for (var i = 0; i < highlightNavigation.navigationListItems.length; i++) {
47+
var el = highlightNavigation.navigationListItems[i];
48+
if (el.classList.contains("active")) {
49+
el.classList.remove("active");
50+
}
8051
}
52+
53+
navigationListItem.classList.add("active");
54+
55+
// Scroll to active item. Not a requested feature but we could revive it. Needs work.
56+
57+
// var menuTop = $("#pytorch-right-menu").position().top;
58+
// var itemTop = navigationListItem.getBoundingClientRect().top;
59+
// var TOP_PADDING = 20
60+
// var newActiveTop = $("#pytorch-side-scroll-right").scrollTop() + itemTop - menuTop - TOP_PADDING;
61+
62+
// $("#pytorch-side-scroll-right").animate({
63+
// scrollTop: newActiveTop
64+
// }, 100);
8165
}
8266

83-
return false;
67+
break;
8468
}
85-
});
69+
}
8670
}
8771
};

js/scroll-to-anchor.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,21 @@ window.scrollToAnchor = {
1212
var anchorScrolls = {
1313
ANCHOR_REGEX: /^#[^ ]+$/,
1414
offsetHeightPx: function() {
15-
return $(".header-holder").height() + $(".pytorch-page-level-bar").height() + 20;
15+
var OFFSET_HEIGHT_PADDING = 20;
16+
return document.getElementById("header-holder").offsetHeight +
17+
document.getElementById("pytorch-page-level-bar").offsetHeight +
18+
OFFSET_HEIGHT_PADDING;
1619
},
1720

1821
/**
1922
* Establish events, and fix initial scroll position if a hash is provided.
2023
*/
2124
init: function() {
2225
this.scrollToCurrent();
23-
$(window).on('hashchange', $.proxy(this, 'scrollToCurrent'));
26+
// This interferes with clicks below it, causing a double fire
27+
// $(window).on('hashchange', $.proxy(this, 'scrollToCurrent'));
2428
$('body').on('click', 'a', $.proxy(this, 'delegateAnchors'));
29+
$('body').on('click', '#pytorch-right-menu li span', $.proxy(this, 'delegateSpans'));
2530
},
2631

2732
/**
@@ -48,7 +53,8 @@ window.scrollToAnchor = {
4853
match = document.getElementById(href.slice(1));
4954

5055
if(match) {
51-
anchorOffset = $(match).offset().top - this.getFixedOffset();
56+
var anchorOffset = $(match).offset().top - this.getFixedOffset();
57+
5258
$('html, body').scrollTop(anchorOffset);
5359

5460
// Add the state to history as-per normal anchor links
@@ -69,6 +75,14 @@ window.scrollToAnchor = {
6975
}
7076
},
7177

78+
delegateSpans: function(e) {
79+
var elem = utilities.closest(e.target, "a");
80+
81+
if(this.scrollIfAnchor(elem.getAttribute('href'), true)) {
82+
e.preventDefault();
83+
}
84+
},
85+
7286
/**
7387
* If the click event's target was an anchor, fix the scroll position.
7488
*/

0 commit comments

Comments
 (0)