diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-08-23 09:38:42 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-23 09:38:42 +0200 |
commit | c49ca3ba841ea7763148a76d9a84e1bf7f5698ad (patch) | |
tree | 7f49588f65540949da16846b06202dc7752c92e1 /server/sonar-web/src/main/js/helpers/scrolling.ts | |
parent | 008f13434b7a6ba482a5c9535708746627f32665 (diff) | |
download | sonarqube-c49ca3ba841ea7763148a76d9a84e1bf7f5698ad.tar.gz sonarqube-c49ca3ba841ea7763148a76d9a84e1bf7f5698ad.zip |
move some helpers to ts (#2399)
Diffstat (limited to 'server/sonar-web/src/main/js/helpers/scrolling.ts')
-rw-r--r-- | server/sonar-web/src/main/js/helpers/scrolling.ts | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/server/sonar-web/src/main/js/helpers/scrolling.ts b/server/sonar-web/src/main/js/helpers/scrolling.ts new file mode 100644 index 00000000000..a36c6ef0789 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/scrolling.ts @@ -0,0 +1,106 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { debounce } from 'lodash'; + +const SCROLLING_DURATION = 100; +const SCROLLING_INTERVAL = 10; +const SCROLLING_STEPS = SCROLLING_DURATION / SCROLLING_INTERVAL; + +function isWindow(element: HTMLElement | Window): element is Window { + return element === window; +} + +function getScrollPosition(element: HTMLElement | Window): number { + return isWindow(element) ? window.scrollY : element.scrollTop; +} + +function scrollElement(element: HTMLElement | Window, position: number): void { + if (isWindow(element)) { + window.scrollTo(0, position); + } else { + element.scrollTop = position; + } +} + +let smoothScrollTop = (y: number, parent: HTMLElement | Window) => { + let scrollTop = getScrollPosition(parent); + const scrollingDown = y > scrollTop; + const step = Math.ceil(Math.abs(y - scrollTop) / SCROLLING_STEPS); + let stepsDone = 0; + + const interval = setInterval(() => { + if (scrollTop === y || SCROLLING_STEPS === stepsDone) { + clearInterval(interval); + } else { + let goal; + if (scrollingDown) { + goal = Math.min(y, scrollTop + step); + } else { + goal = Math.max(y, scrollTop - step); + } + stepsDone++; + scrollTop = goal; + scrollElement(parent, goal); + } + }, SCROLLING_INTERVAL); +}; + +smoothScrollTop = debounce(smoothScrollTop, SCROLLING_DURATION, { leading: true }); + +export function scrollToElement( + element: HTMLElement, + options: { + topOffset?: number; + bottomOffset?: number; + parent?: HTMLElement; + smooth?: boolean; + } +): void { + const opts = { topOffset: 0, bottomOffset: 0, parent: window, smooth: true, ...options }; + const { parent } = opts; + + const { top, bottom } = element.getBoundingClientRect(); + + const scrollTop = getScrollPosition(parent); + + const height: number = isWindow(parent) + ? window.innerHeight + : parent.getBoundingClientRect().height; + + const parentTop = isWindow(parent) ? 0 : parent.getBoundingClientRect().top; + + if (top - parentTop < opts.topOffset) { + const goal = scrollTop - opts.topOffset + top - parentTop; + if (opts.smooth) { + smoothScrollTop(goal, parent); + } else { + scrollElement(parent, goal); + } + } + + if (bottom - parentTop > height - opts.bottomOffset) { + const goal = scrollTop + bottom - parentTop - height + opts.bottomOffset; + if (opts.smooth) { + smoothScrollTop(goal, parent); + } else { + scrollElement(parent, goal); + } + } +} |