mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge remote-tracking branch 'upstream/master' into global-globalize
This commit is contained in:
commit
0117bf476a
94 changed files with 1215 additions and 469 deletions
|
@ -1,130 +0,0 @@
|
|||
define(['dom', 'focusManager'], function (dom, focusManager) {
|
||||
'use strict';
|
||||
|
||||
var inputDisplayElement;
|
||||
var currentDisplayText = '';
|
||||
var currentDisplayTextContainer;
|
||||
|
||||
function onKeyDown(e) {
|
||||
|
||||
if (e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
if (e.shiftKey) {
|
||||
return;
|
||||
}
|
||||
if (e.altKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = e.key;
|
||||
var chr = key ? alphanumeric(key) : null;
|
||||
|
||||
if (chr) {
|
||||
|
||||
chr = chr.toString().toUpperCase();
|
||||
|
||||
if (chr.length === 1) {
|
||||
currentDisplayTextContainer = this.options.itemsContainer;
|
||||
onAlphanumericKeyPress(e, chr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function alphanumeric(value) {
|
||||
var letterNumber = /^[0-9a-zA-Z]+$/;
|
||||
return value.match(letterNumber);
|
||||
}
|
||||
|
||||
function ensureInputDisplayElement() {
|
||||
if (!inputDisplayElement) {
|
||||
inputDisplayElement = document.createElement('div');
|
||||
inputDisplayElement.classList.add('alphanumeric-shortcut');
|
||||
inputDisplayElement.classList.add('hide');
|
||||
|
||||
document.body.appendChild(inputDisplayElement);
|
||||
}
|
||||
}
|
||||
|
||||
var alpanumericShortcutTimeout;
|
||||
function clearAlphaNumericShortcutTimeout() {
|
||||
if (alpanumericShortcutTimeout) {
|
||||
clearTimeout(alpanumericShortcutTimeout);
|
||||
alpanumericShortcutTimeout = null;
|
||||
}
|
||||
}
|
||||
function resetAlphaNumericShortcutTimeout() {
|
||||
clearAlphaNumericShortcutTimeout();
|
||||
alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2000);
|
||||
}
|
||||
|
||||
function onAlphanumericKeyPress(e, chr) {
|
||||
if (currentDisplayText.length >= 3) {
|
||||
return;
|
||||
}
|
||||
ensureInputDisplayElement();
|
||||
currentDisplayText += chr;
|
||||
inputDisplayElement.innerHTML = currentDisplayText;
|
||||
inputDisplayElement.classList.remove('hide');
|
||||
resetAlphaNumericShortcutTimeout();
|
||||
}
|
||||
|
||||
function onAlphanumericShortcutTimeout() {
|
||||
var value = currentDisplayText;
|
||||
var container = currentDisplayTextContainer;
|
||||
|
||||
currentDisplayText = '';
|
||||
currentDisplayTextContainer = null;
|
||||
inputDisplayElement.innerHTML = '';
|
||||
inputDisplayElement.classList.add('hide');
|
||||
clearAlphaNumericShortcutTimeout();
|
||||
selectByShortcutValue(container, value);
|
||||
}
|
||||
|
||||
function selectByShortcutValue(container, value) {
|
||||
|
||||
value = value.toUpperCase();
|
||||
|
||||
var focusElem;
|
||||
if (value === '#') {
|
||||
|
||||
focusElem = container.querySelector('*[data-prefix]');
|
||||
}
|
||||
|
||||
if (!focusElem) {
|
||||
focusElem = container.querySelector('*[data-prefix^=\'' + value + '\']');
|
||||
}
|
||||
|
||||
if (focusElem) {
|
||||
focusManager.focus(focusElem);
|
||||
}
|
||||
}
|
||||
|
||||
function AlphaNumericShortcuts(options) {
|
||||
|
||||
this.options = options;
|
||||
|
||||
var keyDownHandler = onKeyDown.bind(this);
|
||||
|
||||
dom.addEventListener(window, 'keydown', keyDownHandler, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
this.keyDownHandler = keyDownHandler;
|
||||
}
|
||||
|
||||
AlphaNumericShortcuts.prototype.destroy = function () {
|
||||
|
||||
var keyDownHandler = this.keyDownHandler;
|
||||
|
||||
if (keyDownHandler) {
|
||||
dom.removeEventListener(window, 'keydown', keyDownHandler, {
|
||||
passive: true
|
||||
});
|
||||
this.keyDownHandler = null;
|
||||
}
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return AlphaNumericShortcuts;
|
||||
});
|
|
@ -346,7 +346,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper", "webSettings", "g
|
|||
var deviceId;
|
||||
var deviceName;
|
||||
var appName = "Jellyfin Web";
|
||||
var appVersion = "10.5.0";
|
||||
var appVersion = "10.6.0";
|
||||
|
||||
var appHost = {
|
||||
getWindowState: function () {
|
||||
|
|
|
@ -1,278 +0,0 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Useful DOM utilities.
|
||||
* @module components/dom
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns parent of element with specified attribute value.
|
||||
* @param {HTMLElement} elem - Element whose parent need to find.
|
||||
* @param {string} name - Attribute name.
|
||||
* @param {mixed} value - Attribute value.
|
||||
* @returns {HTMLElement} Parent with specified attribute value.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parent of element with one of specified tag names.
|
||||
* @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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns _true_ if class list contains one of specified names.
|
||||
* @param {DOMTokenList} classList - Class list.
|
||||
* @param {Array} classNames - Array of class names.
|
||||
* @returns {boolean} _true_ if class list contains one of specified names.
|
||||
*/
|
||||
function containsAnyClass(classList, classNames) {
|
||||
for (let i = 0, length = classNames.length; i < length; i++) {
|
||||
if (classList.contains(classNames[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parent of element with one of specified class names.
|
||||
* @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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
let supportsCaptureOption = false;
|
||||
try {
|
||||
const opts = Object.defineProperty({}, 'capture', {
|
||||
// eslint-disable-next-line getter-return
|
||||
get: function () {
|
||||
supportsCaptureOption = true;
|
||||
}
|
||||
});
|
||||
window.addEventListener("test", null, opts);
|
||||
} catch (e) {
|
||||
console.debug('error checking capture support');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds event listener to specified target.
|
||||
* @param {EventTarget} target - Event target.
|
||||
* @param {string} type - Event type.
|
||||
* @param {function} handler - Event handler.
|
||||
* @param {Object} [options] - Listener options.
|
||||
*/
|
||||
export function addEventListener(target, type, handler, options) {
|
||||
let optionsOrCapture = options || {};
|
||||
if (!supportsCaptureOption) {
|
||||
optionsOrCapture = optionsOrCapture.capture;
|
||||
}
|
||||
target.addEventListener(type, handler, optionsOrCapture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes event listener from specified target.
|
||||
* @param {EventTarget} target - Event target.
|
||||
* @param {string} type - Event type.
|
||||
* @param {function} handler - Event handler.
|
||||
* @param {Object} [options] - Listener options.
|
||||
*/
|
||||
export function removeEventListener(target, type, handler, options) {
|
||||
let optionsOrCapture = options || {};
|
||||
if (!supportsCaptureOption) {
|
||||
optionsOrCapture = optionsOrCapture.capture;
|
||||
}
|
||||
target.removeEventListener(type, handler, optionsOrCapture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached window size.
|
||||
*/
|
||||
let windowSize;
|
||||
|
||||
/**
|
||||
* Flag of event listener bound.
|
||||
*/
|
||||
let windowSizeEventsBound;
|
||||
|
||||
/**
|
||||
* Resets cached window size.
|
||||
*/
|
||||
function clearWindowSize() {
|
||||
windowSize = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns window size.
|
||||
* @returns {Object} Window size.
|
||||
*/
|
||||
export function getWindowSize() {
|
||||
if (!windowSize) {
|
||||
windowSize = {
|
||||
innerHeight: window.innerHeight,
|
||||
innerWidth: window.innerWidth
|
||||
};
|
||||
|
||||
if (!windowSizeEventsBound) {
|
||||
windowSizeEventsBound = true;
|
||||
addEventListener(window, "orientationchange", clearWindowSize, { passive: true });
|
||||
addEventListener(window, 'resize', clearWindowSize, { passive: true });
|
||||
}
|
||||
}
|
||||
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard screen widths.
|
||||
*/
|
||||
const standardWidths = [480, 720, 1280, 1440, 1920, 2560, 3840, 5120, 7680];
|
||||
|
||||
/**
|
||||
* Returns screen width.
|
||||
* @returns {number} Screen width.
|
||||
*/
|
||||
export function getScreenWidth() {
|
||||
let width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
|
||||
if (height > width) {
|
||||
width = height * (16.0 / 9.0);
|
||||
}
|
||||
|
||||
const closest = standardWidths.sort(function (a, b) {
|
||||
return Math.abs(width - a) - Math.abs(width - b);
|
||||
})[0];
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of animation end event.
|
||||
*/
|
||||
let _animationEvent;
|
||||
|
||||
/**
|
||||
* Returns name of animation end event.
|
||||
* @returns {string} Name of animation end event.
|
||||
*/
|
||||
export function whichAnimationEvent() {
|
||||
if (_animationEvent) {
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
const el = document.createElement("div");
|
||||
const animations = {
|
||||
"animation": "animationend",
|
||||
"OAnimation": "oAnimationEnd",
|
||||
"MozAnimation": "animationend",
|
||||
"WebkitAnimation": "webkitAnimationEnd"
|
||||
};
|
||||
for (let t in animations) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_animationEvent = animations[t];
|
||||
return animations[t];
|
||||
}
|
||||
}
|
||||
|
||||
_animationEvent = 'animationend';
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of animation cancel event.
|
||||
* @returns {string} Name of animation cancel event.
|
||||
*/
|
||||
export function whichAnimationCancelEvent() {
|
||||
return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of transition end event.
|
||||
*/
|
||||
let _transitionEvent;
|
||||
|
||||
/**
|
||||
* Returns name of transition end event.
|
||||
* @returns {string} Name of transition end event.
|
||||
*/
|
||||
export function whichTransitionEvent() {
|
||||
if (_transitionEvent) {
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
const el = document.createElement("div");
|
||||
const transitions = {
|
||||
"transition": "transitionend",
|
||||
"OTransition": "oTransitionEnd",
|
||||
"MozTransition": "transitionend",
|
||||
"WebkitTransition": "webkitTransitionEnd"
|
||||
};
|
||||
for (let t in transitions) {
|
||||
if (el.style[t] !== undefined) {
|
||||
_transitionEvent = transitions[t];
|
||||
return transitions[t];
|
||||
}
|
||||
}
|
||||
|
||||
_transitionEvent = 'transitionend';
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
/* 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
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
export function fileExists(path) {
|
||||
if (window.NativeShell && window.NativeShell.FileSystem) {
|
||||
return window.NativeShell.FileSystem.fileExists(path);
|
||||
}
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
export function directoryExists(path) {
|
||||
if (window.NativeShell && window.NativeShell.FileSystem) {
|
||||
return window.NativeShell.FileSystem.directoryExists(path);
|
||||
}
|
||||
return Promise.reject();
|
||||
}
|
|
@ -64,7 +64,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
|||
} else {
|
||||
var noLibDescription;
|
||||
if (user['Policy'] && user['Policy']['IsAdministrator']) {
|
||||
noLibDescription = globalize.translate("NoCreatedLibraries", '<a id="button-createLibrary" class="button-link">', '</a>');
|
||||
noLibDescription = globalize.translate("NoCreatedLibraries", '<br><a id="button-createLibrary" class="button-link">', '</a>');
|
||||
} else {
|
||||
noLibDescription = globalize.translate("AskAdminToCreateLibrary");
|
||||
}
|
||||
|
@ -243,9 +243,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
|||
return function (items) {
|
||||
var cardLayout = false;
|
||||
var shape;
|
||||
if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books') {
|
||||
if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books' || viewType === 'tvshows') {
|
||||
shape = getPortraitShape();
|
||||
} else if (viewType === 'music') {
|
||||
} else if (viewType === 'music' || viewType === 'homevideos') {
|
||||
shape = getSquareShape();
|
||||
} else {
|
||||
shape = getThumbShape();
|
||||
|
|
|
@ -795,7 +795,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
|||
dlg.parentNode.removeChild(dlg);
|
||||
}
|
||||
|
||||
screenfull.exit();
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.exit();
|
||||
}
|
||||
};
|
||||
|
||||
function onEnded() {
|
||||
|
|
|
@ -1,410 +0,0 @@
|
|||
// # The MIT License (MIT)
|
||||
// #
|
||||
// # Copyright (c) 2016 Microsoft. All rights reserved.
|
||||
// #
|
||||
// # Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// # of this software and associated documentation files (the "Software"), to deal
|
||||
// # in the Software without restriction, including without limitation the rights
|
||||
// # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// # copies of the Software, and to permit persons to whom the Software is
|
||||
// # furnished to do so, subject to the following conditions:
|
||||
// #
|
||||
// # The above copyright notice and this permission notice shall be included in
|
||||
// # all copies or substantial portions of the Software.
|
||||
// #
|
||||
// # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// # THE SOFTWARE.
|
||||
require(['apphost'], function (appHost) {
|
||||
"use strict";
|
||||
|
||||
var _GAMEPAD_A_BUTTON_INDEX = 0;
|
||||
var _GAMEPAD_B_BUTTON_INDEX = 1;
|
||||
var _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12;
|
||||
var _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13;
|
||||
var _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14;
|
||||
var _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15;
|
||||
var _GAMEPAD_A_KEY = "GamepadA";
|
||||
var _GAMEPAD_B_KEY = "GamepadB";
|
||||
var _GAMEPAD_DPAD_UP_KEY = "GamepadDPadUp";
|
||||
var _GAMEPAD_DPAD_DOWN_KEY = "GamepadDPadDown";
|
||||
var _GAMEPAD_DPAD_LEFT_KEY = "GamepadDPadLeft";
|
||||
var _GAMEPAD_DPAD_RIGHT_KEY = "GamepadDPadRight";
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = "GamepadLeftThumbStickUp";
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = "GamepadLeftThumbStickDown";
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = "GamepadLeftThumbStickLeft";
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = "GamepadLeftThumbStickRight";
|
||||
var _GAMEPAD_A_KEYCODE = 0;
|
||||
var _GAMEPAD_B_KEYCODE = 27;
|
||||
var _GAMEPAD_DPAD_UP_KEYCODE = 38;
|
||||
var _GAMEPAD_DPAD_DOWN_KEYCODE = 40;
|
||||
var _GAMEPAD_DPAD_LEFT_KEYCODE = 37;
|
||||
var _GAMEPAD_DPAD_RIGHT_KEYCODE = 39;
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE = 38;
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE = 40;
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE = 37;
|
||||
var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE = 39;
|
||||
var _THUMB_STICK_THRESHOLD = 0.75;
|
||||
|
||||
var _leftThumbstickUpPressed = false;
|
||||
var _leftThumbstickDownPressed = false;
|
||||
var _leftThumbstickLeftPressed = false;
|
||||
var _leftThumbstickRightPressed = false;
|
||||
var _dPadUpPressed = false;
|
||||
var _dPadDownPressed = false;
|
||||
var _dPadLeftPressed = false;
|
||||
var _dPadRightPressed = false;
|
||||
var _gamepadAPressed = false;
|
||||
var _gamepadBPressed = false;
|
||||
|
||||
// The set of buttons on the gamepad we listen for.
|
||||
var ProcessedButtons = [
|
||||
_GAMEPAD_DPAD_UP_BUTTON_INDEX,
|
||||
_GAMEPAD_DPAD_DOWN_BUTTON_INDEX,
|
||||
_GAMEPAD_DPAD_LEFT_BUTTON_INDEX,
|
||||
_GAMEPAD_DPAD_RIGHT_BUTTON_INDEX,
|
||||
_GAMEPAD_A_BUTTON_INDEX,
|
||||
_GAMEPAD_B_BUTTON_INDEX
|
||||
];
|
||||
|
||||
var _ButtonPressedState = {};
|
||||
_ButtonPressedState.getgamepadA = function () {
|
||||
return _gamepadAPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setgamepadA = function (newPressedState) {
|
||||
raiseKeyEvent(_gamepadAPressed, newPressedState, _GAMEPAD_A_KEY, _GAMEPAD_A_KEYCODE, false, true);
|
||||
_gamepadAPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getgamepadB = function () {
|
||||
return _gamepadBPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setgamepadB = function (newPressedState) {
|
||||
raiseKeyEvent(_gamepadBPressed, newPressedState, _GAMEPAD_B_KEY, _GAMEPAD_B_KEYCODE);
|
||||
_gamepadBPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getleftThumbstickUp = function () {
|
||||
return _leftThumbstickUpPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setleftThumbstickUp = function (newPressedState) {
|
||||
raiseKeyEvent(_leftThumbstickUpPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_UP_KEY, _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE, true);
|
||||
_leftThumbstickUpPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getleftThumbstickDown = function () {
|
||||
return _leftThumbstickDownPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setleftThumbstickDown = function (newPressedState) {
|
||||
raiseKeyEvent(_leftThumbstickDownPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE, true);
|
||||
_leftThumbstickDownPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getleftThumbstickLeft = function () {
|
||||
return _leftThumbstickLeftPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setleftThumbstickLeft = function (newPressedState) {
|
||||
raiseKeyEvent(_leftThumbstickLeftPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE, true);
|
||||
_leftThumbstickLeftPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getleftThumbstickRight = function () {
|
||||
return _leftThumbstickRightPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setleftThumbstickRight = function (newPressedState) {
|
||||
raiseKeyEvent(_leftThumbstickRightPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE, true);
|
||||
_leftThumbstickRightPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getdPadUp = function () {
|
||||
return _dPadUpPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setdPadUp = function (newPressedState) {
|
||||
raiseKeyEvent(_dPadUpPressed, newPressedState, _GAMEPAD_DPAD_UP_KEY, _GAMEPAD_DPAD_UP_KEYCODE, true);
|
||||
_dPadUpPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getdPadDown = function () {
|
||||
return _dPadDownPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setdPadDown = function (newPressedState) {
|
||||
raiseKeyEvent(_dPadDownPressed, newPressedState, _GAMEPAD_DPAD_DOWN_KEY, _GAMEPAD_DPAD_DOWN_KEYCODE, true);
|
||||
_dPadDownPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getdPadLeft = function () {
|
||||
return _dPadLeftPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setdPadLeft = function (newPressedState) {
|
||||
raiseKeyEvent(_dPadLeftPressed, newPressedState, _GAMEPAD_DPAD_LEFT_KEY, _GAMEPAD_DPAD_LEFT_KEYCODE, true);
|
||||
_dPadLeftPressed = newPressedState;
|
||||
};
|
||||
|
||||
_ButtonPressedState.getdPadRight = function () {
|
||||
return _dPadRightPressed;
|
||||
};
|
||||
|
||||
_ButtonPressedState.setdPadRight = function (newPressedState) {
|
||||
raiseKeyEvent(_dPadRightPressed, newPressedState, _GAMEPAD_DPAD_RIGHT_KEY, _GAMEPAD_DPAD_RIGHT_KEYCODE, true);
|
||||
_dPadRightPressed = newPressedState;
|
||||
};
|
||||
|
||||
var times = {};
|
||||
|
||||
function throttle(key) {
|
||||
var time = times[key] || 0;
|
||||
var now = new Date().getTime();
|
||||
|
||||
if ((now - time) >= 200) {
|
||||
//times[key] = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function resetThrottle(key) {
|
||||
times[key] = new Date().getTime();
|
||||
}
|
||||
|
||||
var isElectron = navigator.userAgent.toLowerCase().indexOf('electron') !== -1;
|
||||
function allowInput() {
|
||||
|
||||
// This would be nice but always seems to return true with electron
|
||||
if (!isElectron && document.hidden) { /* eslint-disable-line compat/compat */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (appHost.getWindowState() === 'Minimized') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function raiseEvent(name, key, keyCode) {
|
||||
|
||||
if (!allowInput()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent(name, true, true);
|
||||
event.key = key;
|
||||
event.keyCode = keyCode;
|
||||
(document.activeElement || document.body).dispatchEvent(event);
|
||||
}
|
||||
|
||||
function clickElement(elem) {
|
||||
|
||||
if (!allowInput()) {
|
||||
return;
|
||||
}
|
||||
|
||||
elem.click();
|
||||
}
|
||||
|
||||
function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRepeatKeyDown, clickonKeyUp) {
|
||||
|
||||
// No-op if oldPressedState === newPressedState
|
||||
if (newPressedState === true) {
|
||||
|
||||
// button down
|
||||
var fire = false;
|
||||
|
||||
// always fire if this is the initial down press
|
||||
if (oldPressedState === false) {
|
||||
fire = true;
|
||||
resetThrottle(key);
|
||||
} else if (enableRepeatKeyDown) {
|
||||
fire = throttle(key);
|
||||
}
|
||||
|
||||
if (fire && keyCode) {
|
||||
raiseEvent("keydown", key, keyCode);
|
||||
}
|
||||
|
||||
} else if (newPressedState === false && oldPressedState === true) {
|
||||
|
||||
resetThrottle(key);
|
||||
|
||||
// button up
|
||||
if (keyCode) {
|
||||
raiseEvent("keyup", key, keyCode);
|
||||
}
|
||||
if (clickonKeyUp) {
|
||||
clickElement(document.activeElement || window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var inputLoopTimer;
|
||||
function runInputLoop() {
|
||||
// Get the latest gamepad state.
|
||||
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
|
||||
for (var i = 0, len = gamepads.length; i < len; i++) {
|
||||
var gamepad = gamepads[i];
|
||||
if (!gamepad) {
|
||||
continue;
|
||||
}
|
||||
// Iterate through the axes
|
||||
var axes = gamepad.axes;
|
||||
var leftStickX = axes[0];
|
||||
var leftStickY = axes[1];
|
||||
if (leftStickX > _THUMB_STICK_THRESHOLD) { // Right
|
||||
_ButtonPressedState.setleftThumbstickRight(true);
|
||||
} else if (leftStickX < -_THUMB_STICK_THRESHOLD) { // Left
|
||||
_ButtonPressedState.setleftThumbstickLeft(true);
|
||||
} else if (leftStickY < -_THUMB_STICK_THRESHOLD) { // Up
|
||||
_ButtonPressedState.setleftThumbstickUp(true);
|
||||
} else if (leftStickY > _THUMB_STICK_THRESHOLD) { // Down
|
||||
_ButtonPressedState.setleftThumbstickDown(true);
|
||||
} else {
|
||||
_ButtonPressedState.setleftThumbstickLeft(false);
|
||||
_ButtonPressedState.setleftThumbstickRight(false);
|
||||
_ButtonPressedState.setleftThumbstickUp(false);
|
||||
_ButtonPressedState.setleftThumbstickDown(false);
|
||||
}
|
||||
// Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed.
|
||||
var buttons = gamepad.buttons;
|
||||
for (var j = 0, len = buttons.length; j < len; j++) {
|
||||
if (ProcessedButtons.indexOf(j) !== -1) {
|
||||
if (buttons[j].pressed) {
|
||||
switch (j) {
|
||||
case _GAMEPAD_DPAD_UP_BUTTON_INDEX:
|
||||
_ButtonPressedState.setdPadUp(true);
|
||||
break;
|
||||
case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX:
|
||||
_ButtonPressedState.setdPadDown(true);
|
||||
break;
|
||||
case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX:
|
||||
_ButtonPressedState.setdPadLeft(true);
|
||||
break;
|
||||
case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX:
|
||||
_ButtonPressedState.setdPadRight(true);
|
||||
break;
|
||||
case _GAMEPAD_A_BUTTON_INDEX:
|
||||
_ButtonPressedState.setgamepadA(true);
|
||||
break;
|
||||
case _GAMEPAD_B_BUTTON_INDEX:
|
||||
_ButtonPressedState.setgamepadB(true);
|
||||
break;
|
||||
default:
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (j) {
|
||||
case _GAMEPAD_DPAD_UP_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getdPadUp()) {
|
||||
_ButtonPressedState.setdPadUp(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getdPadDown()) {
|
||||
_ButtonPressedState.setdPadDown(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getdPadLeft()) {
|
||||
_ButtonPressedState.setdPadLeft(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getdPadRight()) {
|
||||
_ButtonPressedState.setdPadRight(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_A_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getgamepadA()) {
|
||||
_ButtonPressedState.setgamepadA(false);
|
||||
}
|
||||
break;
|
||||
case _GAMEPAD_B_BUTTON_INDEX:
|
||||
if (_ButtonPressedState.getgamepadB()) {
|
||||
_ButtonPressedState.setgamepadB(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Schedule the next one
|
||||
inputLoopTimer = requestAnimationFrame(runInputLoop);
|
||||
}
|
||||
|
||||
function startInputLoop() {
|
||||
if (!inputLoopTimer) {
|
||||
runInputLoop();
|
||||
}
|
||||
}
|
||||
|
||||
function stopInputLoop() {
|
||||
cancelAnimationFrame(inputLoopTimer);
|
||||
inputLoopTimer = undefined;
|
||||
}
|
||||
|
||||
function isGamepadConnected() {
|
||||
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
|
||||
for (var i = 0, len = gamepads.length; i < len; i++) {
|
||||
var gamepad = gamepads[i];
|
||||
if (gamepad && gamepad.connected) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function onFocusOrGamepadAttach(e) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (isGamepadConnected() && document.hasFocus()) {
|
||||
console.log("Gamepad connected! Starting input loop");
|
||||
startInputLoop();
|
||||
}
|
||||
}
|
||||
|
||||
function onFocusOrGamepadDetach(e) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (!isGamepadConnected() || !document.hasFocus()) {
|
||||
console.log("Gamepad disconnected! No other gamepads are connected, stopping input loop");
|
||||
stopInputLoop();
|
||||
} else {
|
||||
console.log("Gamepad disconnected! There are gamepads still connected.");
|
||||
}
|
||||
}
|
||||
|
||||
// Event listeners for any change in gamepads' state.
|
||||
window.addEventListener("gamepaddisconnected", onFocusOrGamepadDetach);
|
||||
window.addEventListener("gamepadconnected", onFocusOrGamepadAttach);
|
||||
window.addEventListener("blur", onFocusOrGamepadDetach);
|
||||
window.addEventListener("focus", onFocusOrGamepadAttach);
|
||||
|
||||
onFocusOrGamepadAttach();
|
||||
|
||||
// The gamepadInputEmulation is a string property that exists in JavaScript UWAs and in WebViews in UWAs.
|
||||
// It won't exist in Win8.1 style apps or browsers.
|
||||
if (window.navigator && typeof window.navigator.gamepadInputEmulation === "string") {
|
||||
// We want the gamepad to provide gamepad VK keyboard events rather than moving a
|
||||
// mouse like cursor. Set to "keyboard", the gamepad will provide such keyboard events
|
||||
// and provide input to the DOM navigator.getGamepads API.
|
||||
window.navigator.gamepadInputEmulation = "gamepad";
|
||||
}
|
||||
|
||||
});
|
|
@ -1,170 +0,0 @@
|
|||
/**
|
||||
* Module for performing keyboard navigation.
|
||||
* @module components/input/keyboardnavigation
|
||||
*/
|
||||
|
||||
import inputManager from "inputManager";
|
||||
import layoutManager from "layoutManager";
|
||||
|
||||
/**
|
||||
* Key name mapping.
|
||||
*/
|
||||
const KeyNames = {
|
||||
13: "Enter",
|
||||
19: "Pause",
|
||||
27: "Escape",
|
||||
32: "Space",
|
||||
37: "ArrowLeft",
|
||||
38: "ArrowUp",
|
||||
39: "ArrowRight",
|
||||
40: "ArrowDown",
|
||||
// MediaRewind (Tizen/WebOS)
|
||||
412: "MediaRewind",
|
||||
// MediaStop (Tizen/WebOS)
|
||||
413: "MediaStop",
|
||||
// MediaPlay (Tizen/WebOS)
|
||||
415: "MediaPlay",
|
||||
// MediaFastForward (Tizen/WebOS)
|
||||
417: "MediaFastForward",
|
||||
// Back (WebOS)
|
||||
461: "Back",
|
||||
// Back (Tizen)
|
||||
10009: "Back",
|
||||
// MediaTrackPrevious (Tizen)
|
||||
10232: "MediaTrackPrevious",
|
||||
// MediaTrackNext (Tizen)
|
||||
10233: "MediaTrackNext",
|
||||
// MediaPlayPause (Tizen)
|
||||
10252: "MediaPlayPause"
|
||||
};
|
||||
|
||||
/**
|
||||
* Keys used for keyboard navigation.
|
||||
*/
|
||||
const NavigationKeys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"];
|
||||
|
||||
let hasFieldKey = false;
|
||||
try {
|
||||
hasFieldKey = "key" in new KeyboardEvent("keydown");
|
||||
} catch (e) {
|
||||
console.error("error checking 'key' field");
|
||||
}
|
||||
|
||||
if (!hasFieldKey) {
|
||||
// Add [a..z]
|
||||
for (let i = 65; i <= 90; i++) {
|
||||
KeyNames[i] = String.fromCharCode(i).toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns key name from event.
|
||||
*
|
||||
* @param {KeyboardEvent} event - Keyboard event.
|
||||
* @return {string} Key name.
|
||||
*/
|
||||
export function getKeyName(event) {
|
||||
return KeyNames[event.keyCode] || event.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns _true_ if key is used for navigation.
|
||||
*
|
||||
* @param {string} key - Key name.
|
||||
* @return {boolean} _true_ if key is used for navigation.
|
||||
*/
|
||||
export function isNavigationKey(key) {
|
||||
return NavigationKeys.indexOf(key) != -1;
|
||||
}
|
||||
|
||||
export function enable() {
|
||||
document.addEventListener("keydown", function (e) {
|
||||
const key = getKeyName(e);
|
||||
|
||||
// Ignore navigation keys for non-TV
|
||||
if (!layoutManager.tv && isNavigationKey(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let capture = true;
|
||||
|
||||
switch (key) {
|
||||
case "ArrowLeft":
|
||||
inputManager.handle("left");
|
||||
break;
|
||||
case "ArrowUp":
|
||||
inputManager.handle("up");
|
||||
break;
|
||||
case "ArrowRight":
|
||||
inputManager.handle("right");
|
||||
break;
|
||||
case "ArrowDown":
|
||||
inputManager.handle("down");
|
||||
break;
|
||||
|
||||
case "Back":
|
||||
inputManager.handle("back");
|
||||
break;
|
||||
|
||||
case "Escape":
|
||||
if (layoutManager.tv) {
|
||||
inputManager.handle("back");
|
||||
} else {
|
||||
capture = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case "MediaPlay":
|
||||
inputManager.handle("play");
|
||||
break;
|
||||
case "Pause":
|
||||
inputManager.handle("pause");
|
||||
break;
|
||||
case "MediaPlayPause":
|
||||
inputManager.handle("playpause");
|
||||
break;
|
||||
case "MediaRewind":
|
||||
inputManager.handle("rewind");
|
||||
break;
|
||||
case "MediaFastForward":
|
||||
inputManager.handle("fastforward");
|
||||
break;
|
||||
case "MediaStop":
|
||||
inputManager.handle("stop");
|
||||
break;
|
||||
case "MediaTrackPrevious":
|
||||
inputManager.handle("previoustrack");
|
||||
break;
|
||||
case "MediaTrackNext":
|
||||
inputManager.handle("nexttrack");
|
||||
break;
|
||||
|
||||
default:
|
||||
capture = false;
|
||||
}
|
||||
|
||||
if (capture) {
|
||||
console.debug("disabling default event handling");
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Gamepad initialisation. No script is required if no gamepads are present at init time, saving a bit of resources.
|
||||
// Whenever the gamepad is connected, we hand all the control of the gamepad to gamepadtokey.js by removing the event handler
|
||||
function attachGamepadScript(e) {
|
||||
console.log("Gamepad connected! Attaching gamepadtokey.js script");
|
||||
window.removeEventListener("gamepadconnected", attachGamepadScript);
|
||||
require(["components/input/gamepadtokey"]);
|
||||
}
|
||||
|
||||
// No need to check for gamepads manually at load time, the eventhandler will be fired for that
|
||||
if (navigator.getGamepads) { /* eslint-disable-line compat/compat */
|
||||
window.addEventListener("gamepadconnected", attachGamepadScript);
|
||||
}
|
||||
|
||||
export default {
|
||||
enable: enable,
|
||||
getKeyName: getKeyName,
|
||||
isNavigationKey: isNavigationKey
|
||||
};
|
|
@ -1,169 +0,0 @@
|
|||
define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'dom'], function (inputManager, focusManager, browser, layoutManager, events, dom) {
|
||||
'use strict';
|
||||
|
||||
var self = {};
|
||||
|
||||
var lastMouseInputTime = new Date().getTime();
|
||||
var isMouseIdle;
|
||||
|
||||
function mouseIdleTime() {
|
||||
return new Date().getTime() - lastMouseInputTime;
|
||||
}
|
||||
|
||||
function notifyApp() {
|
||||
|
||||
inputManager.notifyMouseMove();
|
||||
}
|
||||
|
||||
function removeIdleClasses() {
|
||||
|
||||
var classList = document.body.classList;
|
||||
|
||||
classList.remove('mouseIdle');
|
||||
classList.remove('mouseIdle-tv');
|
||||
}
|
||||
|
||||
function addIdleClasses() {
|
||||
|
||||
var classList = document.body.classList;
|
||||
|
||||
classList.add('mouseIdle');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
classList.add('mouseIdle-tv');
|
||||
}
|
||||
}
|
||||
|
||||
var lastPointerMoveData;
|
||||
function onPointerMove(e) {
|
||||
|
||||
var eventX = e.screenX;
|
||||
var eventY = e.screenY;
|
||||
|
||||
// if coord don't exist how could it move
|
||||
if (typeof eventX === "undefined" && typeof eventY === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = lastPointerMoveData;
|
||||
if (!obj) {
|
||||
lastPointerMoveData = {
|
||||
x: eventX,
|
||||
y: eventY
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// if coord are same, it didn't move
|
||||
if (Math.abs(eventX - obj.x) < 10 && Math.abs(eventY - obj.y) < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
obj.x = eventX;
|
||||
obj.y = eventY;
|
||||
|
||||
lastMouseInputTime = new Date().getTime();
|
||||
notifyApp();
|
||||
|
||||
if (isMouseIdle) {
|
||||
isMouseIdle = false;
|
||||
removeIdleClasses();
|
||||
events.trigger(self, 'mouseactive');
|
||||
}
|
||||
}
|
||||
|
||||
function onPointerEnter(e) {
|
||||
|
||||
var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
|
||||
|
||||
if (pointerType === 'mouse') {
|
||||
if (!isMouseIdle) {
|
||||
var parent = focusManager.focusableParent(e.target);
|
||||
if (parent) {
|
||||
focusManager.focus(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function enableFocusWithMouse() {
|
||||
|
||||
if (!layoutManager.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (browser.web0s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (browser.tv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function onMouseInterval() {
|
||||
|
||||
if (!isMouseIdle && mouseIdleTime() >= 5000) {
|
||||
isMouseIdle = true;
|
||||
addIdleClasses();
|
||||
events.trigger(self, 'mouseidle');
|
||||
}
|
||||
}
|
||||
|
||||
var mouseInterval;
|
||||
function startMouseInterval() {
|
||||
|
||||
if (!mouseInterval) {
|
||||
mouseInterval = setInterval(onMouseInterval, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function stopMouseInterval() {
|
||||
|
||||
var interval = mouseInterval;
|
||||
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
mouseInterval = null;
|
||||
}
|
||||
|
||||
removeIdleClasses();
|
||||
}
|
||||
|
||||
function initMouse() {
|
||||
|
||||
stopMouseInterval();
|
||||
|
||||
dom.removeEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
if (!layoutManager.mobile) {
|
||||
startMouseInterval();
|
||||
|
||||
dom.addEventListener(document, (window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
dom.removeEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
|
||||
if (enableFocusWithMouse()) {
|
||||
dom.addEventListener(document, (window.PointerEvent ? 'pointerenter' : 'mouseenter'), onPointerEnter, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initMouse();
|
||||
|
||||
events.on(layoutManager, 'modechange', initMouse);
|
||||
|
||||
return self;
|
||||
});
|
|
@ -1,52 +0,0 @@
|
|||
.tmla-mask,
|
||||
.touch-menu-la {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.touch-menu-la {
|
||||
background-color: #fff;
|
||||
will-change: transform;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-transition: -webkit-transform ease-out 40ms, left ease-out 260ms;
|
||||
-o-transition: transform ease-out 40ms, left ease-out 260ms;
|
||||
transition: transform ease-out 40ms, left ease-out 260ms;
|
||||
z-index: 1099;
|
||||
}
|
||||
|
||||
.touch-menu-la.transition {
|
||||
-webkit-transition: -webkit-transform ease-out 240ms, left ease-out 260ms;
|
||||
-o-transition: transform ease-out 240ms, left ease-out 260ms;
|
||||
transition: transform ease-out 240ms, left ease-out 260ms;
|
||||
}
|
||||
|
||||
.drawer-open {
|
||||
-webkit-box-shadow: 2px 0 12px rgba(0, 0, 0, 0.4);
|
||||
box-shadow: 2px 0 12px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.scrollContainer {
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.tmla-mask {
|
||||
left: 0;
|
||||
right: 0;
|
||||
opacity: 0;
|
||||
z-index: 1098;
|
||||
-webkit-transition: opacity ease-in-out 0.38s, visibility ease-in-out 0.38s;
|
||||
-o-transition: opacity ease-in-out 0.38s, visibility ease-in-out 0.38s;
|
||||
transition: opacity ease-in-out 0.38s, visibility ease-in-out 0.38s;
|
||||
will-change: opacity;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.tmla-mask.backdrop {
|
||||
opacity: 1;
|
||||
}
|
|
@ -1,353 +0,0 @@
|
|||
define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser, dom) {
|
||||
"use strict";
|
||||
|
||||
return function (options) {
|
||||
function getTouches(e) {
|
||||
return e.changedTouches || e.targetTouches || e.touches;
|
||||
}
|
||||
|
||||
function onMenuTouchStart(e) {
|
||||
options.target.classList.remove("transition");
|
||||
var touches = getTouches(e);
|
||||
var touch = touches[0] || {};
|
||||
menuTouchStartX = touch.clientX;
|
||||
menuTouchStartY = touch.clientY;
|
||||
menuTouchStartTime = new Date().getTime();
|
||||
}
|
||||
|
||||
function setVelocity(deltaX) {
|
||||
var time = new Date().getTime() - (menuTouchStartTime || 0);
|
||||
velocity = Math.abs(deltaX) / time;
|
||||
}
|
||||
|
||||
function onMenuTouchMove(e) {
|
||||
var isOpen = self.visible;
|
||||
var touches = getTouches(e);
|
||||
var touch = touches[0] || {};
|
||||
var endX = touch.clientX || 0;
|
||||
var endY = touch.clientY || 0;
|
||||
var deltaX = endX - (menuTouchStartX || 0);
|
||||
var deltaY = endY - (menuTouchStartY || 0);
|
||||
setVelocity(deltaX);
|
||||
|
||||
if (isOpen && 1 !== dragMode && deltaX > 0) {
|
||||
dragMode = 2;
|
||||
}
|
||||
|
||||
if (0 === dragMode && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5) {
|
||||
dragMode = 1;
|
||||
scrollContainer.addEventListener("scroll", disableEvent);
|
||||
self.showMask();
|
||||
} else if (0 === dragMode && Math.abs(deltaY) >= 5) {
|
||||
dragMode = 2;
|
||||
}
|
||||
|
||||
if (1 === dragMode) {
|
||||
newPos = currentPos + deltaX;
|
||||
self.changeMenuPos();
|
||||
}
|
||||
}
|
||||
|
||||
function onMenuTouchEnd(e) {
|
||||
options.target.classList.add("transition");
|
||||
scrollContainer.removeEventListener("scroll", disableEvent);
|
||||
dragMode = 0;
|
||||
var touches = getTouches(e);
|
||||
var touch = touches[0] || {};
|
||||
var endX = touch.clientX || 0;
|
||||
var endY = touch.clientY || 0;
|
||||
var deltaX = endX - (menuTouchStartX || 0);
|
||||
var deltaY = endY - (menuTouchStartY || 0);
|
||||
currentPos = deltaX;
|
||||
self.checkMenuState(deltaX, deltaY);
|
||||
}
|
||||
|
||||
function onEdgeTouchStart(e) {
|
||||
if (isPeeking) {
|
||||
onMenuTouchMove(e);
|
||||
} else {
|
||||
if (((getTouches(e)[0] || {}).clientX || 0) <= options.handleSize) {
|
||||
isPeeking = true;
|
||||
|
||||
if (e.type === "touchstart") {
|
||||
dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {});
|
||||
dom.addEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {});
|
||||
}
|
||||
|
||||
onMenuTouchStart(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onEdgeTouchMove(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onEdgeTouchStart(e);
|
||||
}
|
||||
|
||||
function onEdgeTouchEnd(e) {
|
||||
if (isPeeking) {
|
||||
isPeeking = false;
|
||||
dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {});
|
||||
onMenuTouchEnd(e);
|
||||
}
|
||||
}
|
||||
|
||||
function disableEvent(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function onBackgroundTouchStart(e) {
|
||||
var touches = getTouches(e);
|
||||
var touch = touches[0] || {};
|
||||
backgroundTouchStartX = touch.clientX;
|
||||
backgroundTouchStartTime = new Date().getTime();
|
||||
}
|
||||
|
||||
function onBackgroundTouchMove(e) {
|
||||
var touches = getTouches(e);
|
||||
var touch = touches[0] || {};
|
||||
var endX = touch.clientX || 0;
|
||||
|
||||
if (endX <= options.width && self.isVisible) {
|
||||
countStart++;
|
||||
var deltaX = endX - (backgroundTouchStartX || 0);
|
||||
|
||||
if (countStart == 1) {
|
||||
startPoint = deltaX;
|
||||
}
|
||||
if (deltaX < 0 && dragMode !== 2) {
|
||||
dragMode = 1;
|
||||
newPos = deltaX - startPoint + options.width;
|
||||
self.changeMenuPos();
|
||||
var time = new Date().getTime() - (backgroundTouchStartTime || 0);
|
||||
velocity = Math.abs(deltaX) / time;
|
||||
}
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function onBackgroundTouchEnd(e) {
|
||||
var touches = getTouches(e);
|
||||
var touch = touches[0] || {};
|
||||
var endX = touch.clientX || 0;
|
||||
var deltaX = endX - (backgroundTouchStartX || 0);
|
||||
self.checkMenuState(deltaX);
|
||||
countStart = 0;
|
||||
}
|
||||
|
||||
function onMaskTransitionEnd() {
|
||||
var classList = mask.classList;
|
||||
|
||||
if (!classList.contains("backdrop")) {
|
||||
classList.add("hide");
|
||||
}
|
||||
}
|
||||
|
||||
var self;
|
||||
var defaults;
|
||||
var mask;
|
||||
var newPos = 0;
|
||||
var currentPos = 0;
|
||||
var startPoint = 0;
|
||||
var countStart = 0;
|
||||
var velocity = 0;
|
||||
options.target.classList.add("transition");
|
||||
var dragMode = 0;
|
||||
var scrollContainer = options.target.querySelector(".mainDrawer-scrollContainer");
|
||||
scrollContainer.classList.add("scrollY");
|
||||
|
||||
var TouchMenuLA = function () {
|
||||
self = this;
|
||||
defaults = {
|
||||
width: 260,
|
||||
handleSize: 10,
|
||||
disableMask: false,
|
||||
maxMaskOpacity: 0.5
|
||||
};
|
||||
this.isVisible = false;
|
||||
this.initialize();
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.initElements = function () {
|
||||
options.target.classList.add("touch-menu-la");
|
||||
options.target.style.width = options.width + "px";
|
||||
options.target.style.left = -options.width + "px";
|
||||
|
||||
if (!options.disableMask) {
|
||||
mask = document.createElement("div");
|
||||
mask.className = "tmla-mask hide";
|
||||
document.body.appendChild(mask);
|
||||
dom.addEventListener(mask, dom.whichTransitionEvent(), onMaskTransitionEnd, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var menuTouchStartX;
|
||||
var menuTouchStartY;
|
||||
var menuTouchStartTime;
|
||||
var edgeContainer = document.querySelector(".mainDrawerHandle");
|
||||
var isPeeking = false;
|
||||
|
||||
TouchMenuLA.prototype.animateToPosition = function (pos) {
|
||||
requestAnimationFrame(function () {
|
||||
options.target.style.transform = pos ? "translateX(" + pos + "px)" : "none";
|
||||
});
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.changeMenuPos = function () {
|
||||
if (newPos <= options.width) {
|
||||
this.animateToPosition(newPos);
|
||||
}
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.clickMaskClose = function () {
|
||||
mask.addEventListener("click", function () {
|
||||
self.close();
|
||||
});
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.checkMenuState = function (deltaX, deltaY) {
|
||||
if (velocity >= 0.4) {
|
||||
if (deltaX >= 0 || Math.abs(deltaY || 0) >= 70) {
|
||||
self.open();
|
||||
} else {
|
||||
self.close();
|
||||
}
|
||||
} else {
|
||||
if (newPos >= 100) {
|
||||
self.open();
|
||||
} else {
|
||||
if (newPos) {
|
||||
self.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.open = function () {
|
||||
this.animateToPosition(options.width);
|
||||
currentPos = options.width;
|
||||
this.isVisible = true;
|
||||
options.target.classList.add("drawer-open");
|
||||
self.showMask();
|
||||
self.invoke(options.onChange);
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.close = function () {
|
||||
this.animateToPosition(0);
|
||||
currentPos = 0;
|
||||
self.isVisible = false;
|
||||
options.target.classList.remove("drawer-open");
|
||||
self.hideMask();
|
||||
self.invoke(options.onChange);
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.toggle = function () {
|
||||
if (self.isVisible) {
|
||||
self.close();
|
||||
} else {
|
||||
self.open();
|
||||
}
|
||||
};
|
||||
|
||||
var backgroundTouchStartX;
|
||||
var backgroundTouchStartTime;
|
||||
|
||||
TouchMenuLA.prototype.showMask = function () {
|
||||
mask.classList.remove("hide");
|
||||
mask.offsetWidth;
|
||||
mask.classList.add("backdrop");
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.hideMask = function () {
|
||||
mask.classList.add("hide");
|
||||
mask.classList.remove("backdrop");
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.invoke = function (fn) {
|
||||
if (fn) {
|
||||
fn.apply(self);
|
||||
}
|
||||
};
|
||||
|
||||
var _edgeSwipeEnabled;
|
||||
|
||||
TouchMenuLA.prototype.setEdgeSwipeEnabled = function (enabled) {
|
||||
if (!options.disableEdgeSwipe) {
|
||||
if (browser.touch) {
|
||||
if (enabled) {
|
||||
if (!_edgeSwipeEnabled) {
|
||||
_edgeSwipeEnabled = true;
|
||||
dom.addEventListener(edgeContainer, "touchstart", onEdgeTouchStart, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(edgeContainer, "touchend", onEdgeTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (_edgeSwipeEnabled) {
|
||||
_edgeSwipeEnabled = false;
|
||||
dom.removeEventListener(edgeContainer, "touchstart", onEdgeTouchStart, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(edgeContainer, "touchend", onEdgeTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TouchMenuLA.prototype.initialize = function () {
|
||||
options = Object.assign(defaults, options || {});
|
||||
|
||||
if (browser.edge) {
|
||||
options.disableEdgeSwipe = true;
|
||||
}
|
||||
|
||||
self.initElements();
|
||||
|
||||
if (browser.touch) {
|
||||
dom.addEventListener(options.target, "touchstart", onMenuTouchStart, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(options.target, "touchmove", onMenuTouchMove, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(options.target, "touchend", onMenuTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(options.target, "touchcancel", onMenuTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(mask, "touchstart", onBackgroundTouchStart, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(mask, "touchmove", onBackgroundTouchMove, {});
|
||||
dom.addEventListener(mask, "touchend", onBackgroundTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(mask, "touchcancel", onBackgroundTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
self.clickMaskClose();
|
||||
};
|
||||
|
||||
return new TouchMenuLA();
|
||||
};
|
||||
});
|
|
@ -20,9 +20,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
|||
}
|
||||
|
||||
function bindToFullscreenChange(player) {
|
||||
screenfull.on('change', function () {
|
||||
events.trigger(player, 'fullscreenchange');
|
||||
});
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.on('change', function () {
|
||||
events.trigger(player, 'fullscreenchange');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function triggerPlayerChange(playbackManagerInstance, newPlayer, newTarget, previousPlayer, previousTargetInfo) {
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
// Polyfill to add support for preventScroll by focus function
|
||||
|
||||
if (HTMLElement.prototype.nativeFocus === undefined) {
|
||||
(function () {
|
||||
var supportsPreventScrollOption = false;
|
||||
try {
|
||||
var focusElem = document.createElement("div");
|
||||
|
||||
focusElem.addEventListener("focus", function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}, true);
|
||||
|
||||
var opts = Object.defineProperty({}, "preventScroll", {
|
||||
// eslint-disable-next-line getter-return
|
||||
get: function () {
|
||||
supportsPreventScrollOption = true;
|
||||
}
|
||||
});
|
||||
|
||||
focusElem.focus(opts);
|
||||
} catch (e) {
|
||||
console.error("error checking preventScroll support");
|
||||
}
|
||||
|
||||
if (!supportsPreventScrollOption) {
|
||||
HTMLElement.prototype.nativeFocus = HTMLElement.prototype.focus;
|
||||
|
||||
HTMLElement.prototype.focus = function(options) {
|
||||
var scrollX = window.scrollX;
|
||||
var scrollY = window.scrollY;
|
||||
|
||||
this.nativeFocus();
|
||||
|
||||
// Restore window scroll if preventScroll
|
||||
if (options && options.preventScroll) {
|
||||
window.scroll(scrollX, scrollY);
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
if (typeof Object.assign != 'function') {
|
||||
(function () {
|
||||
Object.assign = function (target) {
|
||||
'use strict';
|
||||
if (target === undefined || target === null) {
|
||||
throw new TypeError('Cannot convert undefined or null to object');
|
||||
}
|
||||
|
||||
var output = Object(target);
|
||||
for (var index = 1; index < arguments.length; index++) {
|
||||
var source = arguments[index];
|
||||
if (source !== undefined && source !== null) {
|
||||
for (var nextKey in source) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (source.hasOwnProperty(nextKey)) {
|
||||
output[nextKey] = source[nextKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
})();
|
||||
}
|
|
@ -672,18 +672,6 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
|
|||
playbackManager.setVolume(this.value, currentPlayer);
|
||||
}
|
||||
|
||||
var contextmenuHtml = '<button id="toggleContextMenu" is="paper-icon-button-light" class="btnToggleContextMenu" title=' + globalize.translate('ButtonToggleContextMenu') + '><i class="material-icons more_vert"></i></button>';
|
||||
var volumecontrolHtml = '<div class="volumecontrol flex align-items-center flex-wrap-wrap justify-content-center">';
|
||||
volumecontrolHtml += '<button is="paper-icon-button-light" class="buttonMute autoSize" title=' + globalize.translate('Mute') + '><i class="xlargePaperIconButton material-icons"></i></button>';
|
||||
volumecontrolHtml += '<div class="sliderContainer nowPlayingVolumeSliderContainer"><input is="emby-slider" type="range" step="1" min="0" max="100" value="0" class="nowPlayingVolumeSlider"/></div>';
|
||||
volumecontrolHtml += '</div>';
|
||||
if (!layoutManager.mobile) {
|
||||
context.querySelector(".nowPlayingSecondaryButtons").innerHTML += volumecontrolHtml;
|
||||
context.querySelector(".playlistSectionButton").innerHTML += contextmenuHtml;
|
||||
} else {
|
||||
context.querySelector(".playlistSectionButton").innerHTML += volumecontrolHtml + contextmenuHtml;
|
||||
}
|
||||
|
||||
context.querySelector(".nowPlayingVolumeSlider").addEventListener("change", setVolume);
|
||||
context.querySelector(".nowPlayingVolumeSlider").addEventListener("mousemove", setVolume);
|
||||
context.querySelector(".nowPlayingVolumeSlider").addEventListener("touchmove", setVolume);
|
||||
|
@ -767,6 +755,18 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL
|
|||
}
|
||||
|
||||
function init(ownerView, context) {
|
||||
let contextmenuHtml = `<button id="toggleContextMenu" is="paper-icon-button-light" class="btnToggleContextMenu" title=${globalize.translate('ButtonToggleContextMenu')}><i class="material-icons more_vert"></i></button>`;
|
||||
let volumecontrolHtml = '<div class="volumecontrol flex align-items-center flex-wrap-wrap justify-content-center">';
|
||||
volumecontrolHtml += `<button is="paper-icon-button-light" class="buttonMute autoSize" title=${globalize.translate('Mute')}><i class="xlargePaperIconButton material-icons"></i></button>`;
|
||||
volumecontrolHtml += '<div class="sliderContainer nowPlayingVolumeSliderContainer"><input is="emby-slider" type="range" step="1" min="0" max="100" value="0" class="nowPlayingVolumeSlider"/></div>';
|
||||
volumecontrolHtml += '</div>';
|
||||
if (!layoutManager.mobile) {
|
||||
context.querySelector('.nowPlayingSecondaryButtons').innerHTML += volumecontrolHtml;
|
||||
context.querySelector('.playlistSectionButton').innerHTML += contextmenuHtml;
|
||||
} else {
|
||||
context.querySelector('.playlistSectionButton').innerHTML += volumecontrolHtml + contextmenuHtml;
|
||||
}
|
||||
|
||||
bindEvents(context);
|
||||
context.querySelector(".sendMessageForm").addEventListener("submit", onMessageSubmit);
|
||||
context.querySelector(".typeTextForm").addEventListener("submit", onSendStringSubmit);
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
define(["events", "playbackManager", "pluginManager", "inputManager", "connectionManager", "userSettings"], function (events, playbackManager, pluginManager, inputManager, connectionManager, userSettings) {
|
||||
"use strict";
|
||||
|
||||
function getMinIdleTime() {
|
||||
// Returns the minimum amount of idle time required before the screen saver can be displayed
|
||||
//time units used Millisecond
|
||||
return 180000;
|
||||
}
|
||||
|
||||
var lastFunctionalEvent = 0;
|
||||
|
||||
function getFunctionalEventIdleTime() {
|
||||
return new Date().getTime() - lastFunctionalEvent;
|
||||
}
|
||||
|
||||
events.on(playbackManager, "playbackstop", function (e, stopInfo) {
|
||||
var state = stopInfo.state;
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType == "Video") {
|
||||
lastFunctionalEvent = new Date().getTime();
|
||||
}
|
||||
});
|
||||
|
||||
function getScreensaverPlugin(isLoggedIn) {
|
||||
|
||||
var option;
|
||||
try {
|
||||
option = userSettings.get("screensaver", false);
|
||||
} catch (err) {
|
||||
option = isLoggedIn ? "backdropscreensaver" : "logoscreensaver";
|
||||
}
|
||||
|
||||
var plugins = pluginManager.ofType("screensaver");
|
||||
|
||||
for (var i = 0, length = plugins.length; i < length; i++) {
|
||||
var plugin = plugins[i];
|
||||
|
||||
if (plugin.id === option) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function ScreenSaverManager() {
|
||||
|
||||
var self = this;
|
||||
var activeScreenSaver;
|
||||
|
||||
function showScreenSaver(screensaver) {
|
||||
|
||||
if (activeScreenSaver) {
|
||||
throw new Error("An existing screensaver is already active.");
|
||||
}
|
||||
|
||||
console.debug("Showing screensaver " + screensaver.name);
|
||||
|
||||
screensaver.show();
|
||||
activeScreenSaver = screensaver;
|
||||
|
||||
if (screensaver.hideOnClick !== false) {
|
||||
window.addEventListener("click", hide, true);
|
||||
}
|
||||
if (screensaver.hideOnMouse !== false) {
|
||||
window.addEventListener("mousemove", hide, true);
|
||||
}
|
||||
if (screensaver.hideOnKey !== false) {
|
||||
window.addEventListener("keydown", hide, true);
|
||||
}
|
||||
}
|
||||
|
||||
function hide() {
|
||||
if (activeScreenSaver) {
|
||||
console.debug("Hiding screensaver");
|
||||
activeScreenSaver.hide();
|
||||
activeScreenSaver = null;
|
||||
}
|
||||
|
||||
window.removeEventListener("click", hide, true);
|
||||
window.removeEventListener("mousemove", hide, true);
|
||||
window.removeEventListener("keydown", hide, true);
|
||||
}
|
||||
|
||||
self.isShowing = function () {
|
||||
return activeScreenSaver != null;
|
||||
};
|
||||
|
||||
self.show = function () {
|
||||
var isLoggedIn;
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
|
||||
if (apiClient && apiClient.isLoggedIn()) {
|
||||
isLoggedIn = true;
|
||||
}
|
||||
|
||||
var screensaver = getScreensaverPlugin(isLoggedIn);
|
||||
|
||||
if (screensaver) {
|
||||
showScreenSaver(screensaver);
|
||||
}
|
||||
};
|
||||
|
||||
self.hide = function () {
|
||||
hide();
|
||||
};
|
||||
|
||||
function onInterval() {
|
||||
|
||||
if (self.isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inputManager.idleTime() < getMinIdleTime()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getFunctionalEventIdleTime < getMinIdleTime()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (playbackManager.isPlayingVideo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.show();
|
||||
}
|
||||
|
||||
setInterval(onInterval, 10000);
|
||||
}
|
||||
|
||||
return new ScreenSaverManager();
|
||||
});
|
|
@ -1,932 +0,0 @@
|
|||
define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'scrollStyles'], function (browser, layoutManager, dom, focusManager, ResizeObserver) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Return type of the value.
|
||||
*
|
||||
* @param {Mixed} value
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
function type(value) {
|
||||
if (value == null) {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
if (typeof value === 'object' || typeof value === 'function') {
|
||||
return Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || 'object';
|
||||
}
|
||||
|
||||
return typeof value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables an event it was triggered on and unbinds itself.
|
||||
*
|
||||
* @param {Event} event
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
function disableOneEvent(event) {
|
||||
/*jshint validthis:true */
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.removeEventListener(event.type, disableOneEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that number is within the limits.
|
||||
*
|
||||
* @param {Number} number
|
||||
* @param {Number} min
|
||||
* @param {Number} max
|
||||
*
|
||||
* @return {Number}
|
||||
*/
|
||||
function within(number, min, max) {
|
||||
return number < min ? min : number > max ? max : number;
|
||||
}
|
||||
|
||||
// Other global values
|
||||
var dragMouseEvents = ['mousemove', 'mouseup'];
|
||||
var dragTouchEvents = ['touchmove', 'touchend'];
|
||||
var wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel' : 'mousewheel');
|
||||
var interactiveElements = ['INPUT', 'SELECT', 'TEXTAREA'];
|
||||
var tmpArray = [];
|
||||
var time;
|
||||
|
||||
// Math shorthands
|
||||
var abs = Math.abs;
|
||||
var sqrt = Math.sqrt;
|
||||
var pow = Math.pow;
|
||||
var round = Math.round;
|
||||
var max = Math.max;
|
||||
var min = Math.min;
|
||||
|
||||
var scrollerFactory = function (frame, options) {
|
||||
|
||||
// Extend options
|
||||
var o = Object.assign({}, {
|
||||
slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE.
|
||||
horizontal: false, // Switch to horizontal mode.
|
||||
|
||||
// Scrolling
|
||||
mouseWheel: true,
|
||||
scrollBy: 0, // Pixels or items to move per one mouse scroll. 0 to disable scrolling
|
||||
|
||||
// Dragging
|
||||
dragSource: null, // Selector or DOM element for catching dragging events. Default is FRAME.
|
||||
mouseDragging: 1, // Enable navigation by dragging the SLIDEE with mouse cursor.
|
||||
touchDragging: 1, // Enable navigation by dragging the SLIDEE with touch events.
|
||||
dragThreshold: 3, // Distance in pixels before Sly recognizes dragging.
|
||||
intervactive: null, // Selector for special interactive elements.
|
||||
|
||||
// Mixed options
|
||||
speed: 0 // Animations speed in milliseconds. 0 to disable animations.
|
||||
|
||||
}, options);
|
||||
|
||||
var isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style;
|
||||
|
||||
// native scroll is a must with touch input
|
||||
// also use native scroll when scrolling vertically in desktop mode - excluding horizontal because the mouse wheel support is choppy at the moment
|
||||
// in cases with firefox, if the smooth scroll api is supported then use that because their implementation is very good
|
||||
if (options.allowNativeScroll === false) {
|
||||
options.enableNativeScroll = false;
|
||||
} else if (isSmoothScrollSupported && ((browser.firefox && !layoutManager.tv) || options.allowNativeSmoothScroll)) {
|
||||
// native smooth scroll
|
||||
options.enableNativeScroll = true;
|
||||
} else if (options.requireAnimation && (browser.animate || browser.supportsCssAnimation())) {
|
||||
|
||||
// transform is the only way to guarantee animation
|
||||
options.enableNativeScroll = false;
|
||||
} else if (!layoutManager.tv || !browser.animate) {
|
||||
|
||||
options.enableNativeScroll = true;
|
||||
}
|
||||
|
||||
// Need this for the magic wheel. With the animated scroll the magic wheel will run off of the screen
|
||||
if (browser.web0s) {
|
||||
options.enableNativeScroll = true;
|
||||
}
|
||||
|
||||
// Private variables
|
||||
var self = this;
|
||||
self.options = o;
|
||||
|
||||
// Frame
|
||||
var slideeElement = o.slidee ? o.slidee : sibling(frame.firstChild)[0];
|
||||
self._pos = {
|
||||
start: 0,
|
||||
center: 0,
|
||||
end: 0,
|
||||
cur: 0,
|
||||
dest: 0
|
||||
};
|
||||
|
||||
var transform = !options.enableNativeScroll;
|
||||
|
||||
// Miscellaneous
|
||||
var scrollSource = frame;
|
||||
var dragSourceElement = o.dragSource ? o.dragSource : frame;
|
||||
var dragging = {
|
||||
released: 1
|
||||
};
|
||||
var scrolling = {
|
||||
last: 0,
|
||||
delta: 0,
|
||||
resetTime: 200
|
||||
};
|
||||
|
||||
// Expose properties
|
||||
self.initialized = 0;
|
||||
self.slidee = slideeElement;
|
||||
self.options = o;
|
||||
self.dragging = dragging;
|
||||
|
||||
var nativeScrollElement = frame;
|
||||
|
||||
function sibling(n, elem) {
|
||||
var matched = [];
|
||||
|
||||
for (; n; n = n.nextSibling) {
|
||||
if (n.nodeType === 1 && n !== elem) {
|
||||
matched.push(n);
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
var requiresReflow = true;
|
||||
|
||||
var frameSize = 0;
|
||||
var slideeSize = 0;
|
||||
function ensureSizeInfo() {
|
||||
|
||||
if (requiresReflow) {
|
||||
|
||||
requiresReflow = false;
|
||||
|
||||
// Reset global variables
|
||||
frameSize = o.horizontal ? (frame).offsetWidth : (frame).offsetHeight;
|
||||
|
||||
slideeSize = o.scrollWidth || Math.max(slideeElement[o.horizontal ? 'offsetWidth' : 'offsetHeight'], slideeElement[o.horizontal ? 'scrollWidth' : 'scrollHeight']);
|
||||
|
||||
// Set position limits & relativess
|
||||
self._pos.end = max(slideeSize - frameSize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loading function.
|
||||
*
|
||||
* Populate arrays, set sizes, bind events, ...
|
||||
*
|
||||
* @param {Boolean} [isInit] Whether load is called from within self.init().
|
||||
* @return {Void}
|
||||
*/
|
||||
function load(isInit) {
|
||||
|
||||
requiresReflow = true;
|
||||
|
||||
if (!isInit) {
|
||||
|
||||
ensureSizeInfo();
|
||||
|
||||
// Fix possible overflowing
|
||||
var pos = self._pos;
|
||||
self.slideTo(within(pos.dest, pos.start, pos.end));
|
||||
}
|
||||
}
|
||||
|
||||
function initFrameResizeObserver() {
|
||||
|
||||
var observerOptions = {};
|
||||
|
||||
self.frameResizeObserver = new ResizeObserver(onResize, observerOptions);
|
||||
|
||||
self.frameResizeObserver.observe(frame);
|
||||
}
|
||||
|
||||
self.reload = function () {
|
||||
load();
|
||||
};
|
||||
|
||||
self.getScrollEventName = function () {
|
||||
return transform ? 'scrollanimate' : 'scroll';
|
||||
};
|
||||
|
||||
self.getScrollSlider = function () {
|
||||
return slideeElement;
|
||||
};
|
||||
|
||||
self.getScrollFrame = function () {
|
||||
return frame;
|
||||
};
|
||||
|
||||
function nativeScrollTo(container, pos, immediate) {
|
||||
|
||||
if (container.scroll) {
|
||||
if (o.horizontal) {
|
||||
|
||||
container.scroll({
|
||||
left: pos,
|
||||
behavior: immediate ? 'instant' : 'smooth'
|
||||
});
|
||||
} else {
|
||||
|
||||
container.scroll({
|
||||
top: pos,
|
||||
behavior: immediate ? 'instant' : 'smooth'
|
||||
});
|
||||
}
|
||||
} else if (!immediate && container.scrollTo) {
|
||||
if (o.horizontal) {
|
||||
container.scrollTo(Math.round(pos), 0);
|
||||
} else {
|
||||
container.scrollTo(0, Math.round(pos));
|
||||
}
|
||||
} else {
|
||||
if (o.horizontal) {
|
||||
container.scrollLeft = Math.round(pos);
|
||||
} else {
|
||||
container.scrollTop = Math.round(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lastAnimate;
|
||||
|
||||
/**
|
||||
* Animate to a position.
|
||||
*
|
||||
* @param {Int} newPos New position.
|
||||
* @param {Bool} immediate Reposition immediately without an animation.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
self.slideTo = function (newPos, immediate, fullItemPos) {
|
||||
|
||||
ensureSizeInfo();
|
||||
var pos = self._pos;
|
||||
|
||||
newPos = within(newPos, pos.start, pos.end);
|
||||
|
||||
if (!transform) {
|
||||
|
||||
nativeScrollTo(nativeScrollElement, newPos, immediate);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the animation object
|
||||
var from = pos.cur;
|
||||
immediate = immediate || dragging.init || !o.speed;
|
||||
|
||||
var now = new Date().getTime();
|
||||
|
||||
if (o.autoImmediate) {
|
||||
if (!immediate && (now - (lastAnimate || 0)) <= 50) {
|
||||
immediate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!immediate && o.skipSlideToWhenVisible && fullItemPos && fullItemPos.isVisible) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Start animation rendering
|
||||
// NOTE the dependency was modified here to fix a scrollbutton issue
|
||||
pos.dest = newPos;
|
||||
renderAnimateWithTransform(from, newPos, immediate);
|
||||
lastAnimate = now;
|
||||
};
|
||||
|
||||
function setStyleProperty(elem, name, value, speed, resetTransition) {
|
||||
|
||||
var style = elem.style;
|
||||
|
||||
if (resetTransition || browser.edge) {
|
||||
style.transition = 'none';
|
||||
void elem.offsetWidth;
|
||||
}
|
||||
|
||||
style.transition = 'transform ' + speed + 'ms ease-out';
|
||||
style[name] = value;
|
||||
}
|
||||
|
||||
function dispatchScrollEventIfNeeded() {
|
||||
if (o.dispatchScrollEvent) {
|
||||
frame.dispatchEvent(new CustomEvent(self.getScrollEventName(), {
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function renderAnimateWithTransform(fromPosition, toPosition, immediate) {
|
||||
|
||||
var speed = o.speed;
|
||||
|
||||
if (immediate) {
|
||||
speed = o.immediateSpeed || 50;
|
||||
}
|
||||
|
||||
if (o.horizontal) {
|
||||
setStyleProperty(slideeElement, 'transform', 'translateX(' + (-round(toPosition)) + 'px)', speed);
|
||||
} else {
|
||||
setStyleProperty(slideeElement, 'transform', 'translateY(' + (-round(toPosition)) + 'px)', speed);
|
||||
}
|
||||
self._pos.cur = toPosition;
|
||||
|
||||
dispatchScrollEventIfNeeded();
|
||||
}
|
||||
|
||||
function getBoundingClientRect(elem) {
|
||||
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
// If we don't have gBCR, just use 0,0 rather than error
|
||||
if (elem.getBoundingClientRect) {
|
||||
return elem.getBoundingClientRect();
|
||||
} else {
|
||||
return { top: 0, left: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position object.
|
||||
*
|
||||
* @param {Mixed} item
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
self.getPos = function (item) {
|
||||
|
||||
var scrollElement = transform ? slideeElement : nativeScrollElement;
|
||||
var slideeOffset = getBoundingClientRect(scrollElement);
|
||||
var itemOffset = getBoundingClientRect(item);
|
||||
|
||||
var slideeStartPos = o.horizontal ? slideeOffset.left : slideeOffset.top;
|
||||
var slideeEndPos = o.horizontal ? slideeOffset.right : slideeOffset.bottom;
|
||||
|
||||
var offset = o.horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
|
||||
|
||||
var size = o.horizontal ? itemOffset.width : itemOffset.height;
|
||||
if (!size && size !== 0) {
|
||||
size = item[o.horizontal ? 'offsetWidth' : 'offsetHeight'];
|
||||
}
|
||||
|
||||
var centerOffset = o.centerOffset || 0;
|
||||
|
||||
if (!transform) {
|
||||
centerOffset = 0;
|
||||
if (o.horizontal) {
|
||||
offset += nativeScrollElement.scrollLeft;
|
||||
} else {
|
||||
offset += nativeScrollElement.scrollTop;
|
||||
}
|
||||
}
|
||||
|
||||
ensureSizeInfo();
|
||||
|
||||
var currentStart = self._pos.cur;
|
||||
var currentEnd = currentStart + frameSize;
|
||||
|
||||
console.debug('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd);
|
||||
var isVisible = offset >= currentStart && (offset + size) <= currentEnd;
|
||||
|
||||
return {
|
||||
start: offset,
|
||||
center: offset + centerOffset - (frameSize / 2) + (size / 2),
|
||||
end: offset - frameSize + size,
|
||||
size: size,
|
||||
isVisible: isVisible
|
||||
};
|
||||
};
|
||||
|
||||
self.getCenterPosition = function (item) {
|
||||
|
||||
ensureSizeInfo();
|
||||
|
||||
var pos = self.getPos(item);
|
||||
return within(pos.center, pos.start, pos.end);
|
||||
};
|
||||
|
||||
function dragInitSlidee(event) {
|
||||
var isTouch = event.type === 'touchstart';
|
||||
|
||||
// Ignore when already in progress, or interactive element in non-touch navivagion
|
||||
if (dragging.init || !isTouch && isInteractive(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// SLIDEE dragging conditions
|
||||
if (!(isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isTouch) {
|
||||
// prevents native image dragging in Firefox
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// Reset dragging object
|
||||
dragging.released = 0;
|
||||
|
||||
// Properties used in dragHandler
|
||||
dragging.init = 0;
|
||||
dragging.source = event.target;
|
||||
dragging.touch = isTouch;
|
||||
var pointer = isTouch ? event.touches[0] : event;
|
||||
dragging.initX = pointer.pageX;
|
||||
dragging.initY = pointer.pageY;
|
||||
dragging.initPos = self._pos.cur;
|
||||
dragging.start = +new Date();
|
||||
dragging.time = 0;
|
||||
dragging.path = 0;
|
||||
dragging.delta = 0;
|
||||
dragging.locked = 0;
|
||||
dragging.pathToLock = isTouch ? 30 : 10;
|
||||
|
||||
// Bind dragging events
|
||||
if (transform) {
|
||||
|
||||
if (isTouch) {
|
||||
dragTouchEvents.forEach(function (eventName) {
|
||||
dom.addEventListener(document, eventName, dragHandler, {
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
} else {
|
||||
dragMouseEvents.forEach(function (eventName) {
|
||||
dom.addEventListener(document, eventName, dragHandler, {
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for dragging scrollbar handle or SLIDEE.
|
||||
*
|
||||
* @param {Event} event
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
function dragHandler(event) {
|
||||
dragging.released = event.type === 'mouseup' || event.type === 'touchend';
|
||||
var pointer = dragging.touch ? event[dragging.released ? 'changedTouches' : 'touches'][0] : event;
|
||||
dragging.pathX = pointer.pageX - dragging.initX;
|
||||
dragging.pathY = pointer.pageY - dragging.initY;
|
||||
dragging.path = sqrt(pow(dragging.pathX, 2) + pow(dragging.pathY, 2));
|
||||
dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY;
|
||||
|
||||
if (!dragging.released && dragging.path < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We haven't decided whether this is a drag or not...
|
||||
if (!dragging.init) {
|
||||
// If the drag path was very short, maybe it's not a drag?
|
||||
if (dragging.path < o.dragThreshold) {
|
||||
// If the pointer was released, the path will not become longer and it's
|
||||
// definitely not a drag. If not released yet, decide on next iteration
|
||||
return dragging.released ? dragEnd() : undefined;
|
||||
} else {
|
||||
// If dragging path is sufficiently long we can confidently start a drag
|
||||
// if drag is in different direction than scroll, ignore it
|
||||
if (o.horizontal ? abs(dragging.pathX) > abs(dragging.pathY) : abs(dragging.pathX) < abs(dragging.pathY)) {
|
||||
dragging.init = 1;
|
||||
} else {
|
||||
return dragEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//event.preventDefault();
|
||||
|
||||
// Disable click on a source element, as it is unwelcome when dragging
|
||||
if (!dragging.locked && dragging.path > dragging.pathToLock) {
|
||||
dragging.locked = 1;
|
||||
dragging.source.addEventListener('click', disableOneEvent);
|
||||
}
|
||||
|
||||
// Cancel dragging on release
|
||||
if (dragging.released) {
|
||||
dragEnd();
|
||||
}
|
||||
|
||||
self.slideTo(round(dragging.initPos - dragging.delta));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops dragging and cleans up after it.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
function dragEnd() {
|
||||
dragging.released = true;
|
||||
|
||||
dragTouchEvents.forEach(function (eventName) {
|
||||
dom.removeEventListener(document, eventName, dragHandler, {
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
|
||||
dragMouseEvents.forEach(function (eventName) {
|
||||
dom.removeEventListener(document, eventName, dragHandler, {
|
||||
passive: true
|
||||
});
|
||||
});
|
||||
|
||||
// Make sure that disableOneEvent is not active in next tick.
|
||||
setTimeout(function () {
|
||||
dragging.source.removeEventListener('click', disableOneEvent);
|
||||
});
|
||||
|
||||
dragging.init = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether element is interactive.
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isInteractive(element) {
|
||||
|
||||
while (element) {
|
||||
|
||||
if (interactiveElements.indexOf(element.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
element = element.parentNode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mouse wheel delta normalization.
|
||||
*
|
||||
* @param {Event} event
|
||||
*
|
||||
* @return {Int}
|
||||
*/
|
||||
function normalizeWheelDelta(event) {
|
||||
// JELLYFIN MOD: Only use deltaX for horizontal scroll and remove IE8 support
|
||||
scrolling.curDelta = o.horizontal ? event.deltaX : event.deltaY;
|
||||
// END JELLYFIN MOD
|
||||
|
||||
if (transform) {
|
||||
scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100;
|
||||
}
|
||||
return scrolling.curDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mouse scrolling handler.
|
||||
*
|
||||
* @param {Event} event
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
function scrollHandler(event) {
|
||||
|
||||
ensureSizeInfo();
|
||||
var pos = self._pos;
|
||||
// Ignore if there is no scrolling to be done
|
||||
if (!o.scrollBy || pos.start === pos.end) {
|
||||
return;
|
||||
}
|
||||
var delta = normalizeWheelDelta(event);
|
||||
|
||||
if (transform) {
|
||||
// Trap scrolling only when necessary and/or requested
|
||||
if (delta > 0 && pos.dest < pos.end || delta < 0 && pos.dest > pos.start) {
|
||||
//stopDefault(event, 1);
|
||||
}
|
||||
|
||||
self.slideBy(o.scrollBy * delta);
|
||||
} else {
|
||||
|
||||
if (isSmoothScrollSupported) {
|
||||
delta *= 12;
|
||||
}
|
||||
|
||||
if (o.horizontal) {
|
||||
nativeScrollElement.scrollLeft += delta;
|
||||
} else {
|
||||
nativeScrollElement.scrollTop += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys instance and everything it created.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
self.destroy = function () {
|
||||
|
||||
if (self.frameResizeObserver) {
|
||||
self.frameResizeObserver.disconnect();
|
||||
self.frameResizeObserver = null;
|
||||
}
|
||||
|
||||
// Reset native FRAME element scroll
|
||||
dom.removeEventListener(frame, 'scroll', resetScroll, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.removeEventListener(scrollSource, wheelEvent, scrollHandler, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.removeEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.removeEventListener(frame, 'click', onFrameClick, {
|
||||
passive: true,
|
||||
capture: true
|
||||
});
|
||||
|
||||
dom.removeEventListener(dragSourceElement, 'mousedown', dragInitSlidee, {
|
||||
//passive: true
|
||||
});
|
||||
|
||||
// Reset initialized status and return the instance
|
||||
self.initialized = 0;
|
||||
return self;
|
||||
};
|
||||
|
||||
var contentRect = {};
|
||||
|
||||
function onResize(entries) {
|
||||
|
||||
var entry = entries[0];
|
||||
|
||||
if (entry) {
|
||||
|
||||
var newRect = entry.contentRect;
|
||||
|
||||
// handle element being hidden
|
||||
if (newRect.width === 0 || newRect.height === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (newRect.width !== contentRect.width || newRect.height !== contentRect.height) {
|
||||
|
||||
contentRect = newRect;
|
||||
|
||||
load(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetScroll() {
|
||||
if (o.horizontal) {
|
||||
this.scrollLeft = 0;
|
||||
} else {
|
||||
this.scrollTop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function onFrameClick(e) {
|
||||
if (e.which === 1) {
|
||||
var focusableParent = focusManager.focusableParent(e.target);
|
||||
if (focusableParent && focusableParent !== document.activeElement) {
|
||||
focusableParent.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.getScrollPosition = function () {
|
||||
|
||||
if (transform) {
|
||||
return self._pos.cur;
|
||||
}
|
||||
|
||||
if (o.horizontal) {
|
||||
return nativeScrollElement.scrollLeft;
|
||||
} else {
|
||||
return nativeScrollElement.scrollTop;
|
||||
}
|
||||
};
|
||||
|
||||
self.getScrollSize = function () {
|
||||
|
||||
if (transform) {
|
||||
return slideeSize;
|
||||
}
|
||||
|
||||
if (o.horizontal) {
|
||||
return nativeScrollElement.scrollWidth;
|
||||
} else {
|
||||
return nativeScrollElement.scrollHeight;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
self.init = function () {
|
||||
if (self.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!transform) {
|
||||
if (o.horizontal) {
|
||||
if (layoutManager.desktop && !o.hideScrollbar) {
|
||||
nativeScrollElement.classList.add('scrollX');
|
||||
} else {
|
||||
nativeScrollElement.classList.add('scrollX');
|
||||
nativeScrollElement.classList.add('hiddenScrollX');
|
||||
|
||||
if (layoutManager.tv && o.allowNativeSmoothScroll !== false) {
|
||||
nativeScrollElement.classList.add('smoothScrollX');
|
||||
}
|
||||
}
|
||||
|
||||
if (o.forceHideScrollbars) {
|
||||
nativeScrollElement.classList.add('hiddenScrollX-forced');
|
||||
}
|
||||
} else {
|
||||
if (layoutManager.desktop && !o.hideScrollbar) {
|
||||
nativeScrollElement.classList.add('scrollY');
|
||||
} else {
|
||||
nativeScrollElement.classList.add('scrollY');
|
||||
nativeScrollElement.classList.add('hiddenScrollY');
|
||||
|
||||
if (layoutManager.tv && o.allowNativeSmoothScroll !== false) {
|
||||
nativeScrollElement.classList.add('smoothScrollY');
|
||||
}
|
||||
}
|
||||
|
||||
if (o.forceHideScrollbars) {
|
||||
nativeScrollElement.classList.add('hiddenScrollY-forced');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
frame.style.overflow = 'hidden';
|
||||
slideeElement.style['will-change'] = 'transform';
|
||||
slideeElement.style.transition = 'transform ' + o.speed + 'ms ease-out';
|
||||
|
||||
if (o.horizontal) {
|
||||
slideeElement.classList.add('animatedScrollX');
|
||||
} else {
|
||||
slideeElement.classList.add('animatedScrollY');
|
||||
}
|
||||
}
|
||||
|
||||
if (transform || layoutManager.tv) {
|
||||
// This can prevent others from being able to listen to mouse events
|
||||
dom.addEventListener(dragSourceElement, 'mousedown', dragInitSlidee, {
|
||||
//passive: true
|
||||
});
|
||||
}
|
||||
|
||||
initFrameResizeObserver();
|
||||
|
||||
if (transform) {
|
||||
|
||||
dom.addEventListener(dragSourceElement, 'touchstart', dragInitSlidee, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
if (!o.horizontal) {
|
||||
dom.addEventListener(frame, 'scroll', resetScroll, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
if (o.mouseWheel) {
|
||||
// Scrolling navigation
|
||||
dom.addEventListener(scrollSource, wheelEvent, scrollHandler, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
} else if (o.horizontal) {
|
||||
|
||||
// Don't bind to mouse events with vertical scroll since the mouse wheel can handle this natively
|
||||
|
||||
if (o.mouseWheel) {
|
||||
// Scrolling navigation
|
||||
dom.addEventListener(scrollSource, wheelEvent, scrollHandler, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
dom.addEventListener(frame, 'click', onFrameClick, {
|
||||
passive: true,
|
||||
capture: true
|
||||
});
|
||||
|
||||
// Mark instance as initialized
|
||||
self.initialized = 1;
|
||||
|
||||
// Load
|
||||
load(true);
|
||||
|
||||
// Return instance
|
||||
return self;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Slide SLIDEE by amount of pixels.
|
||||
*
|
||||
* @param {Int} delta Pixels/Items. Positive means forward, negative means backward.
|
||||
* @param {Bool} immediate Reposition immediately without an animation.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
scrollerFactory.prototype.slideBy = function (delta, immediate) {
|
||||
if (!delta) {
|
||||
return;
|
||||
}
|
||||
this.slideTo(this._pos.dest + delta, immediate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Core method for handling `toLocation` methods.
|
||||
*
|
||||
* @param {String} location
|
||||
* @param {Mixed} item
|
||||
* @param {Bool} immediate
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
scrollerFactory.prototype.to = function (location, item, immediate) {
|
||||
// Optional arguments logic
|
||||
if (type(item) === 'boolean') {
|
||||
immediate = item;
|
||||
item = undefined;
|
||||
}
|
||||
|
||||
if (item === undefined) {
|
||||
this.slideTo(this._pos[location], immediate);
|
||||
} else {
|
||||
|
||||
//if (!transform) {
|
||||
|
||||
// item.scrollIntoView();
|
||||
// return;
|
||||
//}
|
||||
|
||||
var itemPos = this.getPos(item);
|
||||
|
||||
if (itemPos) {
|
||||
this.slideTo(itemPos[location], immediate, itemPos);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Animate element or the whole SLIDEE to the start of the frame.
|
||||
*
|
||||
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
|
||||
* @param {Bool} immediate Reposition immediately without an animation.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
scrollerFactory.prototype.toStart = function (item, immediate) {
|
||||
this.to('start', item, immediate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Animate element or the whole SLIDEE to the end of the frame.
|
||||
*
|
||||
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
|
||||
* @param {Bool} immediate Reposition immediately without an animation.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
scrollerFactory.prototype.toEnd = function (item, immediate) {
|
||||
this.to('end', item, immediate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Animate element or the whole SLIDEE to the center of the frame.
|
||||
*
|
||||
* @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE.
|
||||
* @param {Bool} immediate Reposition immediately without an animation.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
scrollerFactory.prototype.toCenter = function (item, immediate) {
|
||||
this.to('center', item, immediate);
|
||||
};
|
||||
|
||||
scrollerFactory.create = function (frame, options) {
|
||||
var instance = new scrollerFactory(frame, options);
|
||||
return Promise.resolve(instance);
|
||||
};
|
||||
|
||||
return scrollerFactory;
|
||||
});
|
|
@ -1,41 +0,0 @@
|
|||
define(['dom'], function (dom) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Copyright 2012, Digital Fusion
|
||||
* Licensed under the MIT license.
|
||||
* http://teamdf.com/jquery-plugins/license/
|
||||
*
|
||||
* @author Sam Sehnert
|
||||
* @desc A small plugin that checks whether elements are within
|
||||
* the user visible viewport of a web browser.
|
||||
* only accounts for vertical position, not horizontal.
|
||||
*/
|
||||
function visibleInViewport(elem, partial, thresholdX, thresholdY) {
|
||||
|
||||
thresholdX = thresholdX || 0;
|
||||
thresholdY = thresholdY || 0;
|
||||
|
||||
if (!elem.getBoundingClientRect) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var windowSize = dom.getWindowSize();
|
||||
|
||||
var vpWidth = windowSize.innerWidth;
|
||||
var vpHeight = windowSize.innerHeight;
|
||||
|
||||
// Use this native browser method, if available.
|
||||
var rec = elem.getBoundingClientRect();
|
||||
var tViz = rec.top >= 0 && rec.top < vpHeight + thresholdY;
|
||||
var bViz = rec.bottom > 0 && rec.bottom <= vpHeight + thresholdY;
|
||||
var lViz = rec.left >= 0 && rec.left < vpWidth + thresholdX;
|
||||
var rViz = rec.right > 0 && rec.right <= vpWidth + thresholdX;
|
||||
var vVisible = partial ? tViz || bViz : tViz && bViz;
|
||||
var hVisible = partial ? lViz || rViz : lViz && rViz;
|
||||
|
||||
return vVisible && hVisible;
|
||||
}
|
||||
|
||||
return visibleInViewport;
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue