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

277 lines
8 KiB
JavaScript
Raw Normal View History

2020-03-29 00:03:15 +03:00
/* eslint-disable indent */
/**
* Useful DOM utilities.
* @module components/dom
*/
/**
* Returns parent of element with specified attribute value.
2020-03-31 18:59:12 +03:00
* @param {HTMLElement} elem - Element whose parent need to find.
* @param {string} name - Attribute name.
2022-02-19 12:43:11 +03:00
* @param {mixed} [value] - Attribute value.
2020-03-31 18:59:12 +03:00
* @returns {HTMLElement} Parent with specified attribute value.
2020-03-29 00:03:15 +03:00
*/
export function parentWithAttribute(elem, name, value) {
while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) {
elem = elem.parentNode;
if (!elem || !elem.getAttribute) {
return null;
}
}
return elem;
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Returns parent of element with one of specified tag names.
2020-03-31 18:59:12 +03:00
* @param {HTMLElement} elem - Element whose parent need to find.
* @param {(string|Array)} tagNames - Tag name or array of tag names.
* @returns {HTMLElement} Parent with one of specified tag names.
2020-03-29 00:03:15 +03:00
*/
export function parentWithTag(elem, tagNames) {
// accept both string and array passed in
if (!Array.isArray(tagNames)) {
tagNames = [tagNames];
}
while (tagNames.indexOf(elem.tagName || '') === -1) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Returns _true_ if class list contains one of specified names.
2020-03-31 18:59:12 +03:00
* @param {DOMTokenList} classList - Class list.
* @param {Array} classNames - Array of class names.
* @returns {boolean} _true_ if class list contains one of specified names.
2020-03-29 00:03:15 +03:00
*/
2018-10-23 01:05:09 +03:00
function containsAnyClass(classList, classNames) {
2020-03-29 00:03:15 +03:00
for (let i = 0, length = classNames.length; i < length; i++) {
if (classList.contains(classNames[i])) {
return true;
}
}
return false;
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Returns parent of element with one of specified class names.
2020-03-31 18:59:12 +03:00
* @param {HTMLElement} elem - Element whose parent need to find.
* @param {(string|Array)} classNames - Class name or array of class names.
* @returns {HTMLElement} Parent with one of specified class names.
2020-03-29 00:03:15 +03:00
*/
export function parentWithClass(elem, classNames) {
// accept both string and array passed in
if (!Array.isArray(classNames)) {
classNames = [classNames];
}
while (!elem.classList || !containsAnyClass(elem.classList, classNames)) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
let supportsCaptureOption = false;
try {
2020-03-29 00:03:15 +03:00
const opts = Object.defineProperty({}, 'capture', {
// eslint-disable-next-line getter-return
get: function () {
supportsCaptureOption = true;
}
});
2020-05-04 12:44:12 +02:00
window.addEventListener('test', null, opts);
} catch (e) {
2020-02-16 03:44:43 +01:00
console.debug('error checking capture support');
}
2020-03-29 00:03:15 +03:00
/**
* Adds event listener to specified target.
2020-03-31 18:59:12 +03:00
* @param {EventTarget} target - Event target.
* @param {string} type - Event type.
* @param {function} handler - Event handler.
* @param {Object} [options] - Listener options.
2020-03-29 00:03:15 +03:00
*/
export function addEventListener(target, type, handler, options) {
let optionsOrCapture = options || {};
if (!supportsCaptureOption) {
optionsOrCapture = optionsOrCapture.capture;
}
target.addEventListener(type, handler, optionsOrCapture);
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Removes event listener from specified target.
2020-03-31 18:59:12 +03:00
* @param {EventTarget} target - Event target.
* @param {string} type - Event type.
* @param {function} handler - Event handler.
* @param {Object} [options] - Listener options.
2020-03-29 00:03:15 +03:00
*/
export function removeEventListener(target, type, handler, options) {
let optionsOrCapture = options || {};
if (!supportsCaptureOption) {
optionsOrCapture = optionsOrCapture.capture;
}
target.removeEventListener(type, handler, optionsOrCapture);
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Cached window size.
*/
let windowSize;
/**
* Flag of event listener bound.
*/
let windowSizeEventsBound;
/**
* Resets cached window size.
*/
2018-10-23 01:05:09 +03:00
function clearWindowSize() {
windowSize = null;
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Returns window size.
2020-03-31 18:59:12 +03:00
* @returns {Object} Window size.
2020-03-29 00:03:15 +03:00
*/
export function getWindowSize() {
if (!windowSize) {
windowSize = {
innerHeight: window.innerHeight,
innerWidth: window.innerWidth
};
if (!windowSizeEventsBound) {
windowSizeEventsBound = true;
2020-05-04 12:44:12 +02:00
addEventListener(window, 'orientationchange', clearWindowSize, { passive: true });
2020-03-29 00:03:15 +03:00
addEventListener(window, 'resize', clearWindowSize, { passive: true });
}
}
return windowSize;
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Standard screen widths.
*/
const standardWidths = [480, 720, 1280, 1440, 1920, 2560, 3840, 5120, 7680];
/**
* Returns screen width.
2020-03-31 18:59:12 +03:00
* @returns {number} Screen width.
2020-03-29 00:03:15 +03:00
*/
export function getScreenWidth() {
let width = window.innerWidth;
const height = window.innerHeight;
2020-03-08 19:08:07 +01:00
if (height > width) {
width = height * (16.0 / 9.0);
2020-03-08 19:08:07 +01:00
}
2020-07-30 19:42:30 +02:00
return standardWidths.sort(function (a, b) {
2020-03-08 19:08:07 +01:00
return Math.abs(width - a) - Math.abs(width - b);
})[0];
}
2020-03-29 00:03:15 +03:00
/**
* Name of animation end event.
*/
let _animationEvent;
2020-03-29 00:03:15 +03:00
/**
* Returns name of animation end event.
2020-03-31 18:59:12 +03:00
* @returns {string} Name of animation end event.
2020-03-29 00:03:15 +03:00
*/
export function whichAnimationEvent() {
if (_animationEvent) {
return _animationEvent;
}
2020-05-04 12:44:12 +02:00
const el = document.createElement('div');
2020-03-29 00:03:15 +03:00
const animations = {
2020-05-04 12:44:12 +02:00
'animation': 'animationend',
'OAnimation': 'oAnimationEnd',
'MozAnimation': 'animationend',
'WebkitAnimation': 'webkitAnimationEnd'
};
for (const t in animations) {
if (el.style[t] !== undefined) {
_animationEvent = animations[t];
return animations[t];
}
}
_animationEvent = 'animationend';
return _animationEvent;
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Returns name of animation cancel event.
2020-03-31 18:59:12 +03:00
* @returns {string} Name of animation cancel event.
2020-03-29 00:03:15 +03:00
*/
export function whichAnimationCancelEvent() {
return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel');
2018-10-23 01:05:09 +03:00
}
2020-03-29 00:03:15 +03:00
/**
* Name of transition end event.
*/
let _transitionEvent;
/**
* Returns name of transition end event.
2020-03-31 18:59:12 +03:00
* @returns {string} Name of transition end event.
2020-03-29 00:03:15 +03:00
*/
export function whichTransitionEvent() {
if (_transitionEvent) {
return _transitionEvent;
}
2020-05-04 12:44:12 +02:00
const el = document.createElement('div');
2020-03-29 00:03:15 +03:00
const transitions = {
2020-05-04 12:44:12 +02:00
'transition': 'transitionend',
'OTransition': 'oTransitionEnd',
'MozTransition': 'transitionend',
'WebkitTransition': 'webkitTransitionEnd'
};
for (const t in transitions) {
if (el.style[t] !== undefined) {
_transitionEvent = transitions[t];
return transitions[t];
2018-10-23 01:05:09 +03:00
}
}
_transitionEvent = 'transitionend';
return _transitionEvent;
}
2020-04-02 23:45:45 +02:00
/* eslint-enable indent */
export default {
parentWithAttribute: parentWithAttribute,
parentWithClass: parentWithClass,
parentWithTag: parentWithTag,
addEventListener: addEventListener,
removeEventListener: removeEventListener,
getWindowSize: getWindowSize,
getScreenWidth: getScreenWidth,
whichTransitionEvent: whichTransitionEvent,
whichAnimationEvent: whichAnimationEvent,
whichAnimationCancelEvent: whichAnimationCancelEvent
};