mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Remove focus-prevent-scroll, migrate gamepadtokey and chromecastHelper to ES6
This commit is contained in:
parent
e2aff66203
commit
58361ce70c
8 changed files with 540 additions and 569 deletions
|
@ -62,6 +62,7 @@
|
||||||
"epubjs": "^0.3.85",
|
"epubjs": "^0.3.85",
|
||||||
"fast-text-encoding": "^1.0.3",
|
"fast-text-encoding": "^1.0.3",
|
||||||
"flv.js": "^1.5.0",
|
"flv.js": "^1.5.0",
|
||||||
|
"focus-options-polyfill": "^1.5.0",
|
||||||
"headroom.js": "^0.11.0",
|
"headroom.js": "^0.11.0",
|
||||||
"hls.js": "^0.14.7",
|
"hls.js": "^0.14.7",
|
||||||
"howler": "^2.2.0",
|
"howler": "^2.2.0",
|
||||||
|
@ -278,6 +279,7 @@
|
||||||
"src/plugins/backdropScreensaver/plugin.js",
|
"src/plugins/backdropScreensaver/plugin.js",
|
||||||
"src/plugins/bookPlayer/plugin.js",
|
"src/plugins/bookPlayer/plugin.js",
|
||||||
"src/plugins/bookPlayer/tableOfContents.js",
|
"src/plugins/bookPlayer/tableOfContents.js",
|
||||||
|
"src/plugins/chromecastPlayer/chromecastHelper.js",
|
||||||
"src/plugins/photoPlayer/plugin.js",
|
"src/plugins/photoPlayer/plugin.js",
|
||||||
"src/plugins/youtubePlayer/plugin.js",
|
"src/plugins/youtubePlayer/plugin.js",
|
||||||
"src/scripts/alphanumericshortcuts.js",
|
"src/scripts/alphanumericshortcuts.js",
|
||||||
|
|
|
@ -10,6 +10,11 @@ _define('fetch', function() {
|
||||||
return fetch;
|
return fetch;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var focusPreventScroll = require('focus-options-polyfill');
|
||||||
|
_define('focus-options-polyfill', function() {
|
||||||
|
return focusPreventScroll;
|
||||||
|
});
|
||||||
|
|
||||||
// Blurhash
|
// Blurhash
|
||||||
var blurhash = require('blurhash');
|
var blurhash = require('blurhash');
|
||||||
_define('blurhash', function() {
|
_define('blurhash', function() {
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
// TODO: Move to external library (https://github.com/calvellido/focus-options-polyfill)
|
|
||||||
// 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,229 +1,229 @@
|
||||||
define(['events'], function (events) {
|
import events from 'events';
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// LinkParser
|
// LinkParser
|
||||||
|
//
|
||||||
|
// https://github.com/ravisorg/LinkParser
|
||||||
|
//
|
||||||
|
// Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and
|
||||||
|
// IPv6, unrecognised TLDs, and more.
|
||||||
|
//
|
||||||
|
// This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||||
|
// http://creativecommons.org/licenses/by-sa/4.0/
|
||||||
|
(function () {
|
||||||
|
// Original URL regex from the Android android.text.util.Linkify function, found here:
|
||||||
|
// http://stackoverflow.com/a/19696443
|
||||||
//
|
//
|
||||||
// https://github.com/ravisorg/LinkParser
|
// However there were problems with it, most probably related to the fact it was
|
||||||
|
// written in 2007, and it's been highly modified.
|
||||||
//
|
//
|
||||||
// Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and
|
// 1) I didn't like the fact that it was tied to specific TLDs, since new ones
|
||||||
// IPv6, unrecognised TLDs, and more.
|
// are being added all the time it wouldn't be reasonable to expect developer to
|
||||||
|
// be continually updating their regular expressions.
|
||||||
//
|
//
|
||||||
// This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
|
// 2) It didn't allow unicode characters in the domains which are now allowed in
|
||||||
// http://creativecommons.org/licenses/by-sa/4.0/
|
// many languages, (including some IDN TLDs). Again these are constantly being
|
||||||
(function () {
|
// added to and it doesn't seem reasonable to hard-code them. Note this ended up
|
||||||
// Original URL regex from the Android android.text.util.Linkify function, found here:
|
// not being possible in standard JS due to the way it handles multibyte strings.
|
||||||
// http://stackoverflow.com/a/19696443
|
// It is possible using XRegExp, however a big performance hit results. Disabled
|
||||||
//
|
// for now.
|
||||||
// However there were problems with it, most probably related to the fact it was
|
//
|
||||||
// written in 2007, and it's been highly modified.
|
// 3) It didn't allow for IPv6 hostnames
|
||||||
//
|
// IPv6 regex from http://stackoverflow.com/a/17871737
|
||||||
// 1) I didn't like the fact that it was tied to specific TLDs, since new ones
|
//
|
||||||
// are being added all the time it wouldn't be reasonable to expect developer to
|
// 4) It was very poorly commented
|
||||||
// be continually updating their regular expressions.
|
//
|
||||||
//
|
// 5) It wasn't as smart as it could have been about what should be part of a
|
||||||
// 2) It didn't allow unicode characters in the domains which are now allowed in
|
// URL and what should be part of human language.
|
||||||
// many languages, (including some IDN TLDs). Again these are constantly being
|
|
||||||
// added to and it doesn't seem reasonable to hard-code them. Note this ended up
|
|
||||||
// not being possible in standard JS due to the way it handles multibyte strings.
|
|
||||||
// It is possible using XRegExp, however a big performance hit results. Disabled
|
|
||||||
// for now.
|
|
||||||
//
|
|
||||||
// 3) It didn't allow for IPv6 hostnames
|
|
||||||
// IPv6 regex from http://stackoverflow.com/a/17871737
|
|
||||||
//
|
|
||||||
// 4) It was very poorly commented
|
|
||||||
//
|
|
||||||
// 5) It wasn't as smart as it could have been about what should be part of a
|
|
||||||
// URL and what should be part of human language.
|
|
||||||
|
|
||||||
var protocols = '(?:(?:http|https|rtsp|ftp):\\/\\/)';
|
const protocols = '(?:(?:http|https|rtsp|ftp):\\/\\/)';
|
||||||
var credentials = "(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}" // username (1-64 normal or url escaped characters)
|
const credentials = "(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}" // username (1-64 normal or url escaped characters)
|
||||||
+ "(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?" // followed by optional password (: + 1-25 normal or url escaped characters)
|
+ "(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?" // followed by optional password (: + 1-25 normal or url escaped characters)
|
||||||
+ '\\@)';
|
+ '\\@)';
|
||||||
|
|
||||||
// IPv6 Regex http://forums.intermapper.com/viewtopic.php?t=452
|
// IPv6 Regex http://forums.intermapper.com/viewtopic.php?t=452
|
||||||
// by Dartware, LLC is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License
|
// by Dartware, LLC is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License
|
||||||
// http://intermapper.com/
|
// http://intermapper.com/
|
||||||
var ipv6 = '('
|
const ipv6 = '('
|
||||||
+ '(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))'
|
+ '(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))'
|
||||||
+ '|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))'
|
+ '|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))'
|
||||||
+ '|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))'
|
+ '|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))'
|
||||||
+ '|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
+ '|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||||
+ '|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
+ '|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||||
+ '|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
+ '|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||||
+ '|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
+ '|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||||
+ '|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
+ '|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||||
+ ')(%.+)?';
|
+ ')(%.+)?';
|
||||||
|
|
||||||
var ipv4 = '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.'
|
const ipv4 = '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.'
|
||||||
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.'
|
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.'
|
||||||
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.'
|
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.'
|
||||||
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])';
|
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])';
|
||||||
|
|
||||||
// This would have been a lot cleaner if JS RegExp supported conditionals...
|
// This would have been a lot cleaner if JS RegExp supported conditionals...
|
||||||
var linkRegExpString =
|
const linkRegExpString =
|
||||||
|
|
||||||
// begin match for protocol / username / password / host
|
// begin match for protocol / username / password / host
|
||||||
'(?:'
|
'(?:'
|
||||||
|
|
||||||
// ============================
|
// ============================
|
||||||
// If we have a recognized protocol at the beginning of the URL, we're
|
// If we have a recognized protocol at the beginning of the URL, we're
|
||||||
// more relaxed about what we accept, because we assume the user wants
|
// more relaxed about what we accept, because we assume the user wants
|
||||||
// this to be a URL, and we're not accidentally matching human language
|
// this to be a URL, and we're not accidentally matching human language
|
||||||
+ protocols + '?'
|
+ protocols + '?'
|
||||||
|
|
||||||
// optional username:password@
|
// optional username:password@
|
||||||
+ credentials + '?'
|
+ credentials + '?'
|
||||||
|
|
||||||
// IP address (both v4 and v6)
|
// IP address (both v4 and v6)
|
||||||
+ '(?:'
|
+ '(?:'
|
||||||
|
|
||||||
// IPv6
|
// IPv6
|
||||||
+ ipv6
|
+ ipv6
|
||||||
|
|
||||||
// IPv4
|
// IPv4
|
||||||
+ '|' + ipv4
|
+ '|' + ipv4
|
||||||
|
|
||||||
+ ')'
|
+ ')'
|
||||||
|
|
||||||
// end match for protocol / username / password / host
|
// end match for protocol / username / password / host
|
||||||
+ ')'
|
+ ')'
|
||||||
|
|
||||||
// optional port number
|
// optional port number
|
||||||
+ '(?:\\:\\d{1,5})?'
|
+ '(?:\\:\\d{1,5})?'
|
||||||
|
|
||||||
// plus optional path and query params (no unicode allowed here?)
|
// plus optional path and query params (no unicode allowed here?)
|
||||||
+ '(?:'
|
+ '(?:'
|
||||||
+ '\\/(?:'
|
+ '\\/(?:'
|
||||||
// some characters we'll accept because it's unlikely human language
|
// some characters we'll accept because it's unlikely human language
|
||||||
// would use them after a URL unless they were part of the url
|
// would use them after a URL unless they were part of the url
|
||||||
+ '(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])'
|
+ '(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])'
|
||||||
+ '|(?:\\%[a-f0-9]{2})'
|
+ '|(?:\\%[a-f0-9]{2})'
|
||||||
// some characters are much more likely to be used AFTER a url and
|
// some characters are much more likely to be used AFTER a url and
|
||||||
// were not intended to be included in the url itself. Mostly end
|
// were not intended to be included in the url itself. Mostly end
|
||||||
// of sentence type things. It's also likely that the URL would
|
// of sentence type things. It's also likely that the URL would
|
||||||
// still work if any of these characters were missing from the end
|
// still work if any of these characters were missing from the end
|
||||||
// because we parsed it incorrectly. For these characters to be accepted
|
// because we parsed it incorrectly. For these characters to be accepted
|
||||||
// they must be followed by another character that we're reasonably
|
// they must be followed by another character that we're reasonably
|
||||||
// sure is part of the url
|
// sure is part of the url
|
||||||
+ "|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})))"
|
+ "|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})))"
|
||||||
+ ')*'
|
+ ')*'
|
||||||
+ '|\\b|\$'
|
+ '|\\b|\$'
|
||||||
+ ')';
|
+ ')';
|
||||||
|
|
||||||
// regex = XRegExp(regex,'gi');
|
// regex = XRegExp(regex,'gi');
|
||||||
var linkRegExp = RegExp(linkRegExpString, 'gi');
|
const linkRegExp = RegExp(linkRegExpString, 'gi');
|
||||||
|
|
||||||
var protocolRegExp = RegExp('^' + protocols, 'i');
|
const protocolRegExp = RegExp('^' + protocols, 'i');
|
||||||
|
|
||||||
// if url doesn't begin with a known protocol, add http by default
|
// if url doesn't begin with a known protocol, add http by default
|
||||||
function ensureProtocol(url) {
|
function ensureProtocol(url) {
|
||||||
if (!url.match(protocolRegExp)) {
|
if (!url.match(protocolRegExp)) {
|
||||||
url = 'http://' + url;
|
url = 'http://' + url;
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
// look for links in the text
|
// look for links in the text
|
||||||
var LinkParser = {
|
const LinkParser = {
|
||||||
parse: function (text) {
|
parse: function (text) {
|
||||||
var links = [];
|
const links = [];
|
||||||
var match;
|
let match;
|
||||||
|
|
||||||
// eslint-disable-next-line no-cond-assign
|
// eslint-disable-next-line no-cond-assign
|
||||||
while (match = linkRegExp.exec(text)) {
|
while (match = linkRegExp.exec(text)) {
|
||||||
console.debug(match);
|
console.debug(match);
|
||||||
var txt = match[0];
|
const txt = match[0];
|
||||||
var pos = match.index;
|
const pos = match.index;
|
||||||
var len = txt.length;
|
const len = txt.length;
|
||||||
var url = ensureProtocol(text);
|
const url = ensureProtocol(text);
|
||||||
links.push({ 'pos': pos, 'text': txt, 'len': len, 'url': url });
|
links.push({ 'pos': pos, 'text': txt, 'len': len, 'url': url });
|
||||||
}
|
|
||||||
|
|
||||||
return links;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
return links;
|
||||||
|
|
||||||
window.LinkParser = LinkParser;
|
|
||||||
})();
|
|
||||||
|
|
||||||
var cache = {};
|
|
||||||
|
|
||||||
function isValidIpAddress(address) {
|
|
||||||
var links = LinkParser.parse(address);
|
|
||||||
|
|
||||||
return links.length == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isLocalIpAddress(address) {
|
|
||||||
address = address.toLowerCase();
|
|
||||||
|
|
||||||
if (address.indexOf('127.0.0.1') !== -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (address.indexOf('localhost') !== -1) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getServerAddress(apiClient) {
|
|
||||||
var serverAddress = apiClient.serverAddress();
|
|
||||||
|
|
||||||
if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) {
|
|
||||||
return Promise.resolve(serverAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
var cachedValue = getCachedValue(serverAddress);
|
|
||||||
if (cachedValue) {
|
|
||||||
return Promise.resolve(cachedValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiClient.getEndpointInfo().then(function (endpoint) {
|
|
||||||
if (endpoint.IsInNetwork) {
|
|
||||||
return apiClient.getPublicSystemInfo().then(function (info) {
|
|
||||||
var localAddress = info.LocalAddress;
|
|
||||||
if (!localAddress) {
|
|
||||||
console.debug('No valid local address returned, defaulting to external one');
|
|
||||||
localAddress = serverAddress;
|
|
||||||
}
|
|
||||||
addToCache(serverAddress, localAddress);
|
|
||||||
return localAddress;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
addToCache(serverAddress, serverAddress);
|
|
||||||
return serverAddress;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearCache() {
|
|
||||||
cache = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function addToCache(key, value) {
|
|
||||||
cache[key] = {
|
|
||||||
value: value,
|
|
||||||
time: new Date().getTime()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCachedValue(key) {
|
|
||||||
var obj = cache[key];
|
|
||||||
|
|
||||||
if (obj && (new Date().getTime() - obj.time) < 180000) {
|
|
||||||
return obj.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
events.on(ConnectionManager, 'localusersignedin', clearCache);
|
|
||||||
events.on(ConnectionManager, 'localusersignedout', clearCache);
|
|
||||||
|
|
||||||
return {
|
|
||||||
getServerAddress: getServerAddress
|
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
window.LinkParser = LinkParser;
|
||||||
|
})();
|
||||||
|
|
||||||
|
let cache = {};
|
||||||
|
|
||||||
|
// TODO: Replace with isIP (https://www.npmjs.com/package/is-ip)
|
||||||
|
function isValidIpAddress(address) {
|
||||||
|
const links = LinkParser.parse(address);
|
||||||
|
|
||||||
|
return links.length == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add IPv6 support. Potentially replace with isLocalhost (https://www.npmjs.com/package/is-localhost-ip)
|
||||||
|
function isLocalIpAddress(address) {
|
||||||
|
address = address.toLowerCase();
|
||||||
|
|
||||||
|
if (address.includes('127.0.0.1')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (address.includes('localhost')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getServerAddress(apiClient) {
|
||||||
|
const serverAddress = apiClient.serverAddress();
|
||||||
|
|
||||||
|
if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) {
|
||||||
|
return Promise.resolve(serverAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedValue = getCachedValue(serverAddress);
|
||||||
|
if (cachedValue) {
|
||||||
|
return Promise.resolve(cachedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiClient.getEndpointInfo().then(function (endpoint) {
|
||||||
|
if (endpoint.IsInNetwork) {
|
||||||
|
return apiClient.getPublicSystemInfo().then(function (info) {
|
||||||
|
let localAddress = info.LocalAddress;
|
||||||
|
if (!localAddress) {
|
||||||
|
console.debug('No valid local address returned, defaulting to external one');
|
||||||
|
localAddress = serverAddress;
|
||||||
|
}
|
||||||
|
addToCache(serverAddress, localAddress);
|
||||||
|
return localAddress;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
addToCache(serverAddress, serverAddress);
|
||||||
|
return serverAddress;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearCache() {
|
||||||
|
cache = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToCache(key, value) {
|
||||||
|
cache[key] = {
|
||||||
|
value: value,
|
||||||
|
time: new Date().getTime()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCachedValue(key) {
|
||||||
|
const obj = cache[key];
|
||||||
|
|
||||||
|
if (obj && (new Date().getTime() - obj.time) < 180000) {
|
||||||
|
return obj.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.on(ConnectionManager, 'localusersignedin', clearCache);
|
||||||
|
events.on(ConnectionManager, 'localusersignedout', clearCache);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getServerAddress: getServerAddress
|
||||||
|
};
|
||||||
|
|
|
@ -366,6 +366,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
require(['./chromecastHelper'], function (chromecastHelper) {
|
require(['./chromecastHelper'], function (chromecastHelper) {
|
||||||
|
chromecastHelper = chromecastHelper.default || chromecastHelper;
|
||||||
|
|
||||||
chromecastHelper.getServerAddress(apiClient).then(function (serverAddress) {
|
chromecastHelper.getServerAddress(apiClient).then(function (serverAddress) {
|
||||||
message.serverAddress = serverAddress;
|
message.serverAddress = serverAddress;
|
||||||
player.sendMessageInternal(message).then(resolve, reject);
|
player.sendMessageInternal(message).then(resolve, reject);
|
||||||
|
|
|
@ -19,384 +19,383 @@
|
||||||
// # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// # 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
|
// # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// # THE SOFTWARE.
|
// # THE SOFTWARE.
|
||||||
require(['apphost'], function (appHost) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var _GAMEPAD_A_BUTTON_INDEX = 0;
|
import appHost from 'apphost';
|
||||||
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 _GAMEPAD_A_BUTTON_INDEX = 0;
|
||||||
var _leftThumbstickDownPressed = false;
|
var _GAMEPAD_B_BUTTON_INDEX = 1;
|
||||||
var _leftThumbstickLeftPressed = false;
|
var _GAMEPAD_DPAD_UP_BUTTON_INDEX = 12;
|
||||||
var _leftThumbstickRightPressed = false;
|
var _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13;
|
||||||
var _dPadUpPressed = false;
|
var _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14;
|
||||||
var _dPadDownPressed = false;
|
var _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15;
|
||||||
var _dPadLeftPressed = false;
|
var _GAMEPAD_A_KEY = 'GamepadA';
|
||||||
var _dPadRightPressed = false;
|
var _GAMEPAD_B_KEY = 'GamepadB';
|
||||||
var _gamepadAPressed = false;
|
var _GAMEPAD_DPAD_UP_KEY = 'GamepadDPadUp';
|
||||||
var _gamepadBPressed = false;
|
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;
|
||||||
|
|
||||||
// The set of buttons on the gamepad we listen for.
|
var _leftThumbstickUpPressed = false;
|
||||||
var ProcessedButtons = [
|
var _leftThumbstickDownPressed = false;
|
||||||
_GAMEPAD_DPAD_UP_BUTTON_INDEX,
|
var _leftThumbstickLeftPressed = false;
|
||||||
_GAMEPAD_DPAD_DOWN_BUTTON_INDEX,
|
var _leftThumbstickRightPressed = false;
|
||||||
_GAMEPAD_DPAD_LEFT_BUTTON_INDEX,
|
var _dPadUpPressed = false;
|
||||||
_GAMEPAD_DPAD_RIGHT_BUTTON_INDEX,
|
var _dPadDownPressed = false;
|
||||||
_GAMEPAD_A_BUTTON_INDEX,
|
var _dPadLeftPressed = false;
|
||||||
_GAMEPAD_B_BUTTON_INDEX
|
var _dPadRightPressed = false;
|
||||||
];
|
var _gamepadAPressed = false;
|
||||||
|
var _gamepadBPressed = false;
|
||||||
|
|
||||||
var _ButtonPressedState = {};
|
// The set of buttons on the gamepad we listen for.
|
||||||
_ButtonPressedState.getgamepadA = function () {
|
var ProcessedButtons = [
|
||||||
return _gamepadAPressed;
|
_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
|
||||||
|
];
|
||||||
|
|
||||||
_ButtonPressedState.setgamepadA = function (newPressedState) {
|
var _ButtonPressedState = {};
|
||||||
raiseKeyEvent(_gamepadAPressed, newPressedState, _GAMEPAD_A_KEY, _GAMEPAD_A_KEYCODE, false, true);
|
_ButtonPressedState.getgamepadA = function () {
|
||||||
_gamepadAPressed = newPressedState;
|
return _gamepadAPressed;
|
||||||
};
|
};
|
||||||
|
|
||||||
_ButtonPressedState.getgamepadB = function () {
|
_ButtonPressedState.setgamepadA = function (newPressedState) {
|
||||||
return _gamepadBPressed;
|
raiseKeyEvent(_gamepadAPressed, newPressedState, _GAMEPAD_A_KEY, _GAMEPAD_A_KEYCODE, false, true);
|
||||||
};
|
_gamepadAPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setgamepadB = function (newPressedState) {
|
_ButtonPressedState.getgamepadB = function () {
|
||||||
raiseKeyEvent(_gamepadBPressed, newPressedState, _GAMEPAD_B_KEY, _GAMEPAD_B_KEYCODE);
|
return _gamepadBPressed;
|
||||||
_gamepadBPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
_ButtonPressedState.getleftThumbstickUp = function () {
|
_ButtonPressedState.setgamepadB = function (newPressedState) {
|
||||||
return _leftThumbstickUpPressed;
|
raiseKeyEvent(_gamepadBPressed, newPressedState, _GAMEPAD_B_KEY, _GAMEPAD_B_KEYCODE);
|
||||||
};
|
_gamepadBPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setleftThumbstickUp = function (newPressedState) {
|
_ButtonPressedState.getleftThumbstickUp = function () {
|
||||||
raiseKeyEvent(_leftThumbstickUpPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_UP_KEY, _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE, true);
|
return _leftThumbstickUpPressed;
|
||||||
_leftThumbstickUpPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
_ButtonPressedState.getleftThumbstickDown = function () {
|
_ButtonPressedState.setleftThumbstickUp = function (newPressedState) {
|
||||||
return _leftThumbstickDownPressed;
|
raiseKeyEvent(_leftThumbstickUpPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_UP_KEY, _GAMEPAD_LEFT_THUMBSTICK_UP_KEYCODE, true);
|
||||||
};
|
_leftThumbstickUpPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setleftThumbstickDown = function (newPressedState) {
|
_ButtonPressedState.getleftThumbstickDown = function () {
|
||||||
raiseKeyEvent(_leftThumbstickDownPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE, true);
|
return _leftThumbstickDownPressed;
|
||||||
_leftThumbstickDownPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
_ButtonPressedState.getleftThumbstickLeft = function () {
|
_ButtonPressedState.setleftThumbstickDown = function (newPressedState) {
|
||||||
return _leftThumbstickLeftPressed;
|
raiseKeyEvent(_leftThumbstickDownPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY, _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEYCODE, true);
|
||||||
};
|
_leftThumbstickDownPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setleftThumbstickLeft = function (newPressedState) {
|
_ButtonPressedState.getleftThumbstickLeft = function () {
|
||||||
raiseKeyEvent(_leftThumbstickLeftPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE, true);
|
return _leftThumbstickLeftPressed;
|
||||||
_leftThumbstickLeftPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
_ButtonPressedState.getleftThumbstickRight = function () {
|
_ButtonPressedState.setleftThumbstickLeft = function (newPressedState) {
|
||||||
return _leftThumbstickRightPressed;
|
raiseKeyEvent(_leftThumbstickLeftPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY, _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEYCODE, true);
|
||||||
};
|
_leftThumbstickLeftPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setleftThumbstickRight = function (newPressedState) {
|
_ButtonPressedState.getleftThumbstickRight = function () {
|
||||||
raiseKeyEvent(_leftThumbstickRightPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE, true);
|
return _leftThumbstickRightPressed;
|
||||||
_leftThumbstickRightPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
_ButtonPressedState.getdPadUp = function () {
|
_ButtonPressedState.setleftThumbstickRight = function (newPressedState) {
|
||||||
return _dPadUpPressed;
|
raiseKeyEvent(_leftThumbstickRightPressed, newPressedState, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY, _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEYCODE, true);
|
||||||
};
|
_leftThumbstickRightPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setdPadUp = function (newPressedState) {
|
_ButtonPressedState.getdPadUp = function () {
|
||||||
raiseKeyEvent(_dPadUpPressed, newPressedState, _GAMEPAD_DPAD_UP_KEY, _GAMEPAD_DPAD_UP_KEYCODE, true);
|
return _dPadUpPressed;
|
||||||
_dPadUpPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
_ButtonPressedState.getdPadDown = function () {
|
_ButtonPressedState.setdPadUp = function (newPressedState) {
|
||||||
return _dPadDownPressed;
|
raiseKeyEvent(_dPadUpPressed, newPressedState, _GAMEPAD_DPAD_UP_KEY, _GAMEPAD_DPAD_UP_KEYCODE, true);
|
||||||
};
|
_dPadUpPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setdPadDown = function (newPressedState) {
|
_ButtonPressedState.getdPadDown = function () {
|
||||||
raiseKeyEvent(_dPadDownPressed, newPressedState, _GAMEPAD_DPAD_DOWN_KEY, _GAMEPAD_DPAD_DOWN_KEYCODE, true);
|
return _dPadDownPressed;
|
||||||
_dPadDownPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
_ButtonPressedState.getdPadLeft = function () {
|
_ButtonPressedState.setdPadDown = function (newPressedState) {
|
||||||
return _dPadLeftPressed;
|
raiseKeyEvent(_dPadDownPressed, newPressedState, _GAMEPAD_DPAD_DOWN_KEY, _GAMEPAD_DPAD_DOWN_KEYCODE, true);
|
||||||
};
|
_dPadDownPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setdPadLeft = function (newPressedState) {
|
_ButtonPressedState.getdPadLeft = function () {
|
||||||
raiseKeyEvent(_dPadLeftPressed, newPressedState, _GAMEPAD_DPAD_LEFT_KEY, _GAMEPAD_DPAD_LEFT_KEYCODE, true);
|
return _dPadLeftPressed;
|
||||||
_dPadLeftPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
_ButtonPressedState.getdPadRight = function () {
|
_ButtonPressedState.setdPadLeft = function (newPressedState) {
|
||||||
return _dPadRightPressed;
|
raiseKeyEvent(_dPadLeftPressed, newPressedState, _GAMEPAD_DPAD_LEFT_KEY, _GAMEPAD_DPAD_LEFT_KEYCODE, true);
|
||||||
};
|
_dPadLeftPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
_ButtonPressedState.setdPadRight = function (newPressedState) {
|
_ButtonPressedState.getdPadRight = function () {
|
||||||
raiseKeyEvent(_dPadRightPressed, newPressedState, _GAMEPAD_DPAD_RIGHT_KEY, _GAMEPAD_DPAD_RIGHT_KEYCODE, true);
|
return _dPadRightPressed;
|
||||||
_dPadRightPressed = newPressedState;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
var times = {};
|
_ButtonPressedState.setdPadRight = function (newPressedState) {
|
||||||
|
raiseKeyEvent(_dPadRightPressed, newPressedState, _GAMEPAD_DPAD_RIGHT_KEY, _GAMEPAD_DPAD_RIGHT_KEYCODE, true);
|
||||||
|
_dPadRightPressed = newPressedState;
|
||||||
|
};
|
||||||
|
|
||||||
function throttle(key) {
|
var times = {};
|
||||||
var time = times[key] || 0;
|
|
||||||
var now = new Date().getTime();
|
|
||||||
|
|
||||||
if ((now - time) >= 200) {
|
function throttle(key) {
|
||||||
//times[key] = now;
|
var time = times[key] || 0;
|
||||||
return true;
|
var now = new Date().getTime();
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ((now - time) >= 200) {
|
||||||
|
//times[key] = now;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function raiseEvent(name, key, keyCode) {
|
return false;
|
||||||
if (!allowInput()) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var event = document.createEvent('Event');
|
function resetThrottle(key) {
|
||||||
event.initEvent(name, true, true);
|
times[key] = new Date().getTime();
|
||||||
event.key = key;
|
}
|
||||||
event.keyCode = keyCode;
|
|
||||||
(document.activeElement || document.body).dispatchEvent(event);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickElement(elem) {
|
if (appHost.getWindowState() === 'Minimized') {
|
||||||
if (!allowInput()) {
|
return false;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
elem.click();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function raiseKeyEvent(oldPressedState, newPressedState, key, keyCode, enableRepeatKeyDown, clickonKeyUp) {
|
return true;
|
||||||
// No-op if oldPressedState === newPressedState
|
}
|
||||||
if (newPressedState === true) {
|
|
||||||
// button down
|
|
||||||
var fire = false;
|
|
||||||
|
|
||||||
// always fire if this is the initial down press
|
function raiseEvent(name, key, keyCode) {
|
||||||
if (oldPressedState === false) {
|
if (!allowInput()) {
|
||||||
fire = true;
|
return;
|
||||||
resetThrottle(key);
|
}
|
||||||
} else if (enableRepeatKeyDown) {
|
|
||||||
fire = throttle(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fire && keyCode) {
|
var event = document.createEvent('Event');
|
||||||
raiseEvent('keydown', key, keyCode);
|
event.initEvent(name, true, true);
|
||||||
}
|
event.key = key;
|
||||||
} else if (newPressedState === false && oldPressedState === true) {
|
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);
|
resetThrottle(key);
|
||||||
|
} else if (enableRepeatKeyDown) {
|
||||||
|
fire = throttle(key);
|
||||||
|
}
|
||||||
|
|
||||||
// button up
|
if (fire && keyCode) {
|
||||||
if (keyCode) {
|
raiseEvent('keydown', key, keyCode);
|
||||||
raiseEvent('keyup', key, keyCode);
|
}
|
||||||
}
|
} else if (newPressedState === false && oldPressedState === true) {
|
||||||
if (clickonKeyUp) {
|
resetThrottle(key);
|
||||||
clickElement(document.activeElement || window);
|
|
||||||
}
|
// button up
|
||||||
|
if (keyCode) {
|
||||||
|
raiseEvent('keyup', key, keyCode);
|
||||||
|
}
|
||||||
|
if (clickonKeyUp) {
|
||||||
|
clickElement(document.activeElement || window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var inputLoopTimer;
|
var inputLoopTimer;
|
||||||
function runInputLoop() {
|
function runInputLoop() {
|
||||||
// Get the latest gamepad state.
|
// Get the latest gamepad state.
|
||||||
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
|
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
|
||||||
for (var i = 0, len = gamepads.length; i < len; i++) {
|
for (var i = 0, len = gamepads.length; i < len; i++) {
|
||||||
var gamepad = gamepads[i];
|
var gamepad = gamepads[i];
|
||||||
if (!gamepad) {
|
if (!gamepad) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Iterate through the axes
|
// Iterate through the axes
|
||||||
var axes = gamepad.axes;
|
var axes = gamepad.axes;
|
||||||
var leftStickX = axes[0];
|
var leftStickX = axes[0];
|
||||||
var leftStickY = axes[1];
|
var leftStickY = axes[1];
|
||||||
if (leftStickX > _THUMB_STICK_THRESHOLD) { // Right
|
if (leftStickX > _THUMB_STICK_THRESHOLD) { // Right
|
||||||
_ButtonPressedState.setleftThumbstickRight(true);
|
_ButtonPressedState.setleftThumbstickRight(true);
|
||||||
} else if (leftStickX < -_THUMB_STICK_THRESHOLD) { // Left
|
} else if (leftStickX < -_THUMB_STICK_THRESHOLD) { // Left
|
||||||
_ButtonPressedState.setleftThumbstickLeft(true);
|
_ButtonPressedState.setleftThumbstickLeft(true);
|
||||||
} else if (leftStickY < -_THUMB_STICK_THRESHOLD) { // Up
|
} else if (leftStickY < -_THUMB_STICK_THRESHOLD) { // Up
|
||||||
_ButtonPressedState.setleftThumbstickUp(true);
|
_ButtonPressedState.setleftThumbstickUp(true);
|
||||||
} else if (leftStickY > _THUMB_STICK_THRESHOLD) { // Down
|
} else if (leftStickY > _THUMB_STICK_THRESHOLD) { // Down
|
||||||
_ButtonPressedState.setleftThumbstickDown(true);
|
_ButtonPressedState.setleftThumbstickDown(true);
|
||||||
} else {
|
} else {
|
||||||
_ButtonPressedState.setleftThumbstickLeft(false);
|
_ButtonPressedState.setleftThumbstickLeft(false);
|
||||||
_ButtonPressedState.setleftThumbstickRight(false);
|
_ButtonPressedState.setleftThumbstickRight(false);
|
||||||
_ButtonPressedState.setleftThumbstickUp(false);
|
_ButtonPressedState.setleftThumbstickUp(false);
|
||||||
_ButtonPressedState.setleftThumbstickDown(false);
|
_ButtonPressedState.setleftThumbstickDown(false);
|
||||||
}
|
}
|
||||||
// Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed.
|
// Iterate through the buttons to see if Left thumbstick, DPad, A and B are pressed.
|
||||||
var buttons = gamepad.buttons;
|
var buttons = gamepad.buttons;
|
||||||
for (var j = 0, len = buttons.length; j < len; j++) {
|
for (var j = 0, len = buttons.length; j < len; j++) {
|
||||||
if (ProcessedButtons.indexOf(j) !== -1) {
|
if (ProcessedButtons.indexOf(j) !== -1) {
|
||||||
if (buttons[j].pressed) {
|
if (buttons[j].pressed) {
|
||||||
switch (j) {
|
switch (j) {
|
||||||
case _GAMEPAD_DPAD_UP_BUTTON_INDEX:
|
case _GAMEPAD_DPAD_UP_BUTTON_INDEX:
|
||||||
_ButtonPressedState.setdPadUp(true);
|
_ButtonPressedState.setdPadUp(true);
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX:
|
case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX:
|
||||||
_ButtonPressedState.setdPadDown(true);
|
_ButtonPressedState.setdPadDown(true);
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX:
|
case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX:
|
||||||
_ButtonPressedState.setdPadLeft(true);
|
_ButtonPressedState.setdPadLeft(true);
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX:
|
case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX:
|
||||||
_ButtonPressedState.setdPadRight(true);
|
_ButtonPressedState.setdPadRight(true);
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_A_BUTTON_INDEX:
|
case _GAMEPAD_A_BUTTON_INDEX:
|
||||||
_ButtonPressedState.setgamepadA(true);
|
_ButtonPressedState.setgamepadA(true);
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_B_BUTTON_INDEX:
|
case _GAMEPAD_B_BUTTON_INDEX:
|
||||||
_ButtonPressedState.setgamepadB(true);
|
_ButtonPressedState.setgamepadB(true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// No-op
|
// No-op
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (j) {
|
switch (j) {
|
||||||
case _GAMEPAD_DPAD_UP_BUTTON_INDEX:
|
case _GAMEPAD_DPAD_UP_BUTTON_INDEX:
|
||||||
if (_ButtonPressedState.getdPadUp()) {
|
if (_ButtonPressedState.getdPadUp()) {
|
||||||
_ButtonPressedState.setdPadUp(false);
|
_ButtonPressedState.setdPadUp(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX:
|
case _GAMEPAD_DPAD_DOWN_BUTTON_INDEX:
|
||||||
if (_ButtonPressedState.getdPadDown()) {
|
if (_ButtonPressedState.getdPadDown()) {
|
||||||
_ButtonPressedState.setdPadDown(false);
|
_ButtonPressedState.setdPadDown(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX:
|
case _GAMEPAD_DPAD_LEFT_BUTTON_INDEX:
|
||||||
if (_ButtonPressedState.getdPadLeft()) {
|
if (_ButtonPressedState.getdPadLeft()) {
|
||||||
_ButtonPressedState.setdPadLeft(false);
|
_ButtonPressedState.setdPadLeft(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX:
|
case _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX:
|
||||||
if (_ButtonPressedState.getdPadRight()) {
|
if (_ButtonPressedState.getdPadRight()) {
|
||||||
_ButtonPressedState.setdPadRight(false);
|
_ButtonPressedState.setdPadRight(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_A_BUTTON_INDEX:
|
case _GAMEPAD_A_BUTTON_INDEX:
|
||||||
if (_ButtonPressedState.getgamepadA()) {
|
if (_ButtonPressedState.getgamepadA()) {
|
||||||
_ButtonPressedState.setgamepadA(false);
|
_ButtonPressedState.setgamepadA(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case _GAMEPAD_B_BUTTON_INDEX:
|
case _GAMEPAD_B_BUTTON_INDEX:
|
||||||
if (_ButtonPressedState.getgamepadB()) {
|
if (_ButtonPressedState.getgamepadB()) {
|
||||||
_ButtonPressedState.setgamepadB(false);
|
_ButtonPressedState.setgamepadB(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// No-op
|
// No-op
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Schedule the next one
|
|
||||||
inputLoopTimer = requestAnimationFrame(runInputLoop);
|
|
||||||
}
|
}
|
||||||
|
// Schedule the next one
|
||||||
|
inputLoopTimer = requestAnimationFrame(runInputLoop);
|
||||||
|
}
|
||||||
|
|
||||||
function startInputLoop() {
|
function startInputLoop() {
|
||||||
if (!inputLoopTimer) {
|
if (!inputLoopTimer) {
|
||||||
runInputLoop();
|
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 stopInputLoop() {
|
function onFocusOrGamepadAttach(e) {
|
||||||
cancelAnimationFrame(inputLoopTimer);
|
/* eslint-disable-next-line compat/compat */
|
||||||
inputLoopTimer = undefined;
|
if (isGamepadConnected() && document.hasFocus()) {
|
||||||
|
console.log('Gamepad connected! Starting input loop');
|
||||||
|
startInputLoop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isGamepadConnected() {
|
function onFocusOrGamepadDetach(e) {
|
||||||
var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */
|
/* eslint-disable-next-line compat/compat */
|
||||||
for (var i = 0, len = gamepads.length; i < len; i++) {
|
if (!isGamepadConnected() || !document.hasFocus()) {
|
||||||
var gamepad = gamepads[i];
|
console.log('Gamepad disconnected! No other gamepads are connected, stopping input loop');
|
||||||
if (gamepad && gamepad.connected) {
|
stopInputLoop();
|
||||||
return true;
|
} else {
|
||||||
}
|
console.log('Gamepad disconnected! There are gamepads still connected.');
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onFocusOrGamepadAttach(e) {
|
// Event listeners for any change in gamepads' state.
|
||||||
/* eslint-disable-next-line compat/compat */
|
window.addEventListener('gamepaddisconnected', onFocusOrGamepadDetach);
|
||||||
if (isGamepadConnected() && document.hasFocus()) {
|
window.addEventListener('gamepadconnected', onFocusOrGamepadAttach);
|
||||||
console.log('Gamepad connected! Starting input loop');
|
window.addEventListener('blur', onFocusOrGamepadDetach);
|
||||||
startInputLoop();
|
window.addEventListener('focus', onFocusOrGamepadAttach);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onFocusOrGamepadDetach(e) {
|
onFocusOrGamepadAttach();
|
||||||
/* 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.
|
// The gamepadInputEmulation is a string property that exists in JavaScript UWAs and in WebViews in UWAs.
|
||||||
window.addEventListener('gamepaddisconnected', onFocusOrGamepadDetach);
|
// It won't exist in Win8.1 style apps or browsers.
|
||||||
window.addEventListener('gamepadconnected', onFocusOrGamepadAttach);
|
if (window.navigator && typeof window.navigator.gamepadInputEmulation === 'string') {
|
||||||
window.addEventListener('blur', onFocusOrGamepadDetach);
|
// We want the gamepad to provide gamepad VK keyboard events rather than moving a
|
||||||
window.addEventListener('focus', onFocusOrGamepadAttach);
|
// mouse like cursor. Set to "keyboard", the gamepad will provide such keyboard events
|
||||||
|
// and provide input to the DOM navigator.getGamepads API.
|
||||||
onFocusOrGamepadAttach();
|
window.navigator.gamepadInputEmulation = 'gamepad';
|
||||||
|
}
|
||||||
// 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';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
|
@ -689,7 +689,8 @@ function initClient() {
|
||||||
'events',
|
'events',
|
||||||
'credentialprovider',
|
'credentialprovider',
|
||||||
'connectionManagerFactory',
|
'connectionManagerFactory',
|
||||||
'appStorage'
|
'appStorage',
|
||||||
|
'focus-options-polyfill'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
urlArgs: urlArgs,
|
urlArgs: urlArgs,
|
||||||
|
@ -698,7 +699,7 @@ function initClient() {
|
||||||
});
|
});
|
||||||
|
|
||||||
promise = require(['fetch'])
|
promise = require(['fetch'])
|
||||||
.then(() => require(['jQuery', 'polyfill', 'fast-text-encoding', 'intersection-observer', 'classlist-polyfill', 'css!assets/css/site', 'jellyfin-noto'], (jQuery) => {
|
.then(() => require(['jQuery', 'polyfill', 'fast-text-encoding', 'intersection-observer', 'classlist-polyfill', 'focus-options-polyfill', 'css!assets/css/site', 'jellyfin-noto'], (jQuery) => {
|
||||||
// Expose jQuery globally
|
// Expose jQuery globally
|
||||||
window.$ = jQuery;
|
window.$ = jQuery;
|
||||||
window.jQuery = jQuery;
|
window.jQuery = jQuery;
|
||||||
|
|
|
@ -4608,6 +4608,11 @@ flv.js@^1.5.0:
|
||||||
es6-promise "^4.2.5"
|
es6-promise "^4.2.5"
|
||||||
webworkify "^1.5.0"
|
webworkify "^1.5.0"
|
||||||
|
|
||||||
|
focus-options-polyfill@^1.5.0:
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/focus-options-polyfill/-/focus-options-polyfill-1.5.0.tgz#fd2e6a0d6d8f828346726a5adf02f3d2bdfece5f"
|
||||||
|
integrity sha512-HiMSaXGUz2OFjOuoGTWXlp+YjZCGnVXPu6vPeccgaSOzGmqLVz8tJRcKXWfMJnj16LXf/IM1rJI0zrZMVc9q7g==
|
||||||
|
|
||||||
follow-redirects@1.5.10:
|
follow-redirects@1.5.10:
|
||||||
version "1.5.10"
|
version "1.5.10"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue