mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-17 19:08:18 -07:00
Merge branch 'release-10.3.z' into translations
This commit is contained in:
commit
ec8d0de8f1
9
.drone.yml
Normal file
9
.drone.yml
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
kind: pipeline
|
||||
name: eslint
|
||||
|
||||
steps:
|
||||
- name: run
|
||||
image: nextcloudci/eslint:eslint-1
|
||||
commands:
|
||||
- ./run-eslint.sh
|
3
.eslintrc.yml
Normal file
3
.eslintrc.yml
Normal file
@ -0,0 +1,3 @@
|
||||
env:
|
||||
browser: true
|
||||
amd: true
|
35
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**To Reproduce**
|
||||
<!-- Steps to reproduce the behavior: -->
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
**Logs**
|
||||
<!-- Please paste any log errors. -->
|
||||
|
||||
**Screenshots**
|
||||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
**System (please complete the following information):**
|
||||
- OS: [e.g. Docker, Debian, Windows]
|
||||
- Browser: [e.g. Firefox, Chrome, Safari]
|
||||
- Jellyfin Version: [e.g. 10.0.1]
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context about the problem here. -->
|
20
.github/ISSUE_TEMPLATE/enhancement-request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/enhancement-request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Enhancement request
|
||||
about: Suggest an modification to an existing feature
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
**Describe the solution you'd like**
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest a new feature
|
||||
title: ''
|
||||
labels: feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the feature you'd like**
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
11
.github/pull_request_template.md
vendored
Normal file
11
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Ensure your title is short, descriptive, and in the imperative mood (Fix X, Change Y, instead of Fixed X, Changed Y).
|
||||
For a good inspiration of what to write in commit messages and PRs please review https://chris.beams.io/posts/git-commit/ and our https://jellyfin.readthedocs.io/en/latest/developer-docs/contributing/ page.
|
||||
-->
|
||||
|
||||
**Changes**
|
||||
<!-- Describe your changes here in 1-5 sentences. -->
|
||||
|
||||
**Issues**
|
||||
<!-- Tag any issues that this PR solves here.
|
||||
ex. Fixes # -->
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -71,9 +71,6 @@ coverage
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
@ -573,3 +570,6 @@ ASALocalRun/
|
||||
healthchecksdb
|
||||
|
||||
# End of https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode
|
||||
|
||||
# dist for webpack output
|
||||
dist
|
@ -19,7 +19,8 @@
|
||||
- [nkmerrill](https://github.com/nkmerrill)
|
||||
- [TtheCreator](https://github.com/Tthecreator)
|
||||
- [RazeLighter777](https://github.com/RazeLighter777)
|
||||
- [anthonylavado](https://github.com/anthonylavado)
|
||||
- [LogicalPhallacy](https://github.com/LogicalPhallacy)
|
||||
- [thornbill](https://github.com/thornbill)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
11
package.json
Normal file
11
package.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "jellyfin-web",
|
||||
"version": "0.0.0",
|
||||
"description": "Web interface for Jellyfin",
|
||||
"repository": "https://github.com/jellyfin/jellyfin-web",
|
||||
"license": "GPL-2",
|
||||
"devDependencies": {
|
||||
"webpack": "^4.29.5",
|
||||
"webpack-cli": "^3.2.3"
|
||||
}
|
||||
}
|
18
run-eslint.sh
Executable file
18
run-eslint.sh
Executable file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# used this pull request for reference
|
||||
# https://github.com/nextcloud/spreed/pull/48
|
||||
ESLINT=$(which eslint || true)
|
||||
if [ -z "$ESLINT" ]
|
||||
then
|
||||
echo "could not find eslint in $PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo checking scripts with $ESLINT
|
||||
find -name "*.js" -print0 | xargs -0 $ESLINT
|
||||
|
||||
# use this line to test changes locally
|
||||
#find src -name "*.js" -exec sh -c 'npx eslint $1' -- {} \;
|
@ -1,4 +1,4 @@
|
||||
<div id="addPluginPage" data-role="page" class="page type-interior pluginConfigurationPage" data-backbutton="true" data-require="emby-select,emby-collapse,emby-linkbutton">
|
||||
<div id="addPluginPage" data-role="page" class="page type-interior pluginConfigurationPage" data-backbutton="true" data-require="emby-select,emby-collapse,emby-button">
|
||||
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
@ -8,7 +8,7 @@
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h1 class="sectionTitle pluginName"></h1>
|
||||
<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Plugins">${Help}</a>
|
||||
<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.readthedocs.io/en/latest/administrator-docs/plugins/">${Help}</a>
|
||||
</div>
|
||||
|
||||
<p id="tagline" style="font-style: italic;"></p>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<form class="manualServerForm" style="margin: 0 auto;">
|
||||
<h1 style="text-align: left;">${HeaderConnectToServer}</h1>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="text" id="txtServerHost" required="required" label="${LabelServerHost}" />
|
||||
<input is="emby-input" type="url" id="txtServerHost" required="required" label="${LabelServerHost}" />
|
||||
<div class="fieldDescription" style="text-align: left;">${LabelServerHostHelp}</div>
|
||||
</div>
|
||||
<br />
|
||||
|
@ -1,21 +0,0 @@
|
||||
<div id="appServicesPage" data-role="page" class="page type-interior appServicesPage withTabs fullWidthContent" data-require="scripts/appservices">
|
||||
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
|
||||
<div class="verticalSection">
|
||||
|
||||
<div class="sectionTitleContainer sectionTitleContainer-cards flex align-items-center">
|
||||
<h2 class="sectionTitle sectionTitle-cards">${HeaderInstalledServices}</h2>
|
||||
<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Plugins">${Help}</a>
|
||||
</div>
|
||||
|
||||
<div class="installedPlugins"></div>
|
||||
</div>
|
||||
<div class="verticalSection">
|
||||
<h2 class="sectionTitle sectionTitle-cards">${HeaderAvailableServices}</h2>
|
||||
<div class="catalog"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
8
src/availableplugins.html
Normal file
8
src/availableplugins.html
Normal file
@ -0,0 +1,8 @@
|
||||
<div id="pluginCatalogPage" data-role="page" class="page type-interior pluginConfigurationPage withTabs fullWidthContent">
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
<div id="noPlugins" class="hide">${MessageNoAvailablePlugins}</div>
|
||||
<div id="pluginTiles" style="text-align:left;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,6 +1,11 @@
|
||||
define(["apiclientcore", "localassetmanager"], function(ApiClient, localassetmanager) {
|
||||
//TODO: (vitorsemeano) modify this lines for webpack
|
||||
define(["bower_components/apiclient/apiclientcore", "localassetmanager"], function(ApiClient, localassetmanager) {
|
||||
"use strict";
|
||||
|
||||
if ("cordova" !== window.appMode && "android" !== window.appMode) {
|
||||
return ApiClient;
|
||||
}
|
||||
|
||||
function isLocalId(str) {
|
||||
return startsWith(str, localPrefix)
|
||||
}
|
53
src/bower_components/apiclient/appStorage.js
vendored
Normal file
53
src/bower_components/apiclient/appStorage.js
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function onCachePutFail(e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
function updateCache(instance) {
|
||||
if (instance.cache) {
|
||||
instance.cache.put("data", new Response(JSON.stringify(instance.localData))).catch(onCachePutFail);
|
||||
}
|
||||
}
|
||||
|
||||
function onCacheOpened(result) {
|
||||
this.cache = result;
|
||||
this.localData = {};
|
||||
}
|
||||
|
||||
function MyStore() {
|
||||
|
||||
this.setItem = function(name, value) {
|
||||
localStorage.setItem(name, value);
|
||||
|
||||
if (this.localData && this.localData[name] !== value) {
|
||||
this.localData[name] = value;
|
||||
updateCache(this);
|
||||
}
|
||||
};
|
||||
|
||||
this.getItem = function(name) {
|
||||
return localStorage.getItem(name);
|
||||
};
|
||||
|
||||
this.removeItem = function(name) {
|
||||
localStorage.removeItem(name);
|
||||
|
||||
if (this.localData) {
|
||||
delete this.localData[name];
|
||||
updateCache(this);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
if (self.caches) {
|
||||
self.caches.open("embydata").then(onCacheOpened.bind(this));
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Error opening cache: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
return new MyStore;
|
||||
});
|
@ -269,12 +269,15 @@ define(["events", "apiclient", "appStorage"], function(events, apiClientFactory,
|
||||
});
|
||||
resolve(servers)
|
||||
};
|
||||
require(["serverdiscovery"], function(serverDiscovery) {
|
||||
serverDiscovery.findServers(1e3).then(onFinish, function() {
|
||||
|
||||
if (window.NativeShell && typeof window.NativeShell.findServers === 'function') {
|
||||
window.NativeShell.findServers(1e3).then(onFinish, function() {
|
||||
onFinish([])
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function convertEndpointAddressToManualAddress(info) {
|
3
src/bower_components/apiclient/package.json
vendored
Normal file
3
src/bower_components/apiclient/package.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "apiclient.js"
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function MyStore() {}
|
||||
|
||||
function updateCache(instance) {
|
||||
instance.cache.put("data", new Response(JSON.stringify(instance.localData)))
|
||||
}
|
||||
return MyStore.prototype.init = function() {
|
||||
var instance = this;
|
||||
return caches.open("embydata").then(function(result) {
|
||||
instance.cache = result, instance.localData = {}
|
||||
})
|
||||
}, MyStore.prototype.setItem = function(name, value) {
|
||||
if (this.localData) {
|
||||
this.localData[name] !== value && (this.localData[name] = value, updateCache(this))
|
||||
}
|
||||
}, MyStore.prototype.getItem = function(name) {
|
||||
if (this.localData) return this.localData[name]
|
||||
}, MyStore.prototype.removeItem = function(name) {
|
||||
this.localData && (this.localData[name] = null, delete this.localData[name], updateCache(this))
|
||||
}, new MyStore
|
||||
});
|
@ -1,37 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function onCachePutFail(e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
function updateCache(instance) {
|
||||
var cache = instance.cache;
|
||||
cache && cache.put("data", new Response(JSON.stringify(instance.localData))).catch(onCachePutFail)
|
||||
}
|
||||
|
||||
function onCacheOpened(result) {
|
||||
this.cache = result, this.localData = {}
|
||||
}
|
||||
|
||||
function MyStore() {
|
||||
try {
|
||||
self.caches && caches.open("embydata").then(onCacheOpened.bind(this))
|
||||
} catch (err) {
|
||||
console.log("Error opening cache: " + err)
|
||||
}
|
||||
}
|
||||
return MyStore.prototype.setItem = function(name, value) {
|
||||
localStorage.setItem(name, value);
|
||||
var localData = this.localData;
|
||||
if (localData) {
|
||||
localData[name] !== value && (localData[name] = value, updateCache(this))
|
||||
}
|
||||
}, MyStore.prototype.getItem = function(name) {
|
||||
return localStorage.getItem(name)
|
||||
}, MyStore.prototype.removeItem = function(name) {
|
||||
localStorage.removeItem(name);
|
||||
var localData = this.localData;
|
||||
localData && (localData[name] = null, delete localData[name], updateCache(this))
|
||||
}, new MyStore
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function MyStore() {
|
||||
this.localData = {}
|
||||
}
|
||||
return MyStore.prototype.setItem = function(name, value) {
|
||||
this.localData[name] = value
|
||||
}, MyStore.prototype.getItem = function(name) {
|
||||
return this.localData[name]
|
||||
}, MyStore.prototype.removeItem = function(name) {
|
||||
this.localData[name] = null
|
||||
}, new MyStore
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function FileUpload() {}
|
||||
return FileUpload.prototype.upload = function(file, url) {
|
||||
return Promise.reject()
|
||||
}, FileUpload
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
return {
|
||||
findServers: function(timeoutMs) {
|
||||
return Promise.resolve([])
|
||||
}
|
||||
}
|
||||
});
|
15
src/bower_components/emby-apiclient/wakeonlan.js
vendored
15
src/bower_components/emby-apiclient/wakeonlan.js
vendored
@ -1,15 +0,0 @@
|
||||
define([], function() {
|
||||
"use strict";
|
||||
|
||||
function send(info) {
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
function isSupported() {
|
||||
return !1
|
||||
}
|
||||
return {
|
||||
send: send,
|
||||
isSupported: isSupported
|
||||
}
|
||||
});
|
@ -1,34 +0,0 @@
|
||||
define(['dialog', 'globalize'], function (dialog, globalize) {
|
||||
'use strict';
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
text: text
|
||||
};
|
||||
} else {
|
||||
options = text;
|
||||
}
|
||||
|
||||
var items = [];
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('ButtonGotIt'),
|
||||
id: 'ok',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
return dialog(options).then(function (result) {
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
};
|
||||
});
|
@ -1,23 +0,0 @@
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
|
||||
return function (options) {
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
text: options
|
||||
};
|
||||
}
|
||||
|
||||
var text = replaceAll(options.text || '', '<br/>', '\n');
|
||||
|
||||
alert(text);
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
define(['multi-download'], function (multiDownload) {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
download: function (items) {
|
||||
|
||||
multiDownload(items.map(function (item) {
|
||||
return item.url;
|
||||
}));
|
||||
}
|
||||
};
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
fileExists: function (path) {
|
||||
return Promise.reject();
|
||||
},
|
||||
directoryExists: function (path) {
|
||||
return Promise.reject();
|
||||
}
|
||||
};
|
||||
});
|
@ -1,26 +0,0 @@
|
||||
define(['dom', 'fullscreenManager'], function (dom, fullscreenManager) {
|
||||
'use strict';
|
||||
|
||||
function isTargetValid(target) {
|
||||
|
||||
if (dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
dom.addEventListener(window, 'dblclick', function (e) {
|
||||
|
||||
if (isTargetValid(e.target)) {
|
||||
if (fullscreenManager.isFullScreen()) {
|
||||
fullscreenManager.exitFullscreen();
|
||||
} else {
|
||||
fullscreenManager.requestFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
});
|
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
@ -1,80 +0,0 @@
|
||||
define(['playbackManager', 'itemHelper'], function (playbackManager, itemHelper) {
|
||||
"use strict";
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(deps, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function validatePlayback(options) {
|
||||
|
||||
var feature = 'playback';
|
||||
if (options.item && (options.item.Type === 'TvChannel' || options.item.Type === 'Recording')) {
|
||||
feature = 'livetv';
|
||||
}
|
||||
|
||||
if (feature === 'playback') {
|
||||
var player = playbackManager.getCurrentPlayer();
|
||||
if (player && !player.isLocalPlayer) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
return getRequirePromise(["registrationServices"]).then(function (registrationServices) {
|
||||
|
||||
return registrationServices.validateFeature(feature, options).then(function (result) {
|
||||
|
||||
if (result && result.enableTimeLimit) {
|
||||
startAutoStopTimer();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var autoStopTimeout;
|
||||
function startAutoStopTimer() {
|
||||
stopAutoStopTimer();
|
||||
autoStopTimeout = setTimeout(onAutoStopTimeout, 63000);
|
||||
}
|
||||
|
||||
function onAutoStopTimeout() {
|
||||
stopAutoStopTimer();
|
||||
playbackManager.stop();
|
||||
}
|
||||
|
||||
function stopAutoStopTimer() {
|
||||
|
||||
var timeout = autoStopTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
autoStopTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function PlaybackValidation() {
|
||||
|
||||
this.name = 'Playback validation';
|
||||
this.type = 'preplayintercept';
|
||||
this.id = 'playbackvalidation';
|
||||
this.order = -1;
|
||||
}
|
||||
|
||||
PlaybackValidation.prototype.intercept = function (options) {
|
||||
|
||||
// Don't care about video backdrops, or theme music or any kind of non-fullscreen playback
|
||||
if (!options.fullscreen) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (options.item && itemHelper.isLocalItem(options.item)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return validatePlayback(options);
|
||||
};
|
||||
|
||||
return PlaybackValidation;
|
||||
});
|
@ -1,25 +0,0 @@
|
||||
if (!Array.prototype.filter) {
|
||||
Array.prototype.filter = function (fun /*, thisp*/) {
|
||||
"use strict";
|
||||
|
||||
if (this == null)
|
||||
throw new TypeError();
|
||||
|
||||
var t = Object(this);
|
||||
var len = t.length >>> 0;
|
||||
if (typeof fun != "function")
|
||||
throw new TypeError();
|
||||
|
||||
var res = [];
|
||||
var thisp = arguments[1];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in t) {
|
||||
var val = t[i]; // in case fun mutates this
|
||||
if (fun.call(thisp, val, i, t))
|
||||
res.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function (oThis) {
|
||||
if (typeof this !== 'function') {
|
||||
// closest thing possible to the ECMAScript 5
|
||||
// internal IsCallable function
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function () { },
|
||||
fBound = function () {
|
||||
return fToBind.apply(this instanceof fNOP
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
if (this.prototype) {
|
||||
// Function.prototype doesn't have a prototype property
|
||||
fNOP.prototype = this.prototype;
|
||||
}
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
@ -1,23 +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) {
|
||||
if (source.hasOwnProperty(nextKey)) {
|
||||
output[nextKey] = source[nextKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
})();
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
|
||||
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
|
||||
|
||||
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
|
||||
|
||||
// MIT license
|
||||
|
||||
(function () {
|
||||
var lastTime = 0;
|
||||
var vendors = ['ms', 'moz', 'webkit', 'o'];
|
||||
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame']
|
||||
|| window[vendors[x] + 'CancelRequestAnimationFrame'];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function (callback, element) {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function () { callback(currTime + timeToCall); },
|
||||
timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
|
||||
if (!window.cancelAnimationFrame)
|
||||
window.cancelAnimationFrame = function (id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}());
|
@ -1,16 +0,0 @@
|
||||
define(['appSettings', 'loading', 'apphost', 'events', 'shell', 'globalize', 'dialogHelper', 'connectionManager', 'layoutManager', 'emby-button', 'emby-linkbutton'], function (appSettings, loading, appHost, events, shell, globalize, dialogHelper, connectionManager, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
function validateFeature(feature, options) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function showPremiereInfo() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return {
|
||||
validateFeature: validateFeature,
|
||||
showPremiereInfo: showPremiereInfo
|
||||
};
|
||||
});
|
@ -1,6 +0,0 @@
|
||||
self.addEventListener('sync', function (event) {
|
||||
'use strict';
|
||||
|
||||
if (event.tag === 'emby-sync') {
|
||||
}
|
||||
});
|
21
src/bower_components/emby-webcomponents/shell.js
vendored
21
src/bower_components/emby-webcomponents/shell.js
vendored
@ -1,21 +0,0 @@
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
openUrl: function (url) {
|
||||
window.open(url, '_blank');
|
||||
},
|
||||
canExec: false,
|
||||
exec: function (options) {
|
||||
// options.path
|
||||
// options.arguments
|
||||
return Promise.reject();
|
||||
},
|
||||
enableFullscreen: function () {
|
||||
// do nothing since this is for native apps
|
||||
},
|
||||
disableFullscreen: function () {
|
||||
// do nothing since this is for native apps
|
||||
}
|
||||
};
|
||||
});
|
@ -1,355 +0,0 @@
|
||||
define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdrop', 'globalize', 'require', 'appSettings'], function (appHost, userSettings, browser, events, pluginManager, backdrop, globalize, require, appSettings) {
|
||||
'use strict';
|
||||
|
||||
var currentSkin;
|
||||
|
||||
function getCurrentSkin() {
|
||||
return currentSkin;
|
||||
}
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(deps, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function loadSkin(id) {
|
||||
|
||||
var newSkin = pluginManager.plugins().filter(function (p) {
|
||||
return p.id === id;
|
||||
})[0];
|
||||
|
||||
if (!newSkin) {
|
||||
newSkin = pluginManager.plugins().filter(function (p) {
|
||||
return p.id === 'defaultskin';
|
||||
})[0];
|
||||
}
|
||||
|
||||
var unloadPromise;
|
||||
|
||||
if (currentSkin) {
|
||||
|
||||
if (currentSkin.id === newSkin.id) {
|
||||
// Nothing to do, it's already the active skin
|
||||
return Promise.resolve(currentSkin);
|
||||
}
|
||||
unloadPromise = unloadSkin(currentSkin);
|
||||
} else {
|
||||
unloadPromise = Promise.resolve();
|
||||
}
|
||||
|
||||
return unloadPromise.then(function () {
|
||||
var deps = newSkin.getDependencies();
|
||||
|
||||
console.log('Loading skin dependencies');
|
||||
|
||||
return getRequirePromise(deps).then(function () {
|
||||
|
||||
console.log('Skin dependencies loaded');
|
||||
|
||||
var strings = newSkin.getTranslations ? newSkin.getTranslations() : [];
|
||||
|
||||
return globalize.loadStrings({
|
||||
|
||||
name: newSkin.id,
|
||||
strings: strings
|
||||
|
||||
}).then(function () {
|
||||
|
||||
globalize.defaultModule(newSkin.id);
|
||||
return loadSkinHeader(newSkin);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function unloadSkin(skin) {
|
||||
|
||||
unloadTheme();
|
||||
backdrop.clear();
|
||||
|
||||
console.log('Unloading skin: ' + skin.name);
|
||||
|
||||
// TODO: unload css
|
||||
|
||||
return skin.unload().then(function () {
|
||||
document.dispatchEvent(new CustomEvent("skinunload", {
|
||||
detail: {
|
||||
name: skin.name
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function loadSkinHeader(skin) {
|
||||
|
||||
return getSkinHeader(skin).then(function (headerHtml) {
|
||||
|
||||
document.querySelector('.skinHeader').innerHTML = headerHtml;
|
||||
|
||||
currentSkin = skin;
|
||||
skin.load();
|
||||
|
||||
return skin;
|
||||
});
|
||||
}
|
||||
|
||||
var cacheParam = new Date().getTime();
|
||||
|
||||
function getSkinHeader(skin) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
if (!skin.getHeaderTemplate) {
|
||||
resolve('');
|
||||
return;
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
var url = skin.getHeaderTemplate();
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 'v=' + cacheParam;
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (this.status < 400) {
|
||||
resolve(this.response);
|
||||
} else {
|
||||
resolve('');
|
||||
}
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function loadUserSkin(options) {
|
||||
|
||||
var skin = userSettings.get('skin', false) || 'defaultskin';
|
||||
|
||||
loadSkin(skin).then(function (skin) {
|
||||
|
||||
options = options || {};
|
||||
if (options.start) {
|
||||
Emby.Page.invokeShortcut(options.start);
|
||||
} else {
|
||||
Emby.Page.goHome();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
events.on(userSettings, 'change', function (e, name) {
|
||||
if (name === 'skin' || name === 'language') {
|
||||
loadUserSkin();
|
||||
}
|
||||
});
|
||||
|
||||
var themeStyleElement;
|
||||
var currentThemeId;
|
||||
function unloadTheme() {
|
||||
var elem = themeStyleElement;
|
||||
if (elem) {
|
||||
|
||||
elem.parentNode.removeChild(elem);
|
||||
themeStyleElement = null;
|
||||
currentThemeId = null;
|
||||
}
|
||||
}
|
||||
|
||||
function getThemes() {
|
||||
|
||||
if (currentSkin.getThemes) {
|
||||
return currentSkin.getThemes();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
var skinManager = {
|
||||
getCurrentSkin: getCurrentSkin,
|
||||
loadSkin: loadSkin,
|
||||
loadUserSkin: loadUserSkin,
|
||||
getThemes: getThemes
|
||||
};
|
||||
|
||||
function onRegistrationSuccess() {
|
||||
appSettings.set('appthemesregistered', 'true');
|
||||
}
|
||||
|
||||
function onRegistrationFailure() {
|
||||
appSettings.set('appthemesregistered', 'false');
|
||||
}
|
||||
|
||||
function isRegistered() {
|
||||
|
||||
getRequirePromise(['registrationServices']).then(function (registrationServices) {
|
||||
registrationServices.validateFeature('themes', {
|
||||
|
||||
showDialog: false
|
||||
|
||||
}).then(onRegistrationSuccess, onRegistrationFailure);
|
||||
});
|
||||
|
||||
return appSettings.get('appthemesregistered') !== 'false';
|
||||
}
|
||||
|
||||
function getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty) {
|
||||
|
||||
var themes = skinManager.getThemes();
|
||||
var defaultTheme;
|
||||
var selectedTheme;
|
||||
|
||||
for (var i = 0, length = themes.length; i < length; i++) {
|
||||
|
||||
var theme = themes[i];
|
||||
if (theme[isDefaultProperty]) {
|
||||
defaultTheme = theme;
|
||||
}
|
||||
if (id === theme.id) {
|
||||
selectedTheme = theme;
|
||||
}
|
||||
}
|
||||
|
||||
selectedTheme = selectedTheme || defaultTheme;
|
||||
|
||||
if (selectedTheme.id !== defaultTheme.id && requiresRegistration && !isRegistered()) {
|
||||
selectedTheme = defaultTheme;
|
||||
}
|
||||
|
||||
var embyWebComponentsBowerPath = 'bower_components/emby-webcomponents';
|
||||
|
||||
return {
|
||||
stylesheetPath: require.toUrl(embyWebComponentsBowerPath + '/themes/' + selectedTheme.id + '/theme.css'),
|
||||
themeId: selectedTheme.id
|
||||
};
|
||||
}
|
||||
|
||||
var themeResources = {};
|
||||
var lastSound = 0;
|
||||
var currentSound;
|
||||
|
||||
function loadThemeResources(id) {
|
||||
|
||||
lastSound = 0;
|
||||
|
||||
if (currentSound) {
|
||||
currentSound.stop();
|
||||
currentSound = null;
|
||||
}
|
||||
|
||||
backdrop.clear();
|
||||
}
|
||||
|
||||
function onThemeLoaded() {
|
||||
document.documentElement.classList.remove('preload');
|
||||
|
||||
|
||||
try {
|
||||
var color = getComputedStyle(document.querySelector('.skinHeader')).getPropertyValue("background-color");
|
||||
|
||||
if (color) {
|
||||
appHost.setThemeColor(color);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log('Error setting theme color: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
skinManager.setTheme = function (id, context) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var requiresRegistration = true;
|
||||
|
||||
if (currentThemeId && currentThemeId === id) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var isDefaultProperty = context === 'serverdashboard' ? 'isDefaultServerDashboard' : 'isDefault';
|
||||
var info = getThemeStylesheetInfo(id, requiresRegistration, isDefaultProperty);
|
||||
|
||||
if (currentThemeId && currentThemeId === info.themeId) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var linkUrl = info.stylesheetPath;
|
||||
|
||||
unloadTheme();
|
||||
|
||||
var link = document.createElement('link');
|
||||
|
||||
link.setAttribute('rel', 'stylesheet');
|
||||
link.setAttribute('type', 'text/css');
|
||||
link.onload = function () {
|
||||
|
||||
onThemeLoaded();
|
||||
resolve();
|
||||
};
|
||||
|
||||
link.setAttribute('href', linkUrl);
|
||||
document.head.appendChild(link);
|
||||
themeStyleElement = link;
|
||||
currentThemeId = info.themeId;
|
||||
loadThemeResources(info.themeId);
|
||||
|
||||
onViewBeforeShow({});
|
||||
});
|
||||
};
|
||||
|
||||
function onViewBeforeShow(e) {
|
||||
|
||||
if (e.detail && e.detail.type === 'video-osd') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (themeResources.backdrop) {
|
||||
|
||||
backdrop.setBackdrop(themeResources.backdrop);
|
||||
}
|
||||
|
||||
if (!browser.mobile && userSettings.enableThemeSongs()) {
|
||||
if (lastSound === 0) {
|
||||
|
||||
if (themeResources.themeSong) {
|
||||
playSound(themeResources.themeSong);
|
||||
}
|
||||
|
||||
} else if ((new Date().getTime() - lastSound) > 30000) {
|
||||
if (themeResources.effect) {
|
||||
playSound(themeResources.effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('viewshow', onViewBeforeShow);
|
||||
|
||||
function playSound(path, volume) {
|
||||
|
||||
lastSound = new Date().getTime();
|
||||
|
||||
require(['howler'], function (howler) {
|
||||
|
||||
try {
|
||||
var sound = new Howl({
|
||||
src: [path],
|
||||
volume: volume || 0.1
|
||||
});
|
||||
|
||||
sound.play();
|
||||
currentSound = sound;
|
||||
}
|
||||
catch (err) {
|
||||
console.log('Error playing sound: ' + err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return skinManager;
|
||||
});
|
@ -1,188 +0,0 @@
|
||||
define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) {
|
||||
'use strict';
|
||||
|
||||
function onClick(e) {
|
||||
|
||||
var button = this;
|
||||
var id = button.getAttribute('data-id');
|
||||
var serverId = button.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
if (!button.classList.contains('downloadbutton-on')) {
|
||||
|
||||
require(['syncDialog'], function (syncDialog) {
|
||||
syncDialog.showMenu({
|
||||
|
||||
items: [id],
|
||||
mode: 'download',
|
||||
serverId: serverId
|
||||
|
||||
}).then(function () {
|
||||
|
||||
button.dispatchEvent(new CustomEvent('download', {
|
||||
cancelable: false
|
||||
}));
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm({
|
||||
|
||||
text: globalize.translate('ConfirmRemoveDownload'),
|
||||
confirmText: globalize.translate('RemoveDownload'),
|
||||
cancelText: globalize.translate('KeepDownload'),
|
||||
primary: 'cancel'
|
||||
|
||||
}).then(function () {
|
||||
apiClient.cancelSyncItems([id]);
|
||||
|
||||
button.dispatchEvent(new CustomEvent('download-cancel', {
|
||||
cancelable: false
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateSyncStatus(button, syncPercent) {
|
||||
|
||||
var icon = button.iconElement;
|
||||
if (!icon) {
|
||||
button.iconElement = button.querySelector('i');
|
||||
icon = button.iconElement;
|
||||
}
|
||||
|
||||
if (syncPercent != null) {
|
||||
button.classList.add('downloadbutton-on');
|
||||
|
||||
if (icon) {
|
||||
icon.classList.add('downloadbutton-icon-on');
|
||||
}
|
||||
|
||||
} else {
|
||||
button.classList.remove('downloadbutton-on');
|
||||
|
||||
if (icon) {
|
||||
icon.classList.remove('downloadbutton-icon-on');
|
||||
}
|
||||
}
|
||||
|
||||
if ((syncPercent || 0) >= 100) {
|
||||
button.classList.add('downloadbutton-complete');
|
||||
|
||||
if (icon) {
|
||||
icon.classList.add('downloadbutton-icon-complete');
|
||||
}
|
||||
} else {
|
||||
button.classList.remove('downloadbutton-complete');
|
||||
|
||||
if (icon) {
|
||||
icon.classList.remove('downloadbutton-icon-complete');
|
||||
}
|
||||
}
|
||||
|
||||
var text;
|
||||
if ((syncPercent || 0) >= 100) {
|
||||
text = globalize.translate('Downloaded');
|
||||
} else if (syncPercent != null) {
|
||||
text = globalize.translate('Downloading');
|
||||
} else {
|
||||
text = globalize.translate('Download');
|
||||
}
|
||||
|
||||
var textElement = button.querySelector('.emby-downloadbutton-downloadtext');
|
||||
if (textElement) {
|
||||
textElement.innerHTML = text;
|
||||
}
|
||||
|
||||
button.title = text;
|
||||
}
|
||||
|
||||
function clearEvents(button) {
|
||||
|
||||
button.removeEventListener('click', onClick);
|
||||
}
|
||||
|
||||
function bindEvents(button) {
|
||||
|
||||
clearEvents(button);
|
||||
|
||||
button.addEventListener('click', onClick);
|
||||
}
|
||||
|
||||
var EmbyDownloadButtonPrototype = Object.create(EmbyButtonPrototype);
|
||||
|
||||
EmbyDownloadButtonPrototype.createdCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.createdCallback) {
|
||||
EmbyButtonPrototype.createdCallback.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyDownloadButtonPrototype.attachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.attachedCallback) {
|
||||
EmbyButtonPrototype.attachedCallback.call(this);
|
||||
}
|
||||
|
||||
var itemId = this.getAttribute('data-id');
|
||||
var serverId = this.getAttribute('data-serverid');
|
||||
if (itemId && serverId) {
|
||||
|
||||
bindEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyDownloadButtonPrototype.detachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.detachedCallback) {
|
||||
EmbyButtonPrototype.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
clearEvents(this);
|
||||
|
||||
this.iconElement = null;
|
||||
};
|
||||
|
||||
function fetchAndUpdate(button, item) {
|
||||
|
||||
connectionManager.getApiClient(item.ServerId).getSyncStatus(item.Id).then(function (result) {
|
||||
|
||||
updateSyncStatus(button, result.Progress);
|
||||
|
||||
}, function () {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
EmbyDownloadButtonPrototype.setItem = function (item) {
|
||||
|
||||
if (item) {
|
||||
|
||||
this.setAttribute('data-id', item.Id);
|
||||
this.setAttribute('data-serverid', item.ServerId);
|
||||
|
||||
fetchAndUpdate(this, item);
|
||||
|
||||
bindEvents(this);
|
||||
|
||||
} else {
|
||||
|
||||
this.removeAttribute('data-id');
|
||||
this.removeAttribute('data-serverid');
|
||||
clearEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-downloadbutton', {
|
||||
prototype: EmbyDownloadButtonPrototype,
|
||||
extends: 'button'
|
||||
});
|
||||
});
|
736
src/bower_components/emby-webcomponents/sync/sync.js
vendored
736
src/bower_components/emby-webcomponents/sync/sync.js
vendored
@ -1,736 +0,0 @@
|
||||
define(['apphost', 'globalize', 'connectionManager', 'layoutManager', 'focusManager', 'scrollHelper', 'appSettings', 'registrationServices', 'dialogHelper', 'paper-icon-button-light', 'formDialogStyle'], function (appHost, globalize, connectionManager, layoutManager, focusManager, scrollHelper, appSettings, registrationServices, dialogHelper) {
|
||||
'use strict';
|
||||
|
||||
var currentDialogOptions;
|
||||
|
||||
function submitJob(dlg, apiClient, userId, syncOptions, form) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('userId cannot be null');
|
||||
}
|
||||
|
||||
if (!syncOptions) {
|
||||
throw new Error('syncOptions cannot be null');
|
||||
}
|
||||
|
||||
if (!form) {
|
||||
throw new Error('form cannot be null');
|
||||
}
|
||||
|
||||
var selectSyncTarget = form.querySelector('#selectSyncTarget');
|
||||
var target = selectSyncTarget ? selectSyncTarget.value : null;
|
||||
|
||||
if (!target) {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('PleaseSelectDeviceToSyncTo'));
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
var options = {
|
||||
|
||||
userId: userId,
|
||||
TargetId: target,
|
||||
|
||||
ParentId: syncOptions.ParentId,
|
||||
Category: syncOptions.Category
|
||||
};
|
||||
|
||||
setJobValues(options, form);
|
||||
|
||||
if (syncOptions.items && syncOptions.items.length) {
|
||||
options.ItemIds = (syncOptions.items || []).map(function (i) {
|
||||
return i.Id || i;
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
apiClient.ajax({
|
||||
|
||||
type: "POST",
|
||||
url: apiClient.getUrl("Sync/Jobs"),
|
||||
data: JSON.stringify(options),
|
||||
contentType: "application/json",
|
||||
dataType: 'json'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
require(['toast'], function (toast) {
|
||||
|
||||
showSubmissionToast(target, apiClient);
|
||||
|
||||
if (syncOptions.mode === 'download') {
|
||||
syncNow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function showSubmissionToast(targetId, apiClient) {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
|
||||
var msg = targetId === apiClient.deviceId() ?
|
||||
globalize.translate('DownloadingDots') :
|
||||
globalize.translate('SyncingDots');
|
||||
|
||||
toast(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function syncNow() {
|
||||
require(['localsync'], function (localSync) {
|
||||
localSync.sync();
|
||||
});
|
||||
}
|
||||
|
||||
function submitQuickSyncJob(apiClient, userId, targetId, syncOptions) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('userId cannot be null');
|
||||
}
|
||||
|
||||
if (!syncOptions) {
|
||||
throw new Error('syncOptions cannot be null');
|
||||
}
|
||||
|
||||
if (!targetId) {
|
||||
throw new Error('targetId cannot be null');
|
||||
}
|
||||
|
||||
var options = {
|
||||
|
||||
userId: userId,
|
||||
TargetId: targetId,
|
||||
|
||||
ParentId: syncOptions.ParentId,
|
||||
Category: syncOptions.Category,
|
||||
Quality: syncOptions.Quality,
|
||||
Bitrate: syncOptions.Bitrate
|
||||
};
|
||||
|
||||
if (syncOptions.items && syncOptions.items.length) {
|
||||
options.ItemIds = (syncOptions.items || []).map(function (i) {
|
||||
return i.Id || i;
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
return apiClient.ajax({
|
||||
|
||||
type: "POST",
|
||||
url: apiClient.getUrl("Sync/Jobs"),
|
||||
data: JSON.stringify(options),
|
||||
contentType: "application/json",
|
||||
dataType: 'json'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
|
||||
showSubmissionToast(targetId, apiClient);
|
||||
|
||||
if (syncOptions.mode === 'download') {
|
||||
syncNow();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setJobValues(job, form) {
|
||||
|
||||
var txtBitrate = form.querySelector('#txtBitrate');
|
||||
var bitrate = txtBitrate ? txtBitrate.value : null;
|
||||
|
||||
if (bitrate) {
|
||||
bitrate = parseFloat(bitrate) * 1000000;
|
||||
}
|
||||
job.Bitrate = bitrate;
|
||||
|
||||
var selectQuality = form.querySelector('#selectQuality');
|
||||
if (selectQuality) {
|
||||
job.Quality = selectQuality.value;
|
||||
|
||||
appSettings.set('sync-lastquality', job.Quality || '');
|
||||
}
|
||||
|
||||
var selectProfile = form.querySelector('#selectProfile');
|
||||
if (selectProfile) {
|
||||
job.Profile = selectProfile.value;
|
||||
}
|
||||
|
||||
var txtItemLimit = form.querySelector('#txtItemLimit');
|
||||
if (txtItemLimit) {
|
||||
job.ItemLimit = txtItemLimit.value || null;
|
||||
}
|
||||
|
||||
var chkSyncNewContent = form.querySelector('#chkSyncNewContent');
|
||||
if (chkSyncNewContent) {
|
||||
job.SyncNewContent = chkSyncNewContent.checked;
|
||||
}
|
||||
|
||||
var chkUnwatchedOnly = form.querySelector('#chkUnwatchedOnly');
|
||||
if (chkUnwatchedOnly) {
|
||||
job.UnwatchedOnly = chkUnwatchedOnly.checked;
|
||||
}
|
||||
}
|
||||
|
||||
function renderForm(options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['emby-checkbox', 'emby-input', 'emby-select'], function () {
|
||||
|
||||
renderFormInternal(options, connectionManager.deviceId(), resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderFormInternal(options, defaultTargetId, resolve) {
|
||||
|
||||
var elem = options.elem;
|
||||
var dialogOptions = options.dialogOptions;
|
||||
|
||||
var targets = dialogOptions.Targets;
|
||||
|
||||
var html = '';
|
||||
|
||||
var mode = options.mode;
|
||||
var targetContainerClass = mode === 'download' ? ' hide' : '';
|
||||
|
||||
var syncTargetLabel = mode === 'convert' ? globalize.translate('LabelConvertTo') : globalize.translate('LabelSyncTo');
|
||||
|
||||
if (options.readOnlySyncTarget) {
|
||||
html += '<div class="inputContainer' + targetContainerClass + '">';
|
||||
html += '<input is="emby-input" type="text" id="selectSyncTarget" readonly label="' + syncTargetLabel + '"/>';
|
||||
html += '</div>';
|
||||
} else {
|
||||
html += '<div class="selectContainer' + targetContainerClass + '">';
|
||||
html += '<select is="emby-select" id="selectSyncTarget" required="required" label="' + syncTargetLabel + '">';
|
||||
|
||||
html += targets.map(function (t) {
|
||||
|
||||
var isSelected = defaultTargetId === t.Id;
|
||||
var selectedHtml = isSelected ? ' selected="selected"' : '';
|
||||
return '<option' + selectedHtml + ' value="' + t.Id + '">' + t.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
html += '</select>';
|
||||
if (!targets.length) {
|
||||
html += '<div class="fieldDescription">' + globalize.translate('LabelSyncNoTargetsHelp') + '</div>';
|
||||
}
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += '<div class="fieldDescription"><a is="emby-linkbutton" class="button-link lnkLearnMore" href="https://github.com/MediaBrowser/Wiki/wiki/Sync" target="_blank">' + globalize.translate('LearnMore') + '</a></div>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '<div class="fldProfile selectContainer hide">';
|
||||
html += '<select is="emby-select" id="selectProfile" label="' + globalize.translate('LabelProfile') + '">';
|
||||
html += '</select>';
|
||||
html += '<div class="fieldDescription profileDescription"></div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="fldQuality selectContainer hide">';
|
||||
html += '<select is="emby-select" id="selectQuality" required="required" label="' + globalize.translate('LabelQuality') + '">';
|
||||
html += '</select>';
|
||||
html += '<div class="fieldDescription qualityDescription"></div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="fldBitrate inputContainer hide">';
|
||||
html += '<input is="emby-input" type="number" step=".1" min=".1" id="txtBitrate" label="' + globalize.translate('LabelBitrateMbps') + '"/>';
|
||||
html += '</div>';
|
||||
|
||||
if (dialogOptions.Options.indexOf('UnwatchedOnly') !== -1) {
|
||||
html += '<div class="checkboxContainer checkboxContainer-withDescription">';
|
||||
html += '<label>';
|
||||
html += '<input is="emby-checkbox" type="checkbox" id="chkUnwatchedOnly"/>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<span>' + globalize.translate('ConvertUnwatchedVideosOnly') + '</span>';
|
||||
} else {
|
||||
html += '<span>' + globalize.translate('SyncUnwatchedVideosOnly') + '</span>';
|
||||
}
|
||||
|
||||
html += '</label>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('ConvertUnwatchedVideosOnlyHelp') + '</div>';
|
||||
} else {
|
||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('SyncUnwatchedVideosOnlyHelp') + '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
if (dialogOptions.Options.indexOf('SyncNewContent') !== -1) {
|
||||
html += '<div class="checkboxContainer checkboxContainer-withDescription">';
|
||||
html += '<label>';
|
||||
html += '<input is="emby-checkbox" type="checkbox" id="chkSyncNewContent"/>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<span>' + globalize.translate('AutomaticallyConvertNewContent') + '</span>';
|
||||
} else {
|
||||
html += '<span>' + globalize.translate('AutomaticallySyncNewContent') + '</span>';
|
||||
}
|
||||
|
||||
html += '</label>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('AutomaticallyConvertNewContentHelp') + '</div>';
|
||||
} else {
|
||||
html += '<div class="fieldDescription checkboxFieldDescription">' + globalize.translate('AutomaticallySyncNewContentHelp') + '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
if (dialogOptions.Options.indexOf('ItemLimit') !== -1) {
|
||||
html += '<div class="inputContainer">';
|
||||
html += '<input is="emby-input" type="number" step="1" min="1" id="txtItemLimit" label="' + globalize.translate('LabelItemLimit') + '"/>';
|
||||
|
||||
if (mode === 'convert') {
|
||||
html += '<div class="fieldDescription">' + globalize.translate('ConvertItemLimitHelp') + '</div>';
|
||||
} else {
|
||||
html += '<div class="fieldDescription">' + globalize.translate('DownloadItemLimitHelp') + '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
//html += '</div>';
|
||||
//html += '</div>';
|
||||
|
||||
elem.innerHTML = html;
|
||||
|
||||
var selectSyncTarget = elem.querySelector('#selectSyncTarget');
|
||||
if (selectSyncTarget) {
|
||||
selectSyncTarget.addEventListener('change', function () {
|
||||
loadQualityOptions(elem, this.value, options.dialogOptionsFn).then(resolve);
|
||||
});
|
||||
selectSyncTarget.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
|
||||
var selectProfile = elem.querySelector('#selectProfile');
|
||||
if (selectProfile) {
|
||||
selectProfile.addEventListener('change', function () {
|
||||
onProfileChange(elem, this.value);
|
||||
});
|
||||
|
||||
if (dialogOptions.ProfileOptions.length) {
|
||||
selectProfile.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
var selectQuality = elem.querySelector('#selectQuality');
|
||||
if (selectQuality) {
|
||||
selectQuality.addEventListener('change', function () {
|
||||
onQualityChange(elem, this.value);
|
||||
});
|
||||
selectQuality.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
|
||||
// This isn't ideal, but allow time for the change handlers above to run
|
||||
setTimeout(function () {
|
||||
focusManager.autoFocus(elem);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function showWifiMessage() {
|
||||
|
||||
require(['dialog', 'appRouter'], function (dialog, appRouter) {
|
||||
|
||||
var options = {
|
||||
|
||||
title: globalize.translate('HeaderWaitingForWifi'),
|
||||
text: globalize.translate('WifiRequiredToDownload')
|
||||
};
|
||||
|
||||
var items = [];
|
||||
|
||||
items.push({
|
||||
name: options.confirmText || globalize.translate('ButtonOk'),
|
||||
id: 'ok',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
items.push({
|
||||
name: options.cancelText || globalize.translate('HeaderDownloadSettings'),
|
||||
id: 'downloadsettings',
|
||||
type: 'cancel'
|
||||
});
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
dialog(options).then(function (result) {
|
||||
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (result === 'downloadsettings') {
|
||||
appRouter.show(appRouter.getRouteUrl('downloadsettings'));
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function validateNetwork() {
|
||||
|
||||
var network = navigator.connection ? navigator.connection.type : null;
|
||||
|
||||
switch (network) {
|
||||
|
||||
case 'cellular':
|
||||
case 'bluetooth':
|
||||
showWifiMessage();
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function showSyncMenu(options) {
|
||||
|
||||
if (options.mode === 'download' && appSettings.syncOnlyOnWifi() && !validateNetwork()) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return registrationServices.validateFeature('sync').then(function () {
|
||||
return showSyncMenuInternal(options);
|
||||
});
|
||||
}
|
||||
|
||||
function enableAutoSync(options) {
|
||||
|
||||
if (options.mode !== 'download') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var firstItem = (options.items || [])[0] || {};
|
||||
|
||||
if (firstItem.Type === 'Audio') {
|
||||
return true;
|
||||
}
|
||||
if (firstItem.Type === 'MusicAlbum') {
|
||||
return true;
|
||||
}
|
||||
if (firstItem.Type === 'MusicArtist') {
|
||||
return true;
|
||||
}
|
||||
if (firstItem.Type === 'MusicGenre') {
|
||||
return true;
|
||||
}
|
||||
if (firstItem.Type === 'Playlist' && firstItem.MediaType === 'Audio') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function showSyncMenuInternal(options) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
var userId = apiClient.getCurrentUserId();
|
||||
|
||||
if (enableAutoSync(options)) {
|
||||
|
||||
return submitQuickSyncJob(apiClient, userId, apiClient.deviceId(), {
|
||||
items: options.items,
|
||||
Quality: 'custom',
|
||||
Bitrate: appSettings.maxStaticMusicBitrate()
|
||||
});
|
||||
}
|
||||
|
||||
var dialogOptionsFn = getTargetDialogOptionsFn(apiClient, {
|
||||
UserId: userId,
|
||||
ItemIds: (options.items || []).map(function (i) {
|
||||
return i.Id || i;
|
||||
}).join(','),
|
||||
|
||||
ParentId: options.ParentId,
|
||||
Category: options.Category,
|
||||
IncludeProviders: options.mode === 'convert' ? 'ConvertSyncProvider' : null,
|
||||
ExcludeProviders: options.mode === 'convert' ? null : 'ConvertSyncProvider'
|
||||
});
|
||||
|
||||
return dialogOptionsFn().then(function (dialogOptions) {
|
||||
|
||||
currentDialogOptions = dialogOptions;
|
||||
|
||||
var dlgElementOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false,
|
||||
autoFocus: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dlgElementOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dlgElementOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dlgElementOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
|
||||
var syncButtonLabel = options.mode === 'download' ?
|
||||
globalize.translate('Download') :
|
||||
(options.mode === 'convert' ? globalize.translate('Convert') : globalize.translate('Sync'));
|
||||
|
||||
html += syncButtonLabel;
|
||||
html += '</h3>';
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += '<a is="emby-linkbutton" href="https://github.com/MediaBrowser/Wiki/wiki/Sync" target="_blank" class="button-link lnkHelp" style="margin-top:0;display:inline-block;vertical-align:middle;margin-left:auto;"><i class="md-icon">info</i><span>' + globalize.translate('Help') + '</span></a>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
|
||||
html += '<form class="formSubmitSyncRequest" style="margin: auto;">';
|
||||
|
||||
html += '<div class="formFields"></div>';
|
||||
|
||||
html += '<div class="formDialogFooter">';
|
||||
|
||||
html += '<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem"><span>' + syncButtonLabel + '</span></button>';
|
||||
html += '</div>';
|
||||
|
||||
html += '</form>';
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
var submitted = false;
|
||||
|
||||
dlg.querySelector('form').addEventListener('submit', function (e) {
|
||||
|
||||
submitted = submitJob(dlg, apiClient, userId, options, this);
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
var promise = dialogHelper.open(dlg);
|
||||
|
||||
renderForm({
|
||||
elem: dlg.querySelector('.formFields'),
|
||||
dialogOptions: dialogOptions,
|
||||
dialogOptionsFn: dialogOptionsFn,
|
||||
mode: options.mode
|
||||
});
|
||||
|
||||
return promise.then(function () {
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getTargetDialogOptionsFn(apiClient, query) {
|
||||
|
||||
return function (targetId) {
|
||||
|
||||
query.TargetId = targetId;
|
||||
return apiClient.getJSON(apiClient.getUrl('Sync/Options', query));
|
||||
};
|
||||
}
|
||||
|
||||
function setQualityFieldVisible(form, visible) {
|
||||
|
||||
var fldQuality = form.querySelector('.fldQuality');
|
||||
var selectQuality = form.querySelector('#selectQuality');
|
||||
|
||||
if (visible) {
|
||||
if (fldQuality) {
|
||||
fldQuality.classList.remove('hide');
|
||||
}
|
||||
if (selectQuality) {
|
||||
//selectQuality.setAttribute('required', 'required');
|
||||
|
||||
// This is a hack due to what appears to be a edge bug but it shoudln't matter as the list always has selectable items
|
||||
selectQuality.removeAttribute('required');
|
||||
}
|
||||
} else {
|
||||
if (fldQuality) {
|
||||
fldQuality.classList.add('hide');
|
||||
}
|
||||
if (selectQuality) {
|
||||
selectQuality.removeAttribute('required');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onProfileChange(form, profileId) {
|
||||
|
||||
var options = currentDialogOptions || {};
|
||||
|
||||
var profileOptions = options.ProfileOptions || [];
|
||||
|
||||
if (!profileOptions.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var option = profileOptions.filter(function (o) {
|
||||
return o.Id === profileId;
|
||||
})[0];
|
||||
|
||||
var qualityOptions = options.QualityOptions || [];
|
||||
|
||||
if (option) {
|
||||
form.querySelector('.profileDescription').innerHTML = option.Description || '';
|
||||
setQualityFieldVisible(form, qualityOptions.length > 0 && option.EnableQualityOptions && options.Options.indexOf('Quality') !== -1);
|
||||
} else {
|
||||
form.querySelector('.profileDescription').innerHTML = '';
|
||||
setQualityFieldVisible(form, qualityOptions.length > 0 && options.Options.indexOf('Quality') !== -1);
|
||||
}
|
||||
}
|
||||
|
||||
function onQualityChange(form, qualityId) {
|
||||
|
||||
var options = currentDialogOptions || {};
|
||||
var option = (options.QualityOptions || []).filter(function (o) {
|
||||
return o.Id === qualityId;
|
||||
})[0];
|
||||
|
||||
var qualityDescription = form.querySelector('.qualityDescription');
|
||||
|
||||
if (option) {
|
||||
qualityDescription.innerHTML = option.Description || '';
|
||||
} else {
|
||||
qualityDescription.innerHTML = '';
|
||||
}
|
||||
|
||||
var fldBitrate = form.querySelector('.fldBitrate');
|
||||
var txtBitrate = form.querySelector('#txtBitrate');
|
||||
|
||||
if (qualityId === 'custom') {
|
||||
|
||||
if (fldBitrate) {
|
||||
fldBitrate.classList.remove('hide');
|
||||
}
|
||||
if (txtBitrate) {
|
||||
txtBitrate.setAttribute('required', 'required');
|
||||
}
|
||||
} else {
|
||||
if (fldBitrate) {
|
||||
fldBitrate.classList.add('hide');
|
||||
}
|
||||
if (txtBitrate) {
|
||||
txtBitrate.removeAttribute('required');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderTargetDialogOptions(form, options) {
|
||||
|
||||
currentDialogOptions = options;
|
||||
|
||||
var fldProfile = form.querySelector('.fldProfile');
|
||||
var selectProfile = form.querySelector('#selectProfile');
|
||||
|
||||
if (options.ProfileOptions.length && options.Options.indexOf('Profile') !== -1) {
|
||||
if (fldProfile) {
|
||||
fldProfile.classList.remove('hide');
|
||||
}
|
||||
if (selectProfile) {
|
||||
selectProfile.setAttribute('required', 'required');
|
||||
}
|
||||
} else {
|
||||
if (fldProfile) {
|
||||
fldProfile.classList.add('hide');
|
||||
}
|
||||
if (selectProfile) {
|
||||
selectProfile.removeAttribute('required');
|
||||
}
|
||||
}
|
||||
|
||||
setQualityFieldVisible(form, options.QualityOptions.length > 0);
|
||||
|
||||
if (selectProfile) {
|
||||
selectProfile.innerHTML = options.ProfileOptions.map(function (o) {
|
||||
|
||||
var selectedAttribute = o.IsDefault ? ' selected="selected"' : '';
|
||||
return '<option value="' + o.Id + '"' + selectedAttribute + '>' + o.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
|
||||
selectProfile.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
|
||||
var selectQuality = form.querySelector('#selectQuality');
|
||||
if (selectQuality) {
|
||||
selectQuality.innerHTML = options.QualityOptions.map(function (o) {
|
||||
|
||||
var selectedAttribute = o.IsDefault ? ' selected="selected"' : '';
|
||||
return '<option value="' + o.Id + '"' + selectedAttribute + '>' + o.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
|
||||
var lastQuality = appSettings.get('sync-lastquality');
|
||||
if (lastQuality && options.QualityOptions.filter(function (i) {
|
||||
|
||||
return i.Id === lastQuality;
|
||||
|
||||
}).length) {
|
||||
selectQuality.value = lastQuality;
|
||||
}
|
||||
|
||||
selectQuality.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function loadQualityOptions(form, targetId, dialogOptionsFn) {
|
||||
|
||||
return dialogOptionsFn(targetId).then(function (options) {
|
||||
|
||||
return renderTargetDialogOptions(form, options);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
showMenu: showSyncMenu,
|
||||
renderForm: renderForm,
|
||||
setJobValues: setJobValues
|
||||
};
|
||||
});
|
Binary file not shown.
Before Width: | Height: | Size: 48 KiB |
Binary file not shown.
Before Width: | Height: | Size: 49 KiB |
@ -1,313 +0,0 @@
|
||||
define(['browser', 'dom', 'layoutManager', 'css!./viewcontainer-lite'], function (browser, dom, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
var mainAnimatedPages = document.querySelector('.mainAnimatedPages');
|
||||
var allPages = [];
|
||||
var currentUrls = [];
|
||||
var pageContainerCount = 3;
|
||||
var selectedPageIndex = -1;
|
||||
|
||||
function enableAnimation() {
|
||||
|
||||
// too slow
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return browser.supportsCssAnimation();
|
||||
}
|
||||
|
||||
function findLastView(parent, className) {
|
||||
|
||||
var nodes = parent.childNodes;
|
||||
for (var i = nodes.length - 1; i >= 0; i--) {
|
||||
var node = nodes[i];
|
||||
var classList = node.classList;
|
||||
if (classList && classList.contains(className)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findViewBefore(elem, className) {
|
||||
|
||||
var node = elem.previousSibling;
|
||||
while (node) {
|
||||
var classList = node.classList;
|
||||
if (classList && classList.contains(className)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
node = node.previousSibling;
|
||||
}
|
||||
}
|
||||
|
||||
function loadView(options) {
|
||||
|
||||
if (options.cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
cancelActiveAnimations();
|
||||
|
||||
var selected = selectedPageIndex;
|
||||
var previousAnimatable = selected === -1 ? null : allPages[selected];
|
||||
var pageIndex = selected + 1;
|
||||
|
||||
if (pageIndex >= pageContainerCount) {
|
||||
pageIndex = 0;
|
||||
}
|
||||
|
||||
var viewHtml = options.view;
|
||||
|
||||
var properties = [];
|
||||
if (options.fullscreen) {
|
||||
properties.push('fullscreen');
|
||||
}
|
||||
|
||||
var currentPage = allPages[pageIndex];
|
||||
|
||||
var view;
|
||||
|
||||
if (currentPage) {
|
||||
triggerDestroy(currentPage);
|
||||
currentPage.insertAdjacentHTML('beforebegin', viewHtml);
|
||||
view = findViewBefore(currentPage, 'view');
|
||||
|
||||
mainAnimatedPages.removeChild(currentPage);
|
||||
|
||||
} else {
|
||||
mainAnimatedPages.insertAdjacentHTML('beforeend', viewHtml);
|
||||
|
||||
view = findLastView(mainAnimatedPages, 'view');
|
||||
}
|
||||
|
||||
view.classList.add('mainAnimatedPage');
|
||||
|
||||
if (properties.length) {
|
||||
view.setAttribute('data-properties', properties.join(','));
|
||||
}
|
||||
|
||||
if (options.type) {
|
||||
view.setAttribute('data-type', options.type);
|
||||
}
|
||||
|
||||
allPages[pageIndex] = view;
|
||||
|
||||
if (onBeforeChange) {
|
||||
onBeforeChange(view, false, options);
|
||||
}
|
||||
|
||||
beforeAnimate(allPages, pageIndex, selected);
|
||||
|
||||
// animate here
|
||||
return animate(view, previousAnimatable, options.transition, options.isBack).then(function () {
|
||||
|
||||
selectedPageIndex = pageIndex;
|
||||
currentUrls[pageIndex] = options.url;
|
||||
if (!options.cancel && previousAnimatable) {
|
||||
afterAnimate(allPages, pageIndex);
|
||||
}
|
||||
|
||||
return view;
|
||||
});
|
||||
}
|
||||
|
||||
function beforeAnimate(allPages, newPageIndex, oldPageIndex) {
|
||||
for (var i = 0, length = allPages.length; i < length; i++) {
|
||||
if (newPageIndex === i || oldPageIndex === i) {
|
||||
//allPages[i].classList.remove('hide');
|
||||
} else {
|
||||
allPages[i].classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function afterAnimate(allPages, newPageIndex) {
|
||||
for (var i = 0, length = allPages.length; i < length; i++) {
|
||||
if (newPageIndex === i) {
|
||||
//allPages[i].classList.remove('hide');
|
||||
} else {
|
||||
allPages[i].classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function animate(newAnimatedPage, oldAnimatedPage, transition, isBack) {
|
||||
|
||||
if (enableAnimation() && oldAnimatedPage) {
|
||||
if (transition === 'slide') {
|
||||
return slide(newAnimatedPage, oldAnimatedPage, transition, isBack);
|
||||
} else if (transition === 'fade') {
|
||||
return fade(newAnimatedPage, oldAnimatedPage, transition, isBack);
|
||||
} else {
|
||||
clearAnimation(newAnimatedPage);
|
||||
if (oldAnimatedPage) {
|
||||
clearAnimation(oldAnimatedPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function clearAnimation(elem) {
|
||||
setAnimation(elem, 'none');
|
||||
}
|
||||
|
||||
function slide(newAnimatedPage, oldAnimatedPage, transition, isBack) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var duration = layoutManager.tv ? 450 : 160;
|
||||
|
||||
var animations = [];
|
||||
|
||||
if (oldAnimatedPage) {
|
||||
if (isBack) {
|
||||
setAnimation(oldAnimatedPage, 'view-slideright-r ' + duration + 'ms ease-out normal both');
|
||||
} else {
|
||||
setAnimation(oldAnimatedPage, 'view-slideleft-r ' + duration + 'ms ease-out normal both');
|
||||
}
|
||||
animations.push(oldAnimatedPage);
|
||||
}
|
||||
|
||||
if (isBack) {
|
||||
setAnimation(newAnimatedPage, 'view-slideright ' + duration + 'ms ease-out normal both');
|
||||
} else {
|
||||
setAnimation(newAnimatedPage, 'view-slideleft ' + duration + 'ms ease-out normal both');
|
||||
}
|
||||
animations.push(newAnimatedPage);
|
||||
|
||||
currentAnimations = animations;
|
||||
|
||||
var onAnimationComplete = function () {
|
||||
dom.removeEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
resolve();
|
||||
};
|
||||
|
||||
dom.addEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function fade(newAnimatedPage, oldAnimatedPage, transition, isBack) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var duration = layoutManager.tv ? 450 : 270;
|
||||
var animations = [];
|
||||
|
||||
newAnimatedPage.style.opacity = 0;
|
||||
setAnimation(newAnimatedPage, 'view-fadein ' + duration + 'ms ease-in normal both');
|
||||
animations.push(newAnimatedPage);
|
||||
|
||||
if (oldAnimatedPage) {
|
||||
setAnimation(oldAnimatedPage, 'view-fadeout ' + duration + 'ms ease-out normal both');
|
||||
animations.push(oldAnimatedPage);
|
||||
}
|
||||
|
||||
currentAnimations = animations;
|
||||
|
||||
var onAnimationComplete = function () {
|
||||
dom.removeEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
resolve();
|
||||
};
|
||||
|
||||
dom.addEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setAnimation(elem, value) {
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
elem.style.animation = value;
|
||||
});
|
||||
}
|
||||
|
||||
var currentAnimations = [];
|
||||
function cancelActiveAnimations() {
|
||||
|
||||
var animations = currentAnimations;
|
||||
for (var i = 0, length = animations.length; i < length; i++) {
|
||||
animations[i].style.animation = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
var onBeforeChange;
|
||||
function setOnBeforeChange(fn) {
|
||||
onBeforeChange = fn;
|
||||
}
|
||||
|
||||
function tryRestoreView(options) {
|
||||
|
||||
var url = options.url;
|
||||
var index = currentUrls.indexOf(url);
|
||||
|
||||
if (index !== -1) {
|
||||
|
||||
var animatable = allPages[index];
|
||||
var view = animatable;
|
||||
|
||||
if (view) {
|
||||
|
||||
if (options.cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
cancelActiveAnimations();
|
||||
|
||||
var selected = selectedPageIndex;
|
||||
var previousAnimatable = selected === -1 ? null : allPages[selected];
|
||||
|
||||
if (onBeforeChange) {
|
||||
onBeforeChange(view, true, options);
|
||||
}
|
||||
|
||||
beforeAnimate(allPages, index, selected);
|
||||
|
||||
animatable.classList.remove('hide');
|
||||
|
||||
return animate(animatable, previousAnimatable, options.transition, options.isBack).then(function () {
|
||||
|
||||
selectedPageIndex = index;
|
||||
if (!options.cancel && previousAnimatable) {
|
||||
afterAnimate(allPages, index);
|
||||
}
|
||||
return view;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
function triggerDestroy(view) {
|
||||
|
||||
view.dispatchEvent(new CustomEvent('viewdestroy', {
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
||||
|
||||
function reset() {
|
||||
|
||||
allPages = [];
|
||||
currentUrls = [];
|
||||
mainAnimatedPages.innerHTML = '';
|
||||
selectedPageIndex = -1;
|
||||
}
|
||||
|
||||
return {
|
||||
loadView: loadView,
|
||||
tryRestoreView: tryRestoreView,
|
||||
reset: reset,
|
||||
setOnBeforeChange: setOnBeforeChange
|
||||
};
|
||||
});
|
263
src/bower_components/fetch/fetch.js
vendored
263
src/bower_components/fetch/fetch.js
vendored
@ -1,263 +0,0 @@
|
||||
! function(self) {
|
||||
"use strict";
|
||||
|
||||
function normalizeName(name) {
|
||||
if ("string" != typeof name && (name = String(name)), /[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) throw new TypeError("Invalid character in header field name");
|
||||
return name.toLowerCase()
|
||||
}
|
||||
|
||||
function normalizeValue(value) {
|
||||
return "string" != typeof value && (value = String(value)), value
|
||||
}
|
||||
|
||||
function iteratorFor(items) {
|
||||
var iterator = {
|
||||
next: function() {
|
||||
var value = items.shift();
|
||||
return {
|
||||
done: void 0 === value,
|
||||
value: value
|
||||
}
|
||||
}
|
||||
};
|
||||
return support.iterable && (iterator[Symbol.iterator] = function() {
|
||||
return iterator
|
||||
}), iterator
|
||||
}
|
||||
|
||||
function Headers(headers) {
|
||||
this.map = {}, headers instanceof Headers ? headers.forEach(function(value, name) {
|
||||
this.append(name, value)
|
||||
}, this) : headers && Object.getOwnPropertyNames(headers).forEach(function(name) {
|
||||
this.append(name, headers[name])
|
||||
}, this)
|
||||
}
|
||||
|
||||
function consumed(body) {
|
||||
if (body.bodyUsed) return Promise.reject(new TypeError("Already read"));
|
||||
body.bodyUsed = !0
|
||||
}
|
||||
|
||||
function fileReaderReady(reader) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
reader.onload = function() {
|
||||
resolve(reader.result)
|
||||
}, reader.onerror = function() {
|
||||
reject(reader.error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function readBlobAsArrayBuffer(blob) {
|
||||
var reader = new FileReader,
|
||||
promise = fileReaderReady(reader);
|
||||
return reader.readAsArrayBuffer(blob), promise
|
||||
}
|
||||
|
||||
function readBlobAsText(blob) {
|
||||
var reader = new FileReader,
|
||||
promise = fileReaderReady(reader);
|
||||
return reader.readAsText(blob), promise
|
||||
}
|
||||
|
||||
function readArrayBufferAsText(buf) {
|
||||
for (var view = new Uint8Array(buf), chars = new Array(view.length), i = 0; i < view.length; i++) chars[i] = String.fromCharCode(view[i]);
|
||||
return chars.join("")
|
||||
}
|
||||
|
||||
function bufferClone(buf) {
|
||||
if (buf.slice) return buf.slice(0);
|
||||
var view = new Uint8Array(buf.byteLength);
|
||||
return view.set(new Uint8Array(buf)), view.buffer
|
||||
}
|
||||
|
||||
function Body() {
|
||||
return this.bodyUsed = !1, this._initBody = function(body) {
|
||||
if (this._bodyInit = body, body)
|
||||
if ("string" == typeof body) this._bodyText = body;
|
||||
else if (support.blob && Blob.prototype.isPrototypeOf(body)) this._bodyBlob = body;
|
||||
else if (support.formData && FormData.prototype.isPrototypeOf(body)) this._bodyFormData = body;
|
||||
else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) this._bodyText = body.toString();
|
||||
else if (support.arrayBuffer && support.blob && isDataView(body)) this._bodyArrayBuffer = bufferClone(body.buffer), this._bodyInit = new Blob([this._bodyArrayBuffer]);
|
||||
else {
|
||||
if (!support.arrayBuffer || !ArrayBuffer.prototype.isPrototypeOf(body) && !isArrayBufferView(body)) throw new Error("unsupported BodyInit type");
|
||||
this._bodyArrayBuffer = bufferClone(body)
|
||||
} else this._bodyText = "";
|
||||
this.headers.get("content-type") || ("string" == typeof body ? this.headers.set("content-type", "text/plain;charset=UTF-8") : this._bodyBlob && this._bodyBlob.type ? this.headers.set("content-type", this._bodyBlob.type) : support.searchParams && URLSearchParams.prototype.isPrototypeOf(body) && this.headers.set("content-type", "application/x-www-form-urlencoded;charset=UTF-8"))
|
||||
}, support.blob && (this.blob = function() {
|
||||
var rejected = consumed(this);
|
||||
if (rejected) return rejected;
|
||||
if (this._bodyBlob) return Promise.resolve(this._bodyBlob);
|
||||
if (this._bodyArrayBuffer) return Promise.resolve(new Blob([this._bodyArrayBuffer]));
|
||||
if (this._bodyFormData) throw new Error("could not read FormData body as blob");
|
||||
return Promise.resolve(new Blob([this._bodyText]))
|
||||
}, this.arrayBuffer = function() {
|
||||
return this._bodyArrayBuffer ? consumed(this) || Promise.resolve(this._bodyArrayBuffer) : this.blob().then(readBlobAsArrayBuffer)
|
||||
}), this.text = function() {
|
||||
var rejected = consumed(this);
|
||||
if (rejected) return rejected;
|
||||
if (this._bodyBlob) return readBlobAsText(this._bodyBlob);
|
||||
if (this._bodyArrayBuffer) return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
|
||||
if (this._bodyFormData) throw new Error("could not read FormData body as text");
|
||||
return Promise.resolve(this._bodyText)
|
||||
}, support.formData && (this.formData = function() {
|
||||
return this.text().then(decode)
|
||||
}), this.json = function() {
|
||||
return this.text().then(JSON.parse)
|
||||
}, this
|
||||
}
|
||||
|
||||
function normalizeMethod(method) {
|
||||
var upcased = method.toUpperCase();
|
||||
return methods.indexOf(upcased) > -1 ? upcased : method
|
||||
}
|
||||
|
||||
function Request(input, options) {
|
||||
options = options || {};
|
||||
var body = options.body;
|
||||
if ("string" == typeof input) this.url = input;
|
||||
else {
|
||||
if (input.bodyUsed) throw new TypeError("Already read");
|
||||
this.url = input.url, this.credentials = input.credentials, options.headers || (this.headers = new Headers(input.headers)), this.method = input.method, this.mode = input.mode, body || null == input._bodyInit || (body = input._bodyInit, input.bodyUsed = !0)
|
||||
}
|
||||
if (this.credentials = options.credentials || this.credentials || "omit", !options.headers && this.headers || (this.headers = new Headers(options.headers)), this.method = normalizeMethod(options.method || this.method || "GET"), this.mode = options.mode || this.mode || null, this.referrer = null, ("GET" === this.method || "HEAD" === this.method) && body) throw new TypeError("Body not allowed for GET or HEAD requests");
|
||||
this._initBody(body)
|
||||
}
|
||||
|
||||
function decode(body) {
|
||||
var form = new FormData;
|
||||
return body.trim().split("&").forEach(function(bytes) {
|
||||
if (bytes) {
|
||||
var split = bytes.split("="),
|
||||
name = split.shift().replace(/\+/g, " "),
|
||||
value = split.join("=").replace(/\+/g, " ");
|
||||
form.append(decodeURIComponent(name), decodeURIComponent(value))
|
||||
}
|
||||
}), form
|
||||
}
|
||||
|
||||
function parseHeaders(rawHeaders) {
|
||||
var headers = new Headers;
|
||||
return rawHeaders.split("\r\n").forEach(function(line) {
|
||||
var parts = line.split(":"),
|
||||
key = parts.shift().trim();
|
||||
if (key) {
|
||||
var value = parts.join(":").trim();
|
||||
headers.append(key, value)
|
||||
}
|
||||
}), headers
|
||||
}
|
||||
|
||||
function Response(bodyInit, options) {
|
||||
options || (options = {}), this.type = "default", this.status = "status" in options ? options.status : 200, this.ok = this.status >= 200 && this.status < 300, this.statusText = "statusText" in options ? options.statusText : "OK", this.headers = new Headers(options.headers), this.url = options.url || "", this._initBody(bodyInit)
|
||||
}
|
||||
if (!self.fetch) {
|
||||
var support = {
|
||||
searchParams: "URLSearchParams" in self,
|
||||
iterable: "Symbol" in self && "iterator" in Symbol,
|
||||
blob: "FileReader" in self && "Blob" in self && function() {
|
||||
try {
|
||||
return new Blob, !0
|
||||
} catch (e) {
|
||||
return !1
|
||||
}
|
||||
}(),
|
||||
formData: "FormData" in self,
|
||||
arrayBuffer: "ArrayBuffer" in self
|
||||
};
|
||||
if (support.arrayBuffer) var viewClasses = ["[object Int8Array]", "[object Uint8Array]", "[object Uint8ClampedArray]", "[object Int16Array]", "[object Uint16Array]", "[object Int32Array]", "[object Uint32Array]", "[object Float32Array]", "[object Float64Array]"],
|
||||
isDataView = function(obj) {
|
||||
return obj && DataView.prototype.isPrototypeOf(obj)
|
||||
},
|
||||
isArrayBufferView = ArrayBuffer.isView || function(obj) {
|
||||
return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
|
||||
};
|
||||
Headers.prototype.append = function(name, value) {
|
||||
name = normalizeName(name), value = normalizeValue(value);
|
||||
var list = this.map[name];
|
||||
list || (list = [], this.map[name] = list), list.push(value)
|
||||
}, Headers.prototype.delete = function(name) {
|
||||
delete this.map[normalizeName(name)]
|
||||
}, Headers.prototype.get = function(name) {
|
||||
var values = this.map[normalizeName(name)];
|
||||
return values ? values[0] : null
|
||||
}, Headers.prototype.getAll = function(name) {
|
||||
return this.map[normalizeName(name)] || []
|
||||
}, Headers.prototype.has = function(name) {
|
||||
return this.map.hasOwnProperty(normalizeName(name))
|
||||
}, Headers.prototype.set = function(name, value) {
|
||||
this.map[normalizeName(name)] = [normalizeValue(value)]
|
||||
}, Headers.prototype.forEach = function(callback, thisArg) {
|
||||
Object.getOwnPropertyNames(this.map).forEach(function(name) {
|
||||
this.map[name].forEach(function(value) {
|
||||
callback.call(thisArg, value, name, this)
|
||||
}, this)
|
||||
}, this)
|
||||
}, Headers.prototype.keys = function() {
|
||||
var items = [];
|
||||
return this.forEach(function(value, name) {
|
||||
items.push(name)
|
||||
}), iteratorFor(items)
|
||||
}, Headers.prototype.values = function() {
|
||||
var items = [];
|
||||
return this.forEach(function(value) {
|
||||
items.push(value)
|
||||
}), iteratorFor(items)
|
||||
}, Headers.prototype.entries = function() {
|
||||
var items = [];
|
||||
return this.forEach(function(value, name) {
|
||||
items.push([name, value])
|
||||
}), iteratorFor(items)
|
||||
}, support.iterable && (Headers.prototype[Symbol.iterator] = Headers.prototype.entries);
|
||||
var methods = ["DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT"];
|
||||
Request.prototype.clone = function() {
|
||||
return new Request(this, {
|
||||
body: this._bodyInit
|
||||
})
|
||||
}, Body.call(Request.prototype), Body.call(Response.prototype), Response.prototype.clone = function() {
|
||||
return new Response(this._bodyInit, {
|
||||
status: this.status,
|
||||
statusText: this.statusText,
|
||||
headers: new Headers(this.headers),
|
||||
url: this.url
|
||||
})
|
||||
}, Response.error = function() {
|
||||
var response = new Response(null, {
|
||||
status: 0,
|
||||
statusText: ""
|
||||
});
|
||||
return response.type = "error", response
|
||||
};
|
||||
var redirectStatuses = [301, 302, 303, 307, 308];
|
||||
Response.redirect = function(url, status) {
|
||||
if (-1 === redirectStatuses.indexOf(status)) throw new RangeError("Invalid status code");
|
||||
return new Response(null, {
|
||||
status: status,
|
||||
headers: {
|
||||
location: url
|
||||
}
|
||||
})
|
||||
}, self.Headers = Headers, self.Request = Request, self.Response = Response, self.fetch = function(input, init) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var request = new Request(input, init),
|
||||
xhr = new XMLHttpRequest;
|
||||
xhr.onload = function() {
|
||||
var options = {
|
||||
status: xhr.status,
|
||||
statusText: xhr.statusText,
|
||||
headers: parseHeaders(xhr.getAllResponseHeaders() || "")
|
||||
};
|
||||
options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL");
|
||||
var body = "response" in xhr ? xhr.response : xhr.responseText;
|
||||
resolve(new Response(body, options))
|
||||
}, xhr.onerror = function() {
|
||||
reject(new TypeError("Network request failed"))
|
||||
}, xhr.ontimeout = function() {
|
||||
reject(new TypeError("Network request failed"))
|
||||
}, xhr.open(request.method, request.url, !0), "include" === request.credentials && (xhr.withCredentials = !0), "responseType" in xhr && support.blob && (xhr.responseType = "blob"), request.headers.forEach(function(value, name) {
|
||||
xhr.setRequestHeader(name, value)
|
||||
}), xhr.send(void 0 === request._bodyInit ? null : request._bodyInit)
|
||||
})
|
||||
}, self.fetch.polyfill = !0
|
||||
}
|
||||
}("undefined" != typeof self ? self : this);
|
3
src/components/actionsheet/package.json
Normal file
3
src/components/actionsheet/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "actionsheet.js"
|
||||
}
|
40
src/components/alert.js
Normal file
40
src/components/alert.js
Normal file
@ -0,0 +1,40 @@
|
||||
define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize) {
|
||||
'use strict';
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
text: text
|
||||
};
|
||||
} else {
|
||||
options = text;
|
||||
}
|
||||
|
||||
if (browser.tv && window.alert) {
|
||||
alert(replaceAll(options.text || '', '<br/>', '\n'));
|
||||
} else {
|
||||
var items = [];
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('ButtonGotIt'),
|
||||
id: 'ok',
|
||||
type: 'submit'
|
||||
});
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
return dialog(options).then(function (result) {
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'pageJs', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, layoutManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost, connectionManager) {
|
||||
define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'page', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, layoutManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost, connectionManager) {
|
||||
'use strict';
|
||||
|
||||
var appRouter = {
|
||||
@ -14,31 +14,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
},
|
||||
showSettings: function () {
|
||||
show('/settings/settings.html');
|
||||
},
|
||||
showSearch: function () {
|
||||
skinManager.getCurrentSkin().search();
|
||||
},
|
||||
showGenre: function (options) {
|
||||
skinManager.getCurrentSkin().showGenre(options);
|
||||
},
|
||||
showGuide: function () {
|
||||
skinManager.getCurrentSkin().showGuide({
|
||||
serverId: connectionManager.currentApiClient().serverId()
|
||||
});
|
||||
},
|
||||
showLiveTV: function () {
|
||||
skinManager.getCurrentSkin().showLiveTV({
|
||||
serverId: connectionManager.currentApiClient().serverId()
|
||||
});
|
||||
},
|
||||
showRecordedTV: function () {
|
||||
skinManager.getCurrentSkin().showRecordedTV();
|
||||
},
|
||||
showFavorites: function () {
|
||||
skinManager.getCurrentSkin().showFavorites();
|
||||
},
|
||||
showNowPlaying: function () {
|
||||
skinManager.getCurrentSkin().showNowPlaying();
|
||||
}
|
||||
};
|
||||
|
||||
@ -125,13 +100,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
sendRouteToViewManager(ctx, next, route, controllerFactory);
|
||||
};
|
||||
|
||||
require(route.dependencies || [], function () {
|
||||
if (route.controller) {
|
||||
require([route.controller], onInitComplete);
|
||||
require(['controllers/' + route.controller], onInitComplete);
|
||||
} else {
|
||||
onInitComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cancelCurrentLoadRequest() {
|
||||
@ -363,8 +336,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
|
||||
firstConnectionResult = result;
|
||||
|
||||
loading.hide();
|
||||
|
||||
options = options || {};
|
||||
|
||||
page({
|
||||
@ -372,6 +343,8 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
hashbang: options.hashbang !== false,
|
||||
enableHistory: enableHistory()
|
||||
});
|
||||
}).finally(function () {
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
@ -438,11 +411,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
|
||||
console.log('appRouter - user is authenticated');
|
||||
|
||||
if (ctx.isBack && (route.isDefaultRoute || route.startup) && !isCurrentRouteStartup) {
|
||||
handleBackToDefault();
|
||||
return;
|
||||
}
|
||||
else if (route.isDefaultRoute) {
|
||||
if (route.isDefaultRoute) {
|
||||
console.log('appRouter - loading skin home page');
|
||||
loadUserSkinWithOptions(ctx);
|
||||
return;
|
||||
@ -501,30 +470,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
var isHandlingBackToDefault;
|
||||
var isDummyBackToHome;
|
||||
|
||||
function handleBackToDefault() {
|
||||
|
||||
if (!appHost.supports('exitmenu') && appHost.supports('exit')) {
|
||||
appHost.exit();
|
||||
return;
|
||||
}
|
||||
|
||||
isDummyBackToHome = true;
|
||||
skinManager.loadUserSkin();
|
||||
|
||||
if (isHandlingBackToDefault) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This must result in a call to either
|
||||
// skinManager.loadUserSkin();
|
||||
// Logout
|
||||
// Or exit app
|
||||
skinManager.getCurrentSkin().showBackMenu().then(function () {
|
||||
|
||||
isHandlingBackToDefault = false;
|
||||
});
|
||||
}
|
||||
|
||||
function loadContent(ctx, route, html, request) {
|
||||
|
||||
html = globalize.translateDocument(html, route.dictionary);
|
||||
@ -670,30 +615,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
return currentRouteInfo ? currentRouteInfo.route : null;
|
||||
}
|
||||
|
||||
function goHome() {
|
||||
|
||||
var skin = skinManager.getCurrentSkin();
|
||||
|
||||
if (skin.getHomeRoute) {
|
||||
var homePath = skin.getHomeRoute();
|
||||
return show(pluginManager.mapRoute(skin, homePath));
|
||||
} else {
|
||||
var homeRoute = skin.getRoutes().filter(function (r) {
|
||||
return r.type === 'home';
|
||||
})[0];
|
||||
|
||||
return show(pluginManager.mapRoute(skin, homeRoute));
|
||||
}
|
||||
}
|
||||
|
||||
function getRouteUrl(item, options) {
|
||||
if (item === 'settings') {
|
||||
return 'settings/settings.html';
|
||||
}
|
||||
|
||||
return skinManager.getCurrentSkin().getRouteUrl(item, options);
|
||||
}
|
||||
|
||||
function showItem(item, serverId, options) {
|
||||
|
||||
if (typeof (item) === 'string') {
|
||||
@ -714,20 +635,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
}
|
||||
|
||||
function setTitle(title) {
|
||||
skinManager.getCurrentSkin().setTitle(title);
|
||||
}
|
||||
|
||||
function showVideoOsd() {
|
||||
var skin = skinManager.getCurrentSkin();
|
||||
|
||||
var homeRoute = skin.getRoutes().filter(function (r) {
|
||||
return r.type === 'video-osd';
|
||||
})[0];
|
||||
|
||||
return show(pluginManager.mapRoute(skin, homeRoute));
|
||||
}
|
||||
|
||||
var allRoutes = [];
|
||||
|
||||
function addRoute(path, newRoute) {
|
||||
@ -834,15 +741,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
appRouter.canGoBack = canGoBack;
|
||||
appRouter.current = current;
|
||||
appRouter.beginConnectionWizard = beginConnectionWizard;
|
||||
appRouter.goHome = goHome;
|
||||
appRouter.showItem = showItem;
|
||||
appRouter.setTitle = setTitle;
|
||||
appRouter.setTransparency = setTransparency;
|
||||
appRouter.getRoutes = getRoutes;
|
||||
appRouter.getRouteUrl = getRouteUrl;
|
||||
appRouter.pushState = pushState;
|
||||
appRouter.enableNativeHistory = enableNativeHistory;
|
||||
appRouter.showVideoOsd = showVideoOsd;
|
||||
appRouter.handleAnchorClick = page.handleAnchorClick;
|
||||
appRouter.TransparencyLevel = {
|
||||
None: 0,
|
@ -3,107 +3,189 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function(appSett
|
||||
|
||||
function getBaseProfileOptions(item) {
|
||||
var disableHlsVideoAudioCodecs = [];
|
||||
return item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType) && ((browser.edge || browser.msie) && disableHlsVideoAudioCodecs.push("mp3"), disableHlsVideoAudioCodecs.push("ac3"), disableHlsVideoAudioCodecs.push("eac3"), disableHlsVideoAudioCodecs.push("opus")), {
|
||||
enableMkvProgressive: !1,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
|
||||
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||
if (browser.edge || browser.msie) {
|
||||
disableHlsVideoAudioCodecs.push("mp3");
|
||||
}
|
||||
|
||||
disableHlsVideoAudioCodecs.push("ac3");
|
||||
disableHlsVideoAudioCodecs.push("eac3");
|
||||
disableHlsVideoAudioCodecs.push("opus");
|
||||
}
|
||||
|
||||
return {
|
||||
enableMkvProgressive: false,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
};
|
||||
}
|
||||
|
||||
function getDeviceProfileForWindowsUwp(item) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(["browserdeviceprofile", "environments/windows-uwp/mediacaps"], function (profileBuilder, uwpMediaCaps) {
|
||||
var profileOptions = getBaseProfileOptions(item);
|
||||
profileOptions.supportsDts = uwpMediaCaps.supportsDTS(), profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby(), profileOptions.audioChannels = uwpMediaCaps.getAudioChannels(), resolve(profileBuilder(profileOptions))
|
||||
})
|
||||
})
|
||||
profileOptions.supportsDts = uwpMediaCaps.supportsDTS();
|
||||
profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby();
|
||||
profileOptions.audioChannels = uwpMediaCaps.getAudioChannels();
|
||||
resolve(profileBuilder(profileOptions));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceProfile(item, options) {
|
||||
return options = options || {}, self.Windows ? getDeviceProfileForWindowsUwp(item) : new Promise(function(resolve, reject) {
|
||||
options = options || {};
|
||||
|
||||
if (self.Windows) {
|
||||
return getDeviceProfileForWindowsUwp(item);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
require(["browserdeviceprofile"], function (profileBuilder) {
|
||||
var profile = profileBuilder(getBaseProfileOptions(item));
|
||||
item && !options.isRetry && "allcomplexformats" !== appSettings.get("subtitleburnin") && (browser.orsay || browser.tizen || (profile.SubtitleProfiles.push({
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
|
||||
} else {
|
||||
profile = profileBuilder(getBaseProfileOptions(item));
|
||||
|
||||
if (item && !options.isRetry && "allcomplexformats" !== appSettings.get("subtitleburnin")) {
|
||||
if (!browser.orsay && !browser.tizen) {
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: "ass",
|
||||
Method: "External"
|
||||
}), profile.SubtitleProfiles.push({
|
||||
});
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: "ssa",
|
||||
Method: "External"
|
||||
}))), resolve(profile)
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1")
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var strReplace2 = escapeRegExp(strReplace),
|
||||
reg = new RegExp(strReplace2, "ig");
|
||||
return originalString.replace(reg, strWith)
|
||||
var strReplace2 = escapeRegExp(strReplace);
|
||||
var reg = new RegExp(strReplace2, "ig");
|
||||
return originalString.replace(reg, strWith);
|
||||
}
|
||||
|
||||
function generateDeviceId() {
|
||||
var keys = [];
|
||||
if (keys.push(navigator.userAgent), keys.push((new Date).getTime()), self.btoa) {
|
||||
|
||||
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), self.btoa) {
|
||||
var result = replaceAll(btoa(keys.join("|")), "=", "1");
|
||||
return Promise.resolve(result)
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
return Promise.resolve((new Date).getTime())
|
||||
|
||||
return Promise.resolve(new Date().getTime());
|
||||
}
|
||||
|
||||
function getDeviceId() {
|
||||
var key = "_deviceId2",
|
||||
deviceId = appSettings.get(key);
|
||||
return deviceId ? Promise.resolve(deviceId) : generateDeviceId().then(function(deviceId) {
|
||||
return appSettings.set(key, deviceId), deviceId
|
||||
})
|
||||
var key = "_deviceId2";
|
||||
var deviceId = appSettings.get(key);
|
||||
|
||||
if (deviceId) {
|
||||
return Promise.resolve(deviceId);
|
||||
}
|
||||
|
||||
return generateDeviceId().then(function (deviceId) {
|
||||
appSettings.set(key, deviceId);
|
||||
return deviceId;
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceName() {
|
||||
var deviceName;
|
||||
return deviceName = browser.tizen ? "Samsung Smart TV" : browser.web0s ? "LG Smart TV" : browser.operaTv ? "Opera TV" : browser.xboxOne ? "Xbox One" : browser.ps4 ? "Sony PS4" : browser.chrome ? "Chrome" : browser.edge ? "Edge" : browser.firefox ? "Firefox" : browser.msie ? "Internet Explorer" : browser.opera ? "Opera" : "Web Browser", browser.ipad ? deviceName += " Ipad" : browser.iphone ? deviceName += " Iphone" : browser.android && (deviceName += " Android"), deviceName
|
||||
deviceName = browser.tizen ? "Samsung Smart TV" : browser.web0s ? "LG Smart TV" : browser.operaTv ? "Opera TV" : browser.xboxOne ? "Xbox One" : browser.ps4 ? "Sony PS4" : browser.chrome ? "Chrome" : browser.edge ? "Edge" : browser.firefox ? "Firefox" : browser.msie ? "Internet Explorer" : browser.opera ? "Opera" : "Web Browser";
|
||||
|
||||
if (browser.ipad) {
|
||||
deviceName += " Ipad";
|
||||
} else {
|
||||
if (browser.iphone) {
|
||||
deviceName += " Iphone";
|
||||
} else {
|
||||
if (browser.android) {
|
||||
deviceName += " Android";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
function supportsVoiceInput() {
|
||||
return !browser.tv && (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition)
|
||||
if (!browser.tv) {
|
||||
return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function supportsFullscreen() {
|
||||
if (browser.tv) return !1;
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var element = document.documentElement;
|
||||
return !!(element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || !!document.createElement("video").webkitEnterFullscreen
|
||||
return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement("video").webkitEnterFullscreen;
|
||||
}
|
||||
|
||||
function getSyncProfile() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
return new Promise(function (resolve) {
|
||||
require(["browserdeviceprofile", "appSettings"], function (profileBuilder, appSettings) {
|
||||
var profile = profileBuilder();
|
||||
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate(), resolve(profile)
|
||||
})
|
||||
})
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getSyncProfile(profileBuilder, appSettings);
|
||||
} else {
|
||||
profile = profileBuilder();
|
||||
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate();
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDefaultLayout() {
|
||||
return "desktop"
|
||||
return "desktop";
|
||||
}
|
||||
|
||||
function supportsHtmlMediaAutoplay() {
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) return !0;
|
||||
if (browser.mobile) return !1;
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.mobile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var savedResult = appSettings.get(htmlMediaAutoplayAppStorageKey);
|
||||
return "true" === savedResult || "false" !== savedResult && null
|
||||
return "true" === savedResult || "false" !== savedResult && null;
|
||||
}
|
||||
|
||||
function cueSupported() {
|
||||
try {
|
||||
var video = document.createElement("video"),
|
||||
style = document.createElement("style");
|
||||
style.textContent = "video::cue {background: inherit}", document.body.appendChild(style), document.body.appendChild(video);
|
||||
var video = document.createElement("video");
|
||||
var style = document.createElement("style");
|
||||
style.textContent = "video::cue {background: inherit}";
|
||||
document.body.appendChild(style);
|
||||
document.body.appendChild(video);
|
||||
var cue = window.getComputedStyle(video, "::cue").background;
|
||||
return document.body.removeChild(style), document.body.removeChild(video), !!cue.length
|
||||
document.body.removeChild(style);
|
||||
document.body.removeChild(video);
|
||||
return !!cue.length;
|
||||
} catch (err) {
|
||||
return console.log("Error detecting cue support:" + err), !1
|
||||
console.log("Error detecting cue support:" + err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,33 +205,97 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function(appSett
|
||||
}
|
||||
|
||||
var htmlMediaAutoplayAppStorageKey = "supportshtmlmediaautoplay0";
|
||||
|
||||
var supportedFeatures = function () {
|
||||
var features = [];
|
||||
navigator.share && features.push("sharing");
|
||||
browser.edgeUwp || browser.tv || browser.xboxOne || browser.ps4 || features.push("filedownload");
|
||||
browser.operaTv || browser.tizen || browser.orsay || browser.web0s
|
||||
? features.push("exit")
|
||||
: (features.push("exitmenu"), features.push("plugins"));
|
||||
browser.operaTv || browser.tizen || browser.orsay || browser.web0s || browser.ps4 || (features.push("externallinks"), features.push("externalpremium"));
|
||||
browser.operaTv || features.push("externallinkdisplay");
|
||||
supportsVoiceInput() && features.push("voiceinput");
|
||||
!browser.tv && !browser.xboxOne && browser.ps4, supportsHtmlMediaAutoplay() && (features.push("htmlaudioautoplay"), features.push("htmlvideoautoplay"));
|
||||
browser.edgeUwp && features.push("sync");
|
||||
supportsFullscreen() && features.push("fullscreenchange");
|
||||
(browser.chrome || browser.edge && !browser.slow) && (browser.noAnimation || browser.edgeUwp || browser.xboxOne || features.push("imageanalysis"));
|
||||
(browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) && features.push("physicalvolumecontrol");
|
||||
browser.tv || browser.xboxOne || browser.ps4 || features.push("remotecontrol");
|
||||
browser.operaTv || browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp || features.push("remotevideo");
|
||||
|
||||
if (navigator.share) {
|
||||
features.push("sharing");
|
||||
}
|
||||
|
||||
if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push("filedownload");
|
||||
}
|
||||
|
||||
if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) {
|
||||
features.push("exit");
|
||||
} else {
|
||||
features.push("exitmenu");
|
||||
features.push("plugins");
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.ps4) {
|
||||
features.push("externallinks");
|
||||
features.push("externalpremium");
|
||||
}
|
||||
|
||||
if (!browser.operaTv) {
|
||||
features.push("externallinkdisplay");
|
||||
}
|
||||
|
||||
if (supportsVoiceInput()) {
|
||||
features.push("voiceinput");
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne) {
|
||||
browser.ps4;
|
||||
}
|
||||
|
||||
if (supportsHtmlMediaAutoplay()) {
|
||||
features.push("htmlaudioautoplay");
|
||||
features.push("htmlvideoautoplay");
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
features.push("sync");
|
||||
}
|
||||
|
||||
if (supportsFullscreen()) {
|
||||
features.push("fullscreenchange");
|
||||
}
|
||||
|
||||
if (browser.chrome || browser.edge && !browser.slow) {
|
||||
if (!browser.noAnimation && !browser.edgeUwp && !browser.xboxOne) {
|
||||
features.push("imageanalysis");
|
||||
}
|
||||
}
|
||||
|
||||
if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
|
||||
features.push("physicalvolumecontrol");
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push("remotecontrol");
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.edgeUwp) {
|
||||
features.push("remotevideo");
|
||||
}
|
||||
|
||||
features.push("displaylanguage");
|
||||
features.push("otherapppromotions");
|
||||
features.push("targetblank");
|
||||
features.push("multiserver");
|
||||
browser.orsay || browser.tizen || browser.msie || !(browser.firefox || browser.ps4 || browser.edge || cueSupported()) || features.push("subtitleappearancesettings");
|
||||
browser.orsay || browser.tizen || features.push("subtitleburnsettings");
|
||||
browser.tv || browser.ps4 || browser.xboxOne || features.push("fileinput");
|
||||
browser.chrome && features.push("chromecast");
|
||||
features.push("targetblank"); // allows users to connect to more than one server
|
||||
//features.push("multiserver");
|
||||
|
||||
if (!browser.orsay && !browser.tizen && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || cueSupported())) {
|
||||
features.push("subtitleappearancesettings");
|
||||
}
|
||||
|
||||
if (!browser.orsay && !browser.tizen) {
|
||||
features.push("subtitleburnsettings");
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.ps4 && !browser.xboxOne) {
|
||||
features.push("fileinput");
|
||||
}
|
||||
|
||||
if (browser.chrome) {
|
||||
features.push("chromecast");
|
||||
}
|
||||
|
||||
return features;
|
||||
}();
|
||||
|
||||
if (supportedFeatures.indexOf("htmlvideoautoplay") === -1 && supportsHtmlMediaAutoplay() !== false) {
|
||||
require(["autoPlayDetect"], function (autoPlayDetect) {
|
||||
autoPlayDetect.supportsHtmlMediaAutoplay().then(function () {
|
||||
@ -169,72 +315,168 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function(appSett
|
||||
var appVersion = window.dashboardVersion || "3.0";
|
||||
var appHost = {
|
||||
getWindowState: function () {
|
||||
return document.windowState || "Normal"
|
||||
return document.windowState || "Normal";
|
||||
},
|
||||
setWindowState: function (state) {
|
||||
alert("setWindowState is not supported and should not be called")
|
||||
alert("setWindowState is not supported and should not be called");
|
||||
},
|
||||
exit: function () {
|
||||
if (browser.tizen) try {
|
||||
tizen.application.getCurrentApplication().exit()
|
||||
if (window.NativeShell) {
|
||||
window.NativeShell.AppHost.exit();
|
||||
} else if (browser.tizen) {
|
||||
try {
|
||||
tizen.application.getCurrentApplication().exit();
|
||||
} catch (err) {
|
||||
console.log("error closing application: " + err)
|
||||
} else window.close()
|
||||
console.log("error closing application: " + err);
|
||||
}
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
},
|
||||
supports: function (command) {
|
||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase())
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.supports(command);
|
||||
}
|
||||
|
||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase());
|
||||
},
|
||||
preferVisualCards: browser.android || browser.chrome,
|
||||
moreIcon: browser.android ? "dots-vert" : "dots-horiz",
|
||||
getSyncProfile: getSyncProfile,
|
||||
getDefaultLayout: getDefaultLayout,
|
||||
getDefaultLayout: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.getDefaultLayout();
|
||||
}
|
||||
|
||||
return getDefaultLayout()
|
||||
},
|
||||
getDeviceProfile: getDeviceProfile,
|
||||
init: function () {
|
||||
return deviceName = getDeviceName(), getDeviceId().then(function(resolvedDeviceId) {
|
||||
deviceId = resolvedDeviceId
|
||||
})
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.init();
|
||||
}
|
||||
|
||||
deviceName = getDeviceName();
|
||||
return getDeviceId().then(function (resolvedDeviceId) {
|
||||
deviceId = resolvedDeviceId;
|
||||
});
|
||||
},
|
||||
deviceName: function () {
|
||||
return deviceName
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceName() : deviceName;
|
||||
},
|
||||
deviceId: function () {
|
||||
return deviceId
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceId() : deviceId;
|
||||
},
|
||||
appName: function () {
|
||||
return "Jellyfin Web"
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appName() : "Jellyfin Web";
|
||||
},
|
||||
appVersion: function () {
|
||||
return appVersion
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appVersion() : appVersion;
|
||||
},
|
||||
getPushTokenInfo: function () {
|
||||
return {}
|
||||
return {};
|
||||
},
|
||||
setThemeColor: function (color) {
|
||||
var metaThemeColor = document.querySelector("meta[name=theme-color]");
|
||||
metaThemeColor && metaThemeColor.setAttribute("content", color)
|
||||
|
||||
if (metaThemeColor) {
|
||||
metaThemeColor.setAttribute("content", color);
|
||||
}
|
||||
},
|
||||
setUserScalable: function (scalable) {
|
||||
if (!browser.tv) {
|
||||
var att = scalable ? "width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes" : "width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no";
|
||||
document.querySelector("meta[name=viewport]").setAttribute("content", att)
|
||||
document.querySelector("meta[name=viewport]").setAttribute("content", att);
|
||||
}
|
||||
},
|
||||
deviceIconUrl: function () {
|
||||
return browser.edgeUwp, browser.edgeUwp ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/windowsrt.png" : browser.opera || browser.operaTv ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/opera.png" : browser.orsay || browser.tizen ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/samsungtv.png" : browser.web0s ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/lgtv.png" : browser.ps4 ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/ps4.png" : browser.chromecast ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/chromecast.png" : browser.chrome ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/chrome.png" : browser.edge ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/edge.png" : browser.firefox ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/firefox.png" : browser.msie ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/internetexplorer.png" : browser.safari ? "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/safari.png" : "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/html5.png"
|
||||
if (browser.edgeUwp) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/windowsrt.png";
|
||||
}
|
||||
|
||||
if (browser.opera || browser.operaTv) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/opera.png";
|
||||
}
|
||||
|
||||
if (browser.orsay || browser.tizen) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/samsungtv.png";
|
||||
}
|
||||
|
||||
if (browser.web0s) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/lgtv.png";
|
||||
}
|
||||
|
||||
if (browser.ps4) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/ps4.png";
|
||||
}
|
||||
|
||||
if (browser.chromecast) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/chromecast.png";
|
||||
}
|
||||
|
||||
if (browser.chrome) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/chrome.png";
|
||||
}
|
||||
|
||||
if (browser.edge) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/edge.png";
|
||||
}
|
||||
|
||||
if (browser.firefox) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/firefox.png";
|
||||
}
|
||||
|
||||
if (browser.msie) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/internetexplorer.png";
|
||||
}
|
||||
|
||||
if (browser.safari) {
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/safari.png";
|
||||
}
|
||||
|
||||
return "https://github.com/MediaBrowser/Emby.Resources/raw/master/images/devices/html5.png";
|
||||
}
|
||||
};
|
||||
|
||||
var doc = self.document;
|
||||
doc && (void 0 !== doc.visibilityState ? (visibilityChange = "visibilitychange", visibilityState = "hidden") : void 0 !== doc.mozHidden ? (visibilityChange = "mozvisibilitychange", visibilityState = "mozVisibilityState") : void 0 !== doc.msHidden ? (visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState") : void 0 !== doc.webkitHidden && (visibilityChange = "webkitvisibilitychange", visibilityState = "webkitVisibilityState"));
|
||||
|
||||
if (doc) {
|
||||
if (void 0 !== doc.visibilityState) {
|
||||
visibilityChange = "visibilitychange";
|
||||
visibilityState = "hidden";
|
||||
} else {
|
||||
if (void 0 !== doc.mozHidden) {
|
||||
visibilityChange = "mozvisibilitychange";
|
||||
visibilityState = "mozVisibilityState";
|
||||
} else {
|
||||
if (void 0 !== doc.msHidden) {
|
||||
visibilityChange = "msvisibilitychange";
|
||||
visibilityState = "msVisibilityState";
|
||||
} else {
|
||||
if (void 0 !== doc.webkitHidden) {
|
||||
visibilityChange = "webkitvisibilitychange";
|
||||
visibilityState = "webkitVisibilityState";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isHidden = false;
|
||||
|
||||
if (doc) {
|
||||
doc.addEventListener(visibilityChange, function () {
|
||||
document[visibilityState] ? onAppHidden() : onAppVisible()
|
||||
if (document[visibilityState]) {
|
||||
onAppHidden();
|
||||
} else {
|
||||
onAppVisible();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (self.addEventListener) {
|
||||
self.addEventListener("focus", onAppVisible);
|
||||
self.addEventListener("blur", onAppHidden);
|
||||
}
|
||||
|
||||
return appHost;
|
||||
});
|
||||
|
3
src/components/backdrop/package.json
Normal file
3
src/components/backdrop/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "backdrop.js"
|
||||
}
|
@ -751,7 +751,7 @@ define(['browser'], function (browser) {
|
||||
Condition: 'Equals',
|
||||
Property: 'IsSecondaryAudio',
|
||||
Value: 'false',
|
||||
IsRequired: 'false'
|
||||
IsRequired: false
|
||||
});
|
||||
}
|
||||
|
||||
@ -780,7 +780,7 @@ define(['browser'], function (browser) {
|
||||
Condition: 'Equals',
|
||||
Property: 'IsSecondaryAudio',
|
||||
Value: 'false',
|
||||
IsRequired: 'false'
|
||||
IsRequired: false
|
||||
}
|
||||
]
|
||||
});
|
@ -1,31 +0,0 @@
|
||||
define(["itemHelper", "libraryMenu", "apphost"], function(itemHelper, libraryMenu, appHost) {
|
||||
"use strict";
|
||||
|
||||
function initSyncButtons(view) {
|
||||
var apiClient = window.ApiClient;
|
||||
apiClient && apiClient.getCurrentUserId() && apiClient.getCurrentUser().then(function(user) {
|
||||
for (var item = {
|
||||
SupportsSync: !0
|
||||
}, categorySyncButtons = view.querySelectorAll(".categorySyncButton"), i = 0, length = categorySyncButtons.length; i < length; i++) categorySyncButtons[i].addEventListener("click", onCategorySyncButtonClick), itemHelper.canSync(user, item) ? categorySyncButtons[i].classList.remove("hide") : categorySyncButtons[i].classList.add("hide")
|
||||
})
|
||||
}
|
||||
|
||||
function onCategorySyncButtonClick(e) {
|
||||
var button = this,
|
||||
category = button.getAttribute("data-category"),
|
||||
parentId = libraryMenu.getTopParentId();
|
||||
require(["syncDialog"], function(syncDialog) {
|
||||
syncDialog.showMenu({
|
||||
ParentId: parentId,
|
||||
Category: category,
|
||||
serverId: ApiClient.serverId(),
|
||||
mode: appHost.supports("sync") ? "download" : "sync"
|
||||
})
|
||||
})
|
||||
}
|
||||
return {
|
||||
init: function(view) {
|
||||
initSyncButtons(view)
|
||||
}
|
||||
}
|
||||
});
|
@ -187,8 +187,13 @@ define(['events'], function (events) {
|
||||
return apiClient.getEndpointInfo().then(function (endpoint) {
|
||||
if (endpoint.IsInNetwork) {
|
||||
return apiClient.getPublicSystemInfo().then(function (info) {
|
||||
addToCache(serverAddress, info.LocalAddress);
|
||||
return info.LocalAddress;
|
||||
var localAddress = info.LocalAddress
|
||||
if (!localAddress) {
|
||||
console.log("No valid local address returned, defaulting to external one")
|
||||
localAddress = serverAddress;
|
||||
}
|
||||
addToCache(serverAddress, localAddress);
|
||||
return localAddress;
|
||||
});
|
||||
} else {
|
||||
addToCache(serverAddress, serverAddress);
|
@ -220,6 +220,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
this.session = null;
|
||||
this.deviceState = DEVICE_STATE.IDLE;
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||
document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||
|
||||
//console.log('sessionUpdateListener: setting currentMediaSession to null');
|
||||
this.currentMediaSession = null;
|
||||
@ -258,6 +260,9 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
this.session.addMediaListener(this.sessionMediaListener.bind(this));
|
||||
this.session.addUpdateListener(this.sessionUpdateListener.bind(this));
|
||||
|
||||
document.addEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||
document.addEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||
|
||||
events.trigger(this, 'connect');
|
||||
|
||||
this.sendMessage({
|
||||
@ -266,6 +271,14 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
});
|
||||
};
|
||||
|
||||
function onVolumeUpKeyDown() {
|
||||
playbackManager.volumeUp();
|
||||
}
|
||||
|
||||
function onVolumeDownKeyDown() {
|
||||
playbackManager.volumeDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* session update listener
|
||||
*/
|
||||
@ -305,6 +318,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
//console.log(message);
|
||||
this.deviceState = DEVICE_STATE.IDLE;
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||
document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||
|
||||
//console.log('onStopAppSuccess: setting currentMediaSession to null');
|
||||
this.currentMediaSession = null;
|
||||
@ -574,8 +589,15 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
|
||||
events.trigger(instance, "playbackstop", [state]);
|
||||
|
||||
var state = instance.lastPlayerData.PlayState || {};
|
||||
var volume = state.VolumeLevel || 0.5;
|
||||
var mute = state.IsMuted || false;
|
||||
|
||||
// Reset this so the next query doesn't make it appear like content is playing.
|
||||
instance.lastPlayerData = {};
|
||||
instance.lastPlayerData.PlayState = {};
|
||||
instance.lastPlayerData.PlayState.VolumeLevel = volume;
|
||||
instance.lastPlayerData.PlayState.IsMuted = mute;
|
||||
});
|
||||
|
||||
events.on(instance._castPlayer, "playbackprogress", function (e, data) {
|
||||
@ -780,11 +802,16 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.volumeDown = function () {
|
||||
var vol = this._castPlayer.session.receiver.volume.level;
|
||||
if (vol == null)
|
||||
{
|
||||
vol = 0.5;
|
||||
}
|
||||
vol -= 0.05;
|
||||
vol = Math.max(vol, 0);
|
||||
|
||||
this._castPlayer.session.setReceiverVolumeLevel(vol);
|
||||
|
||||
this._castPlayer.sendMessage({
|
||||
options: {},
|
||||
command: 'VolumeDown'
|
||||
});
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.endSession = function () {
|
||||
@ -799,24 +826,24 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.volumeUp = function () {
|
||||
var vol = this._castPlayer.session.receiver.volume.level;
|
||||
if (vol == null)
|
||||
{
|
||||
vol = 0.5;
|
||||
}
|
||||
vol += 0.05;
|
||||
vol = Math.min(vol, 1);
|
||||
|
||||
this._castPlayer.sendMessage({
|
||||
options: {},
|
||||
command: 'VolumeUp'
|
||||
});
|
||||
this._castPlayer.session.setReceiverVolumeLevel(vol);
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.setVolume = function (vol) {
|
||||
|
||||
vol = Math.min(vol, 100);
|
||||
vol = Math.max(vol, 0);
|
||||
vol = vol / 100;
|
||||
|
||||
this._castPlayer.sendMessage({
|
||||
options: {
|
||||
volume: vol
|
||||
},
|
||||
command: 'SetVolume'
|
||||
});
|
||||
this._castPlayer.session.setReceiverVolumeLevel(vol);
|
||||
};
|
||||
|
||||
ChromecastPlayer.prototype.unpause = function () {
|
@ -1,4 +1,4 @@
|
||||
define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) {
|
||||
define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) {
|
||||
'use strict';
|
||||
|
||||
var currentServerId;
|
3
src/components/dialog/package.json
Normal file
3
src/components/dialog/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "dialog.js"
|
||||
}
|
3
src/components/dialogHelper/package.json
Normal file
3
src/components/dialogHelper/package.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "dialogHelper.js"
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-button', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-linkbutton'], function(loading, dialogHelper, dom) {
|
||||
define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-button'], function(loading, dialogHelper, dom) {
|
||||
'use strict';
|
||||
|
||||
function getSystemInfo() {
|
||||
@ -222,11 +222,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'emby-b
|
||||
var networkSharePath = this.querySelector("#txtNetworkPath");
|
||||
networkSharePath = networkSharePath ? networkSharePath.value : null;
|
||||
var path = this.querySelector("#txtDirectoryPickerPath").value;
|
||||
validatePath(path, options.validateWriteable, ApiClient).then(
|
||||
function() {
|
||||
options.callback(path, networkSharePath);
|
||||
}
|
||||
);
|
||||
validatePath(path, options.validateWriteable, ApiClient).then(options.callback(path, networkSharePath));
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
@ -1,4 +1,4 @@
|
||||
define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-linkbutton'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) {
|
||||
define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-button'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) {
|
||||
"use strict";
|
||||
|
||||
function fillThemes(select, isDashboard) {
|
||||
@ -225,32 +225,25 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
||||
|
||||
if (user.Id === apiClient.getCurrentUserId()) {
|
||||
|
||||
skinManager.setTheme(userSettingsInstance.theme());
|
||||
}
|
||||
|
||||
layoutManager.setLayout(context.querySelector('.selectLayout').value);
|
||||
|
||||
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
|
||||
}
|
||||
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(function (user) {
|
||||
|
||||
saveUser(context, user, userSettings, apiClient).then(function () {
|
||||
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
});
|
||||
}
|
||||
|
||||
events.trigger(instance, 'saved');
|
||||
|
||||
}, function () {
|
||||
loading.hide();
|
||||
});
|
||||
@ -258,14 +251,12 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
var self = this;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userId = self.options.userId;
|
||||
var userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
|
||||
var enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
@ -278,30 +269,22 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
}
|
||||
|
||||
function embed(options, self) {
|
||||
|
||||
require(['text!./displaysettings.template.html'], function (template) {
|
||||
|
||||
options.element.innerHTML = globalize.translateDocument(template, 'core');
|
||||
|
||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||
|
||||
if (options.enableSaveButton) {
|
||||
options.element.querySelector('.btnSave').classList.remove('hide');
|
||||
}
|
||||
|
||||
self.loadData(options.autoFocus);
|
||||
});
|
||||
}
|
||||
|
||||
function DisplaySettings(options) {
|
||||
|
||||
this.options = options;
|
||||
|
||||
embed(options, this);
|
||||
}
|
||||
|
||||
DisplaySettings.prototype.loadData = function (autoFocus) {
|
||||
|
||||
var self = this;
|
||||
var context = self.options.element;
|
||||
|
||||
@ -312,13 +295,9 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
var userSettings = self.options.userSettings;
|
||||
|
||||
return apiClient.getUser(userId).then(function (user) {
|
||||
|
||||
return userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
|
||||
if (autoFocus) {
|
||||
focusManager.autoFocus(context);
|
||||
}
|
||||
@ -331,7 +310,6 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
};
|
||||
|
||||
DisplaySettings.prototype.destroy = function () {
|
||||
|
||||
this.options = null;
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user