1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Migrate ScrollManger to ES6

This commit is contained in:
Dmitry Lyzo 2020-03-28 19:42:18 +03:00
parent 13bf66de54
commit cc66fb672c
2 changed files with 126 additions and 116 deletions

View file

@ -77,7 +77,8 @@
"src/components/filedownloader.js", "src/components/filedownloader.js",
"src/components/filesystem.js", "src/components/filesystem.js",
"src/components/input/keyboardnavigation.js", "src/components/input/keyboardnavigation.js",
"src/components/sanatizefilename.js" "src/components/sanatizefilename.js",
"src/components/scrollManager.js"
], ],
"plugins": ["@babel/plugin-transform-modules-amd"] "plugins": ["@babel/plugin-transform-modules-amd"]
}] }]

View file

@ -1,15 +1,23 @@
define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManager) { /* eslint-disable indent */
"use strict";
/**
* Module for controlling scroll behavior.
* @module components/scrollManager
*/
import dom from "dom";
import browser from "browser";
import layoutManager from "layoutManager";
/** /**
* Scroll time in ms. * Scroll time in ms.
*/ */
var ScrollTime = 270; const ScrollTime = 270;
/** /**
* Epsilon for comparing values. * Epsilon for comparing values.
*/ */
var Epsilon = 1e-6; const Epsilon = 1e-6;
// FIXME: Need to scroll to top of page to fully show the top menu. This can be solved by some marker of top most elements or their containers // FIXME: Need to scroll to top of page to fully show the top menu. This can be solved by some marker of top most elements or their containers
/** /**
@ -19,20 +27,20 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
* @return {number} minimum vertical scroll * @return {number} minimum vertical scroll
*/ */
function minimumScrollY() { function minimumScrollY() {
var topMenu = document.querySelector(".headerTop"); const topMenu = document.querySelector(".headerTop");
if (topMenu) { if (topMenu) {
return topMenu.clientHeight; return topMenu.clientHeight;
} }
return 0; return 0;
} }
var supportsSmoothScroll = "scrollBehavior" in document.documentElement.style; const supportsSmoothScroll = "scrollBehavior" in document.documentElement.style;
var supportsScrollToOptions = false; let supportsScrollToOptions = false;
try { try {
var elem = document.createElement("div"); const elem = document.createElement("div");
var opts = Object.defineProperty({}, "behavior", { const opts = Object.defineProperty({}, "behavior", {
// eslint-disable-next-line getter-return // eslint-disable-next-line getter-return
get: function () { get: function () {
supportsScrollToOptions = true; supportsScrollToOptions = true;
@ -47,9 +55,9 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Returns value clamped by range [min, max]. * Returns value clamped by range [min, max].
* *
* @param {number} value clamped value * @param {number} value - clamped value
* @param {number} min begining of range * @param {number} min - begining of range
* @param {number} max ending of range * @param {number} max - ending of range
* @return {number} clamped value * @return {number} clamped value
*/ */
function clamp(value, min, max) { function clamp(value, min, max) {
@ -60,15 +68,15 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
* Returns the required delta to fit range 1 into range 2. * Returns the required delta to fit range 1 into range 2.
* In case of range 1 is bigger than range 2 returns delta to fit most out of range part. * In case of range 1 is bigger than range 2 returns delta to fit most out of range part.
* *
* @param {number} begin1 begining of range 1 * @param {number} begin1 - begining of range 1
* @param {number} end1 ending of range 1 * @param {number} end1 - ending of range 1
* @param {number} begin2 begining of range 2 * @param {number} begin2 - begining of range 2
* @param {number} end2 ending of range 2 * @param {number} end2 - ending of range 2
* @return {number} delta: <0 move range1 to the left, >0 - to the right * @return {number} delta: <0 move range1 to the left, >0 - to the right
*/ */
function fitRange(begin1, end1, begin2, end2) { function fitRange(begin1, end1, begin2, end2) {
var delta1 = begin1 - begin2; const delta1 = begin1 - begin2;
var delta2 = end2 - end1; const delta2 = end2 - end1;
if (delta1 < 0 && delta1 < delta2) { if (delta1 < 0 && delta1 < delta2) {
return -delta1; return -delta1;
} else if (delta2 < 0) { } else if (delta2 < 0) {
@ -80,7 +88,7 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Ease value. * Ease value.
* *
* @param {number} t value in range [0, 1] * @param {number} t - value in range [0, 1]
* @return {number} eased value in range [0, 1] * @return {number} eased value in range [0, 1]
*/ */
function ease(t) { function ease(t) {
@ -100,41 +108,40 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
* *
* Tizen 5 Browser/Native: scrolls documentElement (and window); has a document.scrollingElement * Tizen 5 Browser/Native: scrolls documentElement (and window); has a document.scrollingElement
*/ */
function DocumentScroller() { class DocumentScroller {
}
DocumentScroller.prototype = {
get scrollLeft() { get scrollLeft() {
return window.pageXOffset; return window.pageXOffset;
}, }
set scrollLeft(val) { set scrollLeft(val) {
window.scroll(val, window.pageYOffset); window.scroll(val, window.pageYOffset);
}, }
get scrollTop() { get scrollTop() {
return window.pageYOffset; return window.pageYOffset;
}, }
set scrollTop(val) { set scrollTop(val) {
window.scroll(window.pageXOffset, val); window.scroll(window.pageXOffset, val);
}, }
get scrollWidth() { get scrollWidth() {
return Math.max(document.documentElement.scrollWidth, document.body.scrollWidth); return Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
}, }
get scrollHeight() { get scrollHeight() {
return Math.max(document.documentElement.scrollHeight, document.body.scrollHeight); return Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
}, }
get clientWidth() { get clientWidth() {
return Math.min(document.documentElement.clientWidth, document.body.clientWidth); return Math.min(document.documentElement.clientWidth, document.body.clientWidth);
}, }
get clientHeight() { get clientHeight() {
return Math.min(document.documentElement.clientHeight, document.body.clientHeight); return Math.min(document.documentElement.clientHeight, document.body.clientHeight);
}, }
getBoundingClientRect: function() { getBoundingClientRect() {
// Make valid viewport coordinates: documentElement.getBoundingClientRect returns rect of entire document relative to viewport // Make valid viewport coordinates: documentElement.getBoundingClientRect returns rect of entire document relative to viewport
return { return {
left: 0, left: 0,
@ -142,26 +149,29 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
width: this.clientWidth, width: this.clientWidth,
height: this.clientHeight height: this.clientHeight
}; };
}, }
scrollTo: function() { scrollTo() {
window.scrollTo.apply(window, arguments); window.scrollTo.apply(window, arguments);
} }
}; }
var documentScroller = new DocumentScroller(); /**
* Default (document) scroller.
*/
const documentScroller = new DocumentScroller();
/** /**
* Returns parent element that can be scrolled. If no such, returns documentElement. * Returns parent element that can be scrolled. If no such, returns documentElement.
* *
* @param {HTMLElement} element element for which parent is being searched * @param {HTMLElement} element - element for which parent is being searched
* @param {boolean} vertical search for vertical scrollable parent * @param {boolean} vertical - search for vertical scrollable parent
*/ */
function getScrollableParent(element, vertical) { function getScrollableParent(element, vertical) {
if (element) { if (element) {
var nameScroll = "scrollWidth"; let nameScroll = "scrollWidth";
var nameClient = "clientWidth"; let nameClient = "clientWidth";
var nameClass = "scrollX"; let nameClass = "scrollX";
if (vertical) { if (vertical) {
nameScroll = "scrollHeight"; nameScroll = "scrollHeight";
@ -169,7 +179,7 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
nameClass = "scrollY"; nameClass = "scrollY";
} }
var parent = element.parentElement; let parent = element.parentElement;
while (parent) { while (parent) {
// Skip 'emby-scroller' because it scrolls by itself // Skip 'emby-scroller' because it scrolls by itself
@ -187,20 +197,20 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* @typedef {Object} ScrollerData * @typedef {Object} ScrollerData
* @property {number} scrollPos current scroll position * @property {number} scrollPos - current scroll position
* @property {number} scrollSize scroll size * @property {number} scrollSize - scroll size
* @property {number} clientSize client size * @property {number} clientSize - client size
*/ */
/** /**
* Returns scroll data for specified orientation. * Returns scroll data for specified orientation.
* *
* @param {HTMLElement} scroller scroller * @param {HTMLElement} scroller - scroller
* @param {boolean} vertical vertical scroll data * @param {boolean} vertical - vertical scroll data
* @return {ScrollerData} scroll data * @return {ScrollerData} scroll data
*/ */
function getScrollerData(scroller, vertical) { function getScrollerData(scroller, vertical) {
var data = {}; let data = {};
if (!vertical) { if (!vertical) {
data.scrollPos = scroller.scrollLeft; data.scrollPos = scroller.scrollLeft;
@ -218,14 +228,14 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Returns position of child of scroller for specified orientation. * Returns position of child of scroller for specified orientation.
* *
* @param {HTMLElement} scroller scroller * @param {HTMLElement} scroller - scroller
* @param {HTMLElement} element child of scroller * @param {HTMLElement} element - child of scroller
* @param {boolean} vertical vertical scroll * @param {boolean} vertical - vertical scroll
* @return {number} child position * @return {number} child position
*/ */
function getScrollerChildPos(scroller, element, vertical) { function getScrollerChildPos(scroller, element, vertical) {
var elementRect = element.getBoundingClientRect(); const elementRect = element.getBoundingClientRect();
var scrollerRect = scroller.getBoundingClientRect(); const scrollerRect = scroller.getBoundingClientRect();
if (!vertical) { if (!vertical) {
return scroller.scrollLeft + elementRect.left - scrollerRect.left; return scroller.scrollLeft + elementRect.left - scrollerRect.left;
@ -237,21 +247,21 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Returns scroll position for element. * Returns scroll position for element.
* *
* @param {ScrollerData} scrollerData scroller data * @param {ScrollerData} scrollerData - scroller data
* @param {number} elementPos child element position * @param {number} elementPos - child element position
* @param {number} elementSize child element size * @param {number} elementSize - child element size
* @param {boolean} centered scroll to center * @param {boolean} centered - scroll to center
* @return {number} scroll position * @return {number} scroll position
*/ */
function calcScroll(scrollerData, elementPos, elementSize, centered) { function calcScroll(scrollerData, elementPos, elementSize, centered) {
var maxScroll = scrollerData.scrollSize - scrollerData.clientSize; const maxScroll = scrollerData.scrollSize - scrollerData.clientSize;
var scroll; let scroll;
if (centered) { if (centered) {
scroll = elementPos + (elementSize - scrollerData.clientSize) / 2; scroll = elementPos + (elementSize - scrollerData.clientSize) / 2;
} else { } else {
var delta = fitRange(elementPos, elementPos + elementSize - 1, scrollerData.scrollPos, scrollerData.scrollPos + scrollerData.clientSize - 1); const delta = fitRange(elementPos, elementPos + elementSize - 1, scrollerData.scrollPos, scrollerData.scrollPos + scrollerData.clientSize - 1);
scroll = scrollerData.scrollPos - delta; scroll = scrollerData.scrollPos - delta;
} }
@ -261,14 +271,14 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Calls scrollTo function in proper way. * Calls scrollTo function in proper way.
* *
* @param {HTMLElement} scroller scroller * @param {HTMLElement} scroller - scroller
* @param {ScrollToOptions} options scroll options * @param {ScrollToOptions} options - scroll options
*/ */
function scrollToHelper(scroller, options) { function scrollToHelper(scroller, options) {
if ("scrollTo" in scroller) { if ("scrollTo" in scroller) {
if (!supportsScrollToOptions) { if (!supportsScrollToOptions) {
var scrollX = (options.left !== undefined ? options.left : scroller.scrollLeft); const scrollX = (options.left !== undefined ? options.left : scroller.scrollLeft);
var scrollY = (options.top !== undefined ? options.top : scroller.scrollTop); const scrollY = (options.top !== undefined ? options.top : scroller.scrollTop);
scroller.scrollTo(scrollX, scrollY); scroller.scrollTo(scrollX, scrollY);
} else { } else {
scroller.scrollTo(options); scroller.scrollTo(options);
@ -286,14 +296,14 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Performs built-in scroll. * Performs built-in scroll.
* *
* @param {HTMLElement} xScroller horizontal scroller * @param {HTMLElement} xScroller - horizontal scroller
* @param {number} scrollX horizontal coordinate * @param {number} scrollX - horizontal coordinate
* @param {HTMLElement} yScroller vertical scroller * @param {HTMLElement} yScroller - vertical scroller
* @param {number} scrollY vertical coordinate * @param {number} scrollY - vertical coordinate
* @param {boolean} smooth smooth scrolling * @param {boolean} smooth - smooth scrolling
*/ */
function builtinScroll(xScroller, scrollX, yScroller, scrollY, smooth) { function builtinScroll(xScroller, scrollX, yScroller, scrollY, smooth) {
var scrollBehavior = smooth ? "smooth" : "instant"; const scrollBehavior = smooth ? "smooth" : "instant";
if (xScroller !== yScroller) { if (xScroller !== yScroller) {
scrollToHelper(xScroller, {left: scrollX, behavior: scrollBehavior}); scrollToHelper(xScroller, {left: scrollX, behavior: scrollBehavior});
@ -303,7 +313,7 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
} }
} }
var scrollTimer; let scrollTimer;
/** /**
* Resets scroll timer to stop scrolling. * Resets scroll timer to stop scrolling.
@ -316,29 +326,29 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Performs animated scroll. * Performs animated scroll.
* *
* @param {HTMLElement} xScroller horizontal scroller * @param {HTMLElement} xScroller - horizontal scroller
* @param {number} scrollX horizontal coordinate * @param {number} scrollX - horizontal coordinate
* @param {HTMLElement} yScroller vertical scroller * @param {HTMLElement} yScroller - vertical scroller
* @param {number} scrollY vertical coordinate * @param {number} scrollY - vertical coordinate
*/ */
function animateScroll(xScroller, scrollX, yScroller, scrollY) { function animateScroll(xScroller, scrollX, yScroller, scrollY) {
var ox = xScroller.scrollLeft; const ox = xScroller.scrollLeft;
var oy = yScroller.scrollTop; const oy = yScroller.scrollTop;
var dx = scrollX - ox; const dx = scrollX - ox;
var dy = scrollY - oy; const dy = scrollY - oy;
if (Math.abs(dx) < Epsilon && Math.abs(dy) < Epsilon) { if (Math.abs(dx) < Epsilon && Math.abs(dy) < Epsilon) {
return; return;
} }
var start; let start;
function scrollAnim(currentTimestamp) { function scrollAnim(currentTimestamp) {
start = start || currentTimestamp; start = start || currentTimestamp;
var k = Math.min(1, (currentTimestamp - start) / ScrollTime); let k = Math.min(1, (currentTimestamp - start) / ScrollTime);
if (k === 1) { if (k === 1) {
resetScrollTimer(); resetScrollTimer();
@ -348,8 +358,8 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
k = ease(k); k = ease(k);
var x = ox + dx*k; const x = ox + dx*k;
var y = oy + dy*k; const y = oy + dy*k;
builtinScroll(xScroller, x, yScroller, y, false); builtinScroll(xScroller, x, yScroller, y, false);
@ -362,11 +372,11 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Performs scroll. * Performs scroll.
* *
* @param {HTMLElement} xScroller horizontal scroller * @param {HTMLElement} xScroller - horizontal scroller
* @param {number} scrollX horizontal coordinate * @param {number} scrollX - horizontal coordinate
* @param {HTMLElement} yScroller vertical scroller * @param {HTMLElement} yScroller - vertical scroller
* @param {number} scrollY vertical coordinate * @param {number} scrollY - vertical coordinate
* @param {boolean} smooth smooth scrolling * @param {boolean} smooth - smooth scrolling
*/ */
function doScroll(xScroller, scrollX, yScroller, scrollY, smooth) { function doScroll(xScroller, scrollX, yScroller, scrollY, smooth) {
@ -403,26 +413,26 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Returns true if scroll manager is enabled. * Returns true if scroll manager is enabled.
*/ */
var isEnabled = function() { export function isEnabled() {
return layoutManager.tv; return layoutManager.tv;
}; }
/** /**
* Scrolls the document to a given position. * Scrolls the document to a given position.
* *
* @param {number} scrollX horizontal coordinate * @param {number} scrollX - horizontal coordinate
* @param {number} scrollY vertical coordinate * @param {number} scrollY - vertical coordinate
* @param {boolean} [smooth=false] smooth scrolling * @param {boolean} [smooth=false] - smooth scrolling
*/ */
var scrollTo = function(scrollX, scrollY, smooth) { export function scrollTo(scrollX, scrollY, smooth) {
smooth = !!smooth; smooth = !!smooth;
// Scroller is document itself by default // Scroller is document itself by default
var scroller = getScrollableParent(null, false); const scroller = getScrollableParent(null, false);
var xScrollerData = getScrollerData(scroller, false); const xScrollerData = getScrollerData(scroller, false);
var yScrollerData = getScrollerData(scroller, true); const yScrollerData = getScrollerData(scroller, true);
scrollX = clamp(Math.round(scrollX), 0, xScrollerData.scrollSize - xScrollerData.clientSize); scrollX = clamp(Math.round(scrollX), 0, xScrollerData.scrollSize - xScrollerData.clientSize);
scrollY = clamp(Math.round(scrollY), 0, yScrollerData.scrollSize - yScrollerData.clientSize); scrollY = clamp(Math.round(scrollY), 0, yScrollerData.scrollSize - yScrollerData.clientSize);
@ -433,39 +443,39 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
/** /**
* Scrolls the document to a given element. * Scrolls the document to a given element.
* *
* @param {HTMLElement} element target element of scroll task * @param {HTMLElement} element - target element of scroll task
* @param {boolean} [smooth=false] smooth scrolling * @param {boolean} [smooth=false] - smooth scrolling
*/ */
var scrollToElement = function(element, smooth) { export function scrollToElement(element, smooth) {
smooth = !!smooth; smooth = !!smooth;
var scrollCenterX = true; let scrollCenterX = true;
var scrollCenterY = true; let scrollCenterY = true;
var offsetParent = element.offsetParent; const offsetParent = element.offsetParent;
// In Firefox offsetParent.offsetParent is BODY // In Firefox offsetParent.offsetParent is BODY
var isFixed = offsetParent && (!offsetParent.offsetParent || window.getComputedStyle(offsetParent).position === "fixed"); const isFixed = offsetParent && (!offsetParent.offsetParent || window.getComputedStyle(offsetParent).position === "fixed");
// Scroll fixed elements to nearest edge (or do not scroll at all) // Scroll fixed elements to nearest edge (or do not scroll at all)
if (isFixed) { if (isFixed) {
scrollCenterX = scrollCenterY = false; scrollCenterX = scrollCenterY = false;
} }
var xScroller = getScrollableParent(element, false); const xScroller = getScrollableParent(element, false);
var yScroller = getScrollableParent(element, true); const yScroller = getScrollableParent(element, true);
var elementRect = element.getBoundingClientRect(); const elementRect = element.getBoundingClientRect();
var xScrollerData = getScrollerData(xScroller, false); const xScrollerData = getScrollerData(xScroller, false);
var yScrollerData = getScrollerData(yScroller, true); const yScrollerData = getScrollerData(yScroller, true);
var xPos = getScrollerChildPos(xScroller, element, false); const xPos = getScrollerChildPos(xScroller, element, false);
var yPos = getScrollerChildPos(yScroller, element, true); const yPos = getScrollerChildPos(yScroller, element, true);
var scrollX = calcScroll(xScrollerData, xPos, elementRect.width, scrollCenterX); const scrollX = calcScroll(xScrollerData, xPos, elementRect.width, scrollCenterX);
var scrollY = calcScroll(yScrollerData, yPos, elementRect.height, scrollCenterY); let scrollY = calcScroll(yScrollerData, yPos, elementRect.height, scrollCenterY);
// HACK: Scroll to top for top menu because it is hidden // HACK: Scroll to top for top menu because it is hidden
// FIXME: Need a marker to scroll top/bottom // FIXME: Need a marker to scroll top/bottom
@ -490,9 +500,8 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage
}, {capture: true}); }, {capture: true});
} }
return { export default {
isEnabled: isEnabled, isEnabled: isEnabled,
scrollTo: scrollTo, scrollTo: scrollTo,
scrollToElement: scrollToElement scrollToElement: scrollToElement
}; };
});