summaryrefslogtreecommitdiffstats
path: root/js
diff options
context:
space:
mode:
authorKohei Yoshino <kohei.yoshino@gmail.com>2018-01-08 15:22:45 +0100
committerDylan William Hardison <dylan@hardison.net>2018-01-08 15:22:45 +0100
commitf86567c1f22f5d4dfa9bcc097efaef3ecb8b44bc (patch)
treef760021037129b07d8fe2565e4972e64eab014fb /js
parent19e368ee6d070699e52c845c324143568f08444a (diff)
downloadbugzilla-f86567c1f22f5d4dfa9bcc097efaef3ecb8b44bc.tar.gz
bugzilla-f86567c1f22f5d4dfa9bcc097efaef3ecb8b44bc.tar.xz
Bug 1427800 - Wrong anchor scrolling with old UI
Diffstat (limited to 'js')
-rw-r--r--js/global.js58
1 files changed, 50 insertions, 8 deletions
diff --git a/js/global.js b/js/global.js
index 93f364c9e..68aceb03f 100644
--- a/js/global.js
+++ b/js/global.js
@@ -214,22 +214,64 @@ const detect_blocked_gravatars = () => {
}
/**
- * If the URL contains a hash like #c10, scroll down the page to show the
- * element below the fixed global header. This workaround is required for
- * comments on show_bug.cgi, components on describecomponents.cgi, etc.
+ * If the current URL contains a hash like `#c10`, adjust the scroll position to
+ * make some room above the focused element.
*/
-const scroll_element_into_view = () => {
+const adjust_scroll_onload = () => {
if (location.hash) {
- const $main = document.querySelector('main');
const $target = document.querySelector(location.hash);
if ($target) {
- window.setTimeout(() => $main.scrollTop = $target.offsetTop - 20, 50);
+ window.setTimeout(() => scroll_element_into_view($target), 50);
}
}
}
+/**
+ * Bring an element into the visible area of the browser window. Unlike the
+ * native `Element.scrollIntoView()` function, this adds some extra room above
+ * the target element. Smooth scroll can be done using CSS.
+ * @param {Element} $target - An element to be brought.
+ * @param {Function} [complete] - An optional callback function to be executed
+ * once the scroll is complete.
+ */
+const scroll_element_into_view = ($target, complete) => {
+ let top = 0;
+ let $element = $target;
+
+ // Traverse up in the DOM tree to the scroll container of the
+ // focused element, either `<main>` or `<div role="feed">`.
+ do {
+ top += ($element.offsetTop || 0);
+ $element = $element.offsetParent;
+ } while ($element && !$element.matches('main, [role="feed"]'))
+
+ if (!$element) {
+ return;
+ }
+
+ if (typeof complete === 'function') {
+ const callback = () => {
+ $element.removeEventListener('scroll', listener);
+ complete();
+ };
+
+ // Emulate the `scrollend` event
+ const listener = () => {
+ window.clearTimeout(timer);
+ timer = window.setTimeout(callback, 100);
+ };
+
+ // Make sure the callback is always fired even if no scroll happened
+ let timer = window.setTimeout(callback, 100);
+
+ $element.addEventListener('scroll', listener);
+ }
+
+ $element.scrollTop = top - 20;
+}
+
window.addEventListener('DOMContentLoaded', focus_main_content, { once: true });
window.addEventListener('load', detect_blocked_gravatars, { once: true });
-window.addEventListener('load', scroll_element_into_view, { once: true });
-window.addEventListener('hashchange', scroll_element_into_view);
+window.addEventListener('load', adjust_scroll_onload, { once: true });
+window.addEventListener('hashchange', adjust_scroll_onload);