Compare commits
21 Commits
release-10
...
release-10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc66fadb0e | ||
|
|
298d8d7929 | ||
|
|
bdf8553728 | ||
|
|
8ac155fb7a | ||
|
|
54dee197fd | ||
|
|
7a3eb3ffad | ||
|
|
15b987e0de | ||
|
|
54b05ab27d | ||
|
|
e1308f01b6 | ||
|
|
c596c19bfd | ||
|
|
087d06debf | ||
|
|
0b4402b642 | ||
|
|
b36369b562 | ||
|
|
78a2ba73e7 | ||
|
|
1be5e20363 | ||
|
|
9a130f5869 | ||
|
|
d6cec24d9e | ||
|
|
2044efc0c3 | ||
|
|
e12a8bc39d | ||
|
|
a885964e46 | ||
|
|
efdc07e032 |
@@ -20,21 +20,24 @@ jobs:
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node'
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '10.x'
|
||||
|
||||
- script: 'yarn install'
|
||||
displayName: 'Install Dependencies'
|
||||
- script: |
|
||||
yarn install
|
||||
displayName: 'Install dependencies'
|
||||
|
||||
- script: 'test -d dist'
|
||||
displayName: 'Check Build'
|
||||
- script: |
|
||||
test -d dist
|
||||
displayName: 'Check dist directory'
|
||||
|
||||
- script: 'yarn pack --filename jellyfin-web.tgz'
|
||||
displayName: 'Bundle Release'
|
||||
- script: |
|
||||
yarn pack --filename jellyfin-web.tgz
|
||||
displayName: 'Build package'
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish Release'
|
||||
displayName: 'Publish package'
|
||||
condition: succeeded()
|
||||
inputs:
|
||||
targetPath: '$(Build.SourcesDirectory)/jellyfin-web.tgz'
|
||||
@@ -48,16 +51,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node'
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '10.x'
|
||||
|
||||
- script: 'yarn install'
|
||||
displayName: 'Install Dependencies'
|
||||
|
||||
- script: 'yarn run lint'
|
||||
displayName: 'Run ESLint'
|
||||
- script: |
|
||||
yarn install
|
||||
displayName: 'Install dependencies'
|
||||
|
||||
- script: |
|
||||
yarn run stylelint
|
||||
displayName: 'Run stylelint'
|
||||
yarn run lint
|
||||
displayName: 'Run ESLint'
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
libraries/
|
||||
@@ -1,71 +1,4 @@
|
||||
env:
|
||||
es6: false
|
||||
es6: true
|
||||
browser: true
|
||||
amd: true
|
||||
|
||||
globals:
|
||||
# New browser globals
|
||||
DataView: readonly
|
||||
MediaMetadata: readonly
|
||||
Promise: readonly
|
||||
# Deprecated browser globals
|
||||
DocumentTouch: readonly
|
||||
# Tizen globals
|
||||
tizen: readonly
|
||||
webapis: readonly
|
||||
# WebOS globals
|
||||
webOS: readonly
|
||||
# Dependency globals
|
||||
$: readonly
|
||||
jQuery: readonly
|
||||
queryString: readonly
|
||||
requirejs: readonly
|
||||
# Jellyfin globals
|
||||
ApiClient: writable
|
||||
AppInfo: writable
|
||||
chrome: writable
|
||||
ConnectionManager: writable
|
||||
DlnaProfilePage: writable
|
||||
Dashboard: writable
|
||||
DashboardPage: writable
|
||||
Emby: readonly
|
||||
Events: writable
|
||||
getParameterByName: writable
|
||||
getWindowLocationSearch: writable
|
||||
Globalize: writable
|
||||
Hls: writable
|
||||
humaneDate: writable
|
||||
humaneElapsed: writable
|
||||
LibraryMenu: writable
|
||||
LinkParser: writable
|
||||
LiveTvHelpers: writable
|
||||
MetadataEditor: writable
|
||||
pageClassOn: writable
|
||||
pageIdOn: writable
|
||||
PlaylistViewer: writable
|
||||
UserParentalControlPage: writable
|
||||
Windows: readonly
|
||||
|
||||
extends:
|
||||
- eslint:recommended
|
||||
|
||||
rules:
|
||||
block-spacing: ["error"]
|
||||
brace-style: ["error"]
|
||||
comma-dangle: ["error", "never"]
|
||||
comma-spacing: ["error"]
|
||||
eol-last: ["error"]
|
||||
indent: ["error", 4, { "SwitchCase": 1 }]
|
||||
keyword-spacing: ["error"]
|
||||
max-statements-per-line: ["error"]
|
||||
no-floating-decimal: ["error"]
|
||||
no-multi-spaces: ["error"]
|
||||
no-multiple-empty-lines: ["error", { "max": 1 }]
|
||||
no-trailing-spaces: ["error"]
|
||||
one-var: ["error", "never"]
|
||||
semi: ["warn"]
|
||||
space-before-blocks: ["error"]
|
||||
# TODO: Fix warnings and remove these rules
|
||||
no-redeclare: ["warn"]
|
||||
no-unused-vars: ["warn"]
|
||||
no-useless-escape: ["warn"]
|
||||
|
||||
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@@ -8,7 +8,6 @@ exemptLabels:
|
||||
- future
|
||||
- feature
|
||||
- enhancement
|
||||
- confirmed
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -81,9 +81,6 @@ build/Release
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Dependency lockfile
|
||||
package-lock.json
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
@@ -575,4 +572,4 @@ healthchecksdb
|
||||
# End of https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode
|
||||
|
||||
# dist for webpack output
|
||||
dist
|
||||
dist
|
||||
143
.stylelintrc
143
.stylelintrc
@@ -1,143 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"stylelint-no-browser-hacks/lib",
|
||||
],
|
||||
"rules": {
|
||||
"at-rule-empty-line-before": [ "always", {
|
||||
except: [
|
||||
"blockless-after-same-name-blockless",
|
||||
"first-nested",
|
||||
],
|
||||
ignore: ["after-comment"],
|
||||
} ],
|
||||
"at-rule-name-case": "lower",
|
||||
"at-rule-name-space-after": "always-single-line",
|
||||
"at-rule-no-unknown": true,
|
||||
"at-rule-semicolon-newline-after": "always",
|
||||
"block-closing-brace-empty-line-before": "never",
|
||||
"block-closing-brace-newline-after": "always",
|
||||
"block-closing-brace-newline-before": "always-multi-line",
|
||||
"block-closing-brace-space-before": "always-single-line",
|
||||
"block-no-empty": true,
|
||||
"block-opening-brace-newline-after": "always-multi-line",
|
||||
"block-opening-brace-space-after": "always-single-line",
|
||||
"block-opening-brace-space-before": "always",
|
||||
"color-hex-case": "lower",
|
||||
"color-hex-length": "short",
|
||||
"color-no-invalid-hex": true,
|
||||
"comment-empty-line-before": [ "always", {
|
||||
except: ["first-nested"],
|
||||
ignore: ["stylelint-commands"],
|
||||
} ],
|
||||
"comment-no-empty": true,
|
||||
"comment-whitespace-inside": "always",
|
||||
"custom-property-empty-line-before": [ "always", {
|
||||
except: [
|
||||
"after-custom-property",
|
||||
"first-nested",
|
||||
],
|
||||
ignore: [
|
||||
"after-comment",
|
||||
"inside-single-line-block",
|
||||
],
|
||||
} ],
|
||||
"declaration-bang-space-after": "never",
|
||||
"declaration-bang-space-before": "always",
|
||||
"declaration-block-no-duplicate-properties": [
|
||||
true,
|
||||
{
|
||||
ignore: ["consecutive-duplicates-with-different-values"]
|
||||
}
|
||||
],
|
||||
"declaration-block-no-shorthand-property-overrides": true,
|
||||
"declaration-block-semicolon-newline-after": "always-multi-line",
|
||||
"declaration-block-semicolon-space-after": "always-single-line",
|
||||
"declaration-block-semicolon-space-before": "never",
|
||||
"declaration-block-single-line-max-declarations": 1,
|
||||
"declaration-block-trailing-semicolon": "always",
|
||||
"declaration-colon-newline-after": "always-multi-line",
|
||||
"declaration-colon-space-after": "always-single-line",
|
||||
"declaration-colon-space-before": "never",
|
||||
"font-family-no-duplicate-names": true,
|
||||
"function-calc-no-invalid": true,
|
||||
"function-calc-no-unspaced-operator": true,
|
||||
"function-comma-newline-after": "always-multi-line",
|
||||
"function-comma-space-after": "always-single-line",
|
||||
"function-comma-space-before": "never",
|
||||
"function-linear-gradient-no-nonstandard-direction": true,
|
||||
"function-max-empty-lines": 0,
|
||||
"function-name-case": "lower",
|
||||
"function-parentheses-newline-inside": "always-multi-line",
|
||||
"function-parentheses-space-inside": "never-single-line",
|
||||
"function-whitespace-after": "always",
|
||||
"indentation": 4,
|
||||
"keyframe-declaration-no-important": true,
|
||||
"length-zero-no-unit": true,
|
||||
"max-empty-lines": 1,
|
||||
"media-feature-colon-space-after": "always",
|
||||
"media-feature-colon-space-before": "never",
|
||||
"media-feature-name-case": "lower",
|
||||
"media-feature-name-no-unknown": true,
|
||||
"media-feature-parentheses-space-inside": "never",
|
||||
"media-feature-range-operator-space-after": "always",
|
||||
"media-feature-range-operator-space-before": "always",
|
||||
"media-query-list-comma-newline-after": "always-multi-line",
|
||||
"media-query-list-comma-space-after": "always-single-line",
|
||||
"media-query-list-comma-space-before": "never",
|
||||
"no-descending-specificity": true,
|
||||
"no-duplicate-at-import-rules": true,
|
||||
"no-duplicate-selectors": true,
|
||||
"no-empty-source": true,
|
||||
"no-eol-whitespace": true,
|
||||
"no-extra-semicolons": true,
|
||||
"no-invalid-double-slash-comments": true,
|
||||
"no-missing-end-of-source-newline": true,
|
||||
"number-leading-zero": "always",
|
||||
"number-no-trailing-zeros": true,
|
||||
"plugin/no-browser-hacks": true,
|
||||
"property-case": "lower",
|
||||
"property-no-unknown": [
|
||||
true,
|
||||
{
|
||||
"ignoreProperties": [
|
||||
"user-drag"
|
||||
]
|
||||
}
|
||||
],
|
||||
"rule-empty-line-before": [ "always-multi-line", {
|
||||
except: ["first-nested"],
|
||||
ignore: ["after-comment"],
|
||||
} ],
|
||||
"selector-attribute-brackets-space-inside": "never",
|
||||
"selector-attribute-operator-space-after": "never",
|
||||
"selector-attribute-operator-space-before": "never",
|
||||
"selector-combinator-space-after": "always",
|
||||
"selector-combinator-space-before": "always",
|
||||
"selector-descendant-combinator-no-non-space": true,
|
||||
"selector-list-comma-newline-after": "always",
|
||||
"selector-list-comma-space-before": "never",
|
||||
"selector-max-empty-lines": 0,
|
||||
"selector-pseudo-class-case": "lower",
|
||||
"selector-pseudo-class-no-unknown": true,
|
||||
"selector-pseudo-class-parentheses-space-inside": "never",
|
||||
"selector-pseudo-element-case": "lower",
|
||||
"selector-pseudo-element-colon-notation": "double",
|
||||
"selector-pseudo-element-no-unknown": [
|
||||
true,
|
||||
{
|
||||
"ignorePseudoElements": [
|
||||
"cue"
|
||||
]
|
||||
}
|
||||
],
|
||||
"selector-type-case": "lower",
|
||||
"selector-type-no-unknown": true,
|
||||
"string-no-newline": true,
|
||||
"unit-case": "lower",
|
||||
"unit-no-unknown": true,
|
||||
"value-list-comma-newline-after": "always-multi-line",
|
||||
"value-list-comma-space-after": "always-single-line",
|
||||
"value-list-comma-space-before": "never",
|
||||
"value-list-max-empty-lines": 0,
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,6 @@
|
||||
- [bilde2910](https://github.com/bilde2910)
|
||||
- [Daniel Hartung](https://github.com/dhartung)
|
||||
- [Ryan Hartzell](https://github.com/ryan-hartzell)
|
||||
- [Thibault Nocchi](https://github.com/ThibaultNocchi)
|
||||
- [MrTimscampi](https://github.com/MrTimscampi)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
||||
61
README.md
61
README.md
@@ -1,64 +1,15 @@
|
||||
<h1 align="center">Jellyfin Web</h1>
|
||||
<h3 align="center">Part of the <a href="https://jellyfin.org">Jellyfin Project</a></h3>
|
||||
<h3 align="center">The Free Software Media System</h3>
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<img alt="Logo Banner" src="https://raw.githubusercontent.com/jellyfin/jellyfin-ux/master/branding/SVG/banner-logo-solid.svg?sanitize=true"/>
|
||||
<br/>
|
||||
<br/>
|
||||
<a href="https://github.com/jellyfin/jellyfin-web">
|
||||
<img alt="GPL 2.0 License" src="https://img.shields.io/github/license/jellyfin/jellyfin-web.svg"/>
|
||||
</a>
|
||||
<a href="https://github.com/jellyfin/jellyfin-web/releases">
|
||||
<img alt="Current Release" src="https://img.shields.io/github/release/jellyfin/jellyfin-web.svg"/>
|
||||
</a>
|
||||
<a href="https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/?utm_source=widget">
|
||||
<img src="https://translate.jellyfin.org/widgets/jellyfin/-/jellyfin-web/svg-badge.svg" alt="Translation Status"/>
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://opencollective.com/jellyfin">
|
||||
<img alt="Donate" src="https://img.shields.io/opencollective/all/jellyfin.svg?label=backers"/>
|
||||
</a>
|
||||
<a href="https://features.jellyfin.org">
|
||||
<img alt="Feature Requests" src="https://img.shields.io/badge/fider-vote%20on%20features-success.svg"/>
|
||||
</a>
|
||||
<a href="https://forum.jellyfin.org">
|
||||
<img alt="Discuss on our Forum" src="https://img.shields.io/discourse/https/forum.jellyfin.org/users.svg"/>
|
||||
</a>
|
||||
<a href="https://matrix.to/#/+jellyfin:matrix.org">
|
||||
<img alt="Chat on Matrix" src="https://img.shields.io/matrix/jellyfin:matrix.org.svg?logo=matrix"/>
|
||||
</a>
|
||||
<a href="https://www.reddit.com/r/jellyfin">
|
||||
<img alt="Join our Subreddit" src="https://img.shields.io/badge/reddit-r%2Fjellyfin-%23FF5700.svg"/>
|
||||
</a>
|
||||
<br/><br/>
|
||||
<a href="https://github.com/jellyfin/jellyfin-web"><img alt="GPL 2.0 License" src="https://img.shields.io/github/license/jellyfin/jellyfin-web.svg"/></a>
|
||||
<a href="https://github.com/jellyfin/jellyfin-web/releases"><img alt="Current Release" src="https://img.shields.io/github/release/jellyfin/jellyfin-web.svg"/></a>
|
||||
</p>
|
||||
|
||||
Jellyfin Web is the frontend used for most of the clients available for end users, such as desktop browsers, Android, and iOS. We welcome all contributions and pull requests! If you have a larger feature in mind please open an issue so we can discuss the implementation before you start. Translations can be improved very easily from our <a href="https://translate.jellyfin.org/projects/jellyfin/jellyfin-web">Weblate</a> instance. Look through the following graphic to see if your native language could use some work!
|
||||
---
|
||||
|
||||
<a href="https://translate.jellyfin.org/engage/jellyfin/?utm_source=widget">
|
||||
<img src="https://translate.jellyfin.org/widgets/jellyfin/-/jellyfin-web/multi-auto.svg" alt="Detailed Translation Status"/>
|
||||
</a>
|
||||
|
||||
## Build Process
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Yarn
|
||||
|
||||
### Getting Started
|
||||
|
||||
1. Clone or download this repository.
|
||||
```sh
|
||||
git clone https://github.com/jellyfin/jellyfin-web.git
|
||||
cd jellyfin-web
|
||||
```
|
||||
2. Install build dependencies in the project directory.
|
||||
```sh
|
||||
yarn install
|
||||
```
|
||||
|
||||
3. Run the web client with webpack for local development.
|
||||
```sh
|
||||
yarn serve
|
||||
```
|
||||
Jellyfin is a free software media system that puts you in control of managing and streaming your media.
|
||||
|
||||
57
package.json
57
package.json
@@ -5,62 +5,31 @@
|
||||
"repository": "https://github.com/jellyfin/jellyfin-web",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"devDependencies": {
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "^3.4.2",
|
||||
"eslint": "^6.8.0",
|
||||
"file-loader": "^5.0.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"style-loader": "^1.1.3",
|
||||
"stylelint": "^13.1.0",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-no-browser-hacks": "^1.2.1",
|
||||
"stylelint-order": "^4.0.0",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-concat-plugin": "^3.0.0",
|
||||
"webpack-dev-server": "^3.10.3",
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"css-loader": "^2.1.0",
|
||||
"eslint": "^5.16.0",
|
||||
"file-loader": "^3.0.1",
|
||||
"style-loader": "^0.23.1",
|
||||
"webpack": "^4.41.0",
|
||||
"webpack-cli": "^3.3.9",
|
||||
"webpack-dev-server": "^3.8.1",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"alameda": "^1.4.0",
|
||||
"document-register-element": "^1.14.3",
|
||||
"flv.js": "^1.5.0",
|
||||
"hls.js": "^0.13.1",
|
||||
"howler": "^2.1.3",
|
||||
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
|
||||
"hls.js": "^0.12.4",
|
||||
"howler": "^2.1.2",
|
||||
"jquery": "^3.4.1",
|
||||
"jstree": "^3.3.7",
|
||||
"libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-cordova",
|
||||
"libjass": "^0.11.0",
|
||||
"material-design-icons-iconfont": "^5.0.1",
|
||||
"native-promise-only": "^0.8.0-a",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"shaka-player": "^2.5.9",
|
||||
"sortablejs": "^1.10.2",
|
||||
"swiper": "^5.3.1",
|
||||
"webcomponents.js": "^0.7.24",
|
||||
"whatwg-fetch": "^3.0.0"
|
||||
"shaka-player": "^2.5.5",
|
||||
"sortablejs": "^1.9.0",
|
||||
"swiper": "^3.4.2"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 2 Firefox versions",
|
||||
"last 2 Chrome versions",
|
||||
"last 2 ChromeAndroid versions",
|
||||
"last 2 Safari versions",
|
||||
"last 2 iOS versions",
|
||||
"last 2 Edge versions",
|
||||
"Chrome 38",
|
||||
"Chrome 47",
|
||||
"Chrome 53",
|
||||
"Chrome 56",
|
||||
"Chrome 63",
|
||||
"Firefox ESR"
|
||||
],
|
||||
"scripts": {
|
||||
"serve": "webpack-dev-server --config webpack.dev.js --open",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
"lint": "eslint \"src\"",
|
||||
"stylelint": "stylelint \"src/**/*.css\"",
|
||||
"prepare": "webpack --config webpack.prod.js"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# load every key in the source language
|
||||
# check the keys in all translations
|
||||
# remove keys that only exist in translations
|
||||
|
||||
cwd = os.getcwd()
|
||||
langdir = cwd + '/../src/strings'
|
||||
langlst = os.listdir(langdir)
|
||||
|
||||
langlst.remove('en-us.json')
|
||||
print(langlst)
|
||||
input('press enter to continue')
|
||||
|
||||
keysus = []
|
||||
with open(langdir + '/' + 'en-us.json') as en:
|
||||
langus = json.load(en)
|
||||
for key in langus:
|
||||
keysus.append(key)
|
||||
|
||||
for lang in langlst:
|
||||
with open(langdir + '/' + lang, 'r') as f:
|
||||
inde = 2
|
||||
if '\n \"' in f.read():
|
||||
inde = 4
|
||||
f.close()
|
||||
with open(langdir + '/' + lang, 'r+') as f:
|
||||
langjson = json.load(f)
|
||||
langjnew = {}
|
||||
for key in langjson:
|
||||
if key in keysus:
|
||||
langjnew[key] = langjson[key]
|
||||
f.seek(0)
|
||||
f.write(json.dumps(langjnew, indent=inde, sort_keys=False, ensure_ascii=False))
|
||||
f.write('\n')
|
||||
f.truncate()
|
||||
f.close()
|
||||
|
||||
print('DONE')
|
||||
@@ -1,40 +0,0 @@
|
||||
import os
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
# load all keys in the source language
|
||||
# check entire codebase for usages
|
||||
# print unused keys to a text file
|
||||
# TODO: dynamic string usages cause false positives
|
||||
|
||||
cwd = os.getcwd()
|
||||
langdir = cwd + '/../src/strings'
|
||||
langlst = []
|
||||
langlst.append('en-us.json')
|
||||
|
||||
# unused keys
|
||||
dep = []
|
||||
|
||||
def grep(key):
|
||||
command = 'grep -r -E "(\(\\\"|\(\'|\{)%s(\\\"|\'|\})" --include=\*.{js,html} --exclude-dir=../src/strings ../src' % key
|
||||
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
output = p.stdout.readlines()
|
||||
if output:
|
||||
print('DONE: ' + key)
|
||||
return True
|
||||
print('UNUSED: ' + key)
|
||||
dep.append(key)
|
||||
return False
|
||||
|
||||
for lang in langlst:
|
||||
with open(langdir + '/' + lang) as f:
|
||||
langjson = json.load(f)
|
||||
for key in langjson:
|
||||
grep(key)
|
||||
|
||||
print(dep)
|
||||
print('LENGTH: ' + str(len(dep)))
|
||||
with open('scout.txt', 'w') as out:
|
||||
for item in dep:
|
||||
out.write(item + '\n')
|
||||
out.close()
|
||||
@@ -1,34 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
|
||||
# load text file containing unused keys
|
||||
# remove the keys from all string files
|
||||
|
||||
cwd = os.getcwd()
|
||||
langdir = cwd + '/../src/strings'
|
||||
langlst = os.listdir(langdir)
|
||||
|
||||
keys = []
|
||||
|
||||
with open('scout.txt', 'r') as f:
|
||||
for line in f:
|
||||
keys.append(line.strip('\n'))
|
||||
|
||||
for lang in langlst:
|
||||
with open(langdir + '/' + lang, 'r') as f:
|
||||
inde = 2
|
||||
if '\n \"' in f.read():
|
||||
inde = 4
|
||||
f.close()
|
||||
with open(langdir + '/' + lang, 'r+') as f:
|
||||
langjson = json.load(f)
|
||||
for key in keys:
|
||||
langjson.pop(key, None)
|
||||
f.seek(0)
|
||||
f.write(json.dumps(langjson, indent=inde, sort_keys=False, ensure_ascii=False))
|
||||
f.write('\n')
|
||||
f.truncate()
|
||||
f.close()
|
||||
|
||||
print('DONE')
|
||||
@@ -1,7 +1,10 @@
|
||||
<div id="addPluginPage" data-role="page" class="page type-interior pluginConfigurationPage" data-backbutton="true">
|
||||
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
|
||||
<div class="readOnlyContent">
|
||||
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h1 class="sectionTitle pluginName"></h1>
|
||||
@@ -10,7 +13,9 @@
|
||||
|
||||
<p id="tagline" style="font-style: italic;"></p>
|
||||
<p id="pPreviewImage"></p>
|
||||
|
||||
<p id="overview"></p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="verticalSection">
|
||||
@@ -22,12 +27,12 @@
|
||||
<select id="selectVersion" name="selectVersion" is="emby-select" label="${LabelSelectVersionToInstall}"></select>
|
||||
</div>
|
||||
|
||||
<div id="btnInstallDiv" class="hide">
|
||||
<p id="btnInstallDiv" class="hide">
|
||||
<button is="emby-button" type="submit" id="btnInstall" class="raised button-submit block">
|
||||
<span>${Install}</span>
|
||||
</button>
|
||||
<div class="fieldDescription">${ServerRestartNeededAfterPluginInstall}</div>
|
||||
</div>
|
||||
</p>
|
||||
<p id="nonServerMsg"></p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
<div class="detailSectionHeader">
|
||||
<h2 style="margin:.6em 0;vertical-align:middle;display:inline-block;">${HeaderApiKeys}</h2>
|
||||
<h2 style="margin:.6em 0;vertical-align:middle;display:inline-block;">
|
||||
${HeaderApiKeys}
|
||||
</h2>
|
||||
<button is="emby-button" type="button" class="fab btnNewKey submit" style="margin-left:1em;" title="${ButtonAdd}">
|
||||
<i class="material-icons">add</i>
|
||||
<i class="md-icon">add</i>
|
||||
</button>
|
||||
</div>
|
||||
<p>${HeaderApiKeysHelp}</p>
|
||||
@@ -22,4 +24,4 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,37 +0,0 @@
|
||||
html {
|
||||
font-family: "Noto Sans", sans-serif;
|
||||
font-size: 93%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-family: "Noto Sans", sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 400;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 400;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: 400;
|
||||
font-size: 1.17em;
|
||||
}
|
||||
|
||||
.layout-tv {
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
.layout-mobile {
|
||||
font-size: 90%;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
html {
|
||||
font-size: 82% !important;
|
||||
}
|
||||
|
||||
.formDialogFooter {
|
||||
position: static !important;
|
||||
margin: 0 -1em !important;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
.guideVerticalScroller {
|
||||
padding-bottom: 15em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 62.5em) {
|
||||
#guideTab {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 19H0a13.6 13.6 0 0 1 2.21-6.07A11.2 11.2 0 0 1 5.87 9.4l.41-.23-2.02-3.41a.51.51 0 0 1 .17-.7.5.5 0 0 1 .69.18l2.08 3.5a12.62 12.62 0 0 1 4.84-.9 12.2 12.2 0 0 1 4.75.9l2.07-3.5a.5.5 0 0 1 .7-.17.51.51 0 0 1 .16.7L17.7 9.19l.5.28a11.38 11.38 0 0 1 3.63 3.62A14.48 14.48 0 0 1 24 19zm-7.5-4.48a1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1 1 1 0 0 0-1 1zm-11 0a1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1 1 1 0 0 0-1 1z" fill="#fff"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 563 B |
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-36.173 -93.796)">
|
||||
<g transform="matrix(.08 0 0 .08 40.527 88.485)">
|
||||
<path d="m53.295 119.35v-39.688h79.375v79.375h-79.375z" fill="#fcfdfd" stroke-width=".26458"/>
|
||||
</g>
|
||||
<g transform="matrix(1.3761 0 0 1.3825 -26.63 -38.456)" fill="#fff">
|
||||
<path transform="matrix(.08 0 0 .08 40.527 88.485)" d="m86.822 141.89c-4.738-4.7596-5.2168-5.3235-5.2168-6.1442 0-0.82158 0.47505-1.3787 5.2329-6.1365 4.7552-4.7552 5.3153-5.2329 6.1353-5.2329 0.81617 0 1.3676 0.46161 5.7678 4.8286 4.8692 4.8324 5.6182 5.7452 5.6182 6.8466 0 0.41218-1.5697 2.1641-5.2274 5.834-4.8206 4.8367-5.3 5.2449-6.1603 5.2449-0.86046 0-1.3378-0.40681-6.1497-5.2406zm22.168-12.455c-0.43656-0.27248-2.9071-2.6371-5.4901-5.2547-4.1957-4.2519-4.6964-4.8534-4.6964-5.6418 0-0.7938 0.52954-1.414 5.2644-6.1655 4.6582-4.6746 5.362-5.2829 6.1127-5.2829 0.75071 0 1.4546 0.60829 6.1127 5.2829 4.7729 4.7898 5.2644 5.3668 5.2644 6.1818 0 0.81542-0.48628 1.3851-5.2394 6.1382-5.6104 5.6104-5.7707 5.7142-7.3283 4.742zm-40.16-5.2731c-3.5636-3.5816-4.9518-5.1483-4.9518-5.5886 0-0.75745 9.3384-10.601 10.057-10.601 0.2584 0 0.54208 0.18833 0.63041 0.41851s0.1606 4.7624 0.1606 10.072c0 9.1098-0.10948 10.677-0.74606 10.677-0.10905 0-2.4266-2.2396-5.1501-4.9768zm13.2-1.5272c-0.08833-0.23018-0.1606-5.3558-0.1606-11.39 0-8.9734 0.06852-11.102 0.37621-11.686 0.20691-0.39296 2.447-2.7683 4.9781-5.2785 4.3226-4.2871 4.6624-4.5641 5.5987-4.5641 0.94583 0 1.2591 0.26717 6.1277 5.2255 4.658 4.7439 5.1315 5.3102 5.1376 6.1439 6e-3 0.85888-0.67407 1.6-10.506 11.443-5.782 5.7887-10.71 10.525-10.952 10.525s-0.51144-0.18833-0.59977-0.41852z" fill="#fff" stroke-width=".26458"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg id="svg3390" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="141.25" viewBox="0 0 138.75 141.25" width="138.75" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata id="metadata3396">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g id="layer1" fill="#f93208">
|
||||
<path id="path3412" d="m20.154 40.829c-28.149 27.622-13.657 61.011-5.734 71.931 35.254 41.954 92.792 25.339 111.89-5.9071 4.7608-8.2027 22.554-53.467-23.976-78.009z"/>
|
||||
<path id="path3471" d="m39.613 39.265 4.7778-8.8607 28.406-5.0384 11.119 9.2082z"/>
|
||||
</g>
|
||||
<g id="layer2">
|
||||
<path id="path3437" d="m39.436 8.5696 8.9682-5.2826 6.7569 15.479c3.7925-6.3226 13.79-16.316 24.939-4.6684-4.7281 1.2636-7.5161 3.8553-7.7397 8.4768 15.145-4.1697 31.343 3.2127 33.539 9.0911-10.951-4.314-27.695 10.377-41.771 2.334 0.009 15.045-12.617 16.636-19.902 17.076 2.077-4.996 5.591-9.994 1.474-14.987-7.618 8.171-13.874 10.668-33.17 4.668 4.876-1.679 14.843-11.39 24.448-11.425-6.775-2.467-12.29-2.087-17.814-1.475 2.917-3.961 12.149-15.197 28.625-8.476z" fill="#02902e"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="145" height="140"><path fill="#0fc755" d="M47.4 35.342c-13.607-7.935-12.32-25.203 2.097-31.88 26.124-6.531 29.117 13.78 22.652 30.412-6.542 24.11 18.095 23.662 19.925 10.067 3.605-18.412 19.394-26.695 31.67-16.359 12.598 12.135 7.074 36.581-17.827 34.187-16.03-1.545-19.552 19.585.839 21.183 32.228 1.915 42.49 22.167 31.04 35.865-15.993 15.15-37.691-4.439-45.512-19.505-6.8-9.307-17.321.11-13.423 6.502 12.983 19.465 2.923 31.229-10.906 30.62-13.37-.85-20.96-9.06-13.214-29.15 3.897-12.481-8.595-15.386-16.57-5.45-11.707 19.61-28.865 13.68-33.976 4.19-3.243-7.621-2.921-25.846 24.119-23.696 16.688 4.137 11.776-12.561-.63-13.633-9.245-.443-30.501-7.304-22.86-24.54 7.34-11.056 24.958-11.768 33.348 6.293 3.037 4.232 8.361 11.042 18.037 5.033 3.51-5.197 1.21-13.9-8.809-20.135z"/></svg>
|
||||
|
Before Width: | Height: | Size: 833 B |
@@ -5,4 +5,4 @@
|
||||
<div id="pluginTiles" style="text-align:left;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
419
src/bower_components/alameda/alameda.js
vendored
Normal file
419
src/bower_components/alameda/alameda.js
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
var requirejs, require, define;
|
||||
! function(global, Promise, undef) {
|
||||
function commentReplace(match, singlePrefix) {
|
||||
return singlePrefix || ""
|
||||
}
|
||||
|
||||
function hasProp(obj, prop) {
|
||||
return hasOwn.call(obj, prop)
|
||||
}
|
||||
|
||||
function getOwn(obj, prop) {
|
||||
return obj && hasProp(obj, prop) && obj[prop]
|
||||
}
|
||||
|
||||
function obj() {
|
||||
return Object.create(null)
|
||||
}
|
||||
|
||||
function eachProp(obj, func) {
|
||||
var prop;
|
||||
for (prop in obj)
|
||||
if (hasProp(obj, prop) && func(obj[prop], prop)) break
|
||||
}
|
||||
|
||||
function mixin(target, source, force, deepStringMixin) {
|
||||
return source && eachProp(source, function(value, prop) {
|
||||
!force && hasProp(target, prop) || (!deepStringMixin || "object" != typeof value || !value || Array.isArray(value) || "function" == typeof value || value instanceof RegExp ? target[prop] = value : (target[prop] || (target[prop] = {}), mixin(target[prop], value, force, deepStringMixin)))
|
||||
}), target
|
||||
}
|
||||
|
||||
function getGlobal(value) {
|
||||
if (!value) return value;
|
||||
var g = global;
|
||||
return value.split(".").forEach(function(part) {
|
||||
g = g[part]
|
||||
}), g
|
||||
}
|
||||
|
||||
function newContext(contextName) {
|
||||
function trimDots(ary) {
|
||||
var i, part, length = ary.length;
|
||||
for (i = 0; i < length; i++)
|
||||
if ("." === (part = ary[i])) ary.splice(i, 1), i -= 1;
|
||||
else if (".." === part) {
|
||||
if (0 === i || 1 === i && ".." === ary[2] || ".." === ary[i - 1]) continue;
|
||||
i > 0 && (ary.splice(i - 1, 2), i -= 2)
|
||||
}
|
||||
}
|
||||
|
||||
function normalize(name, baseName, applyMap) {
|
||||
var mapValue, nameParts, i, j, nameSegment, lastIndex, foundMap, foundI, foundStarMap, starI, baseParts = baseName && baseName.split("/"),
|
||||
normalizedBaseParts = baseParts,
|
||||
map = config.map,
|
||||
starMap = map && map["*"];
|
||||
if (name && (name = name.split("/"), lastIndex = name.length - 1, config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex]) && (name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, "")), "." === name[0].charAt(0) && baseParts && (normalizedBaseParts = baseParts.slice(0, baseParts.length - 1), name = normalizedBaseParts.concat(name)), trimDots(name), name = name.join("/")), applyMap && map && (baseParts || starMap)) {
|
||||
nameParts = name.split("/");
|
||||
outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
|
||||
if (nameSegment = nameParts.slice(0, i).join("/"), baseParts)
|
||||
for (j = baseParts.length; j > 0; j -= 1)
|
||||
if ((mapValue = getOwn(map, baseParts.slice(0, j).join("/"))) && (mapValue = getOwn(mapValue, nameSegment))) {
|
||||
foundMap = mapValue, foundI = i;
|
||||
break outerLoop
|
||||
}! foundStarMap && starMap && getOwn(starMap, nameSegment) && (foundStarMap = getOwn(starMap, nameSegment), starI = i)
|
||||
}!foundMap && foundStarMap && (foundMap = foundStarMap, foundI = starI), foundMap && (nameParts.splice(0, foundI, foundMap), name = nameParts.join("/"))
|
||||
}
|
||||
return getOwn(config.pkgs, name) || name
|
||||
}
|
||||
|
||||
function makeShimExports(value) {
|
||||
function fn() {
|
||||
var ret;
|
||||
return value.init && (ret = value.init.apply(global, arguments)), ret || value.exports && getGlobal(value.exports)
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
function takeQueue(anonId) {
|
||||
var i, id, args, shim;
|
||||
for (i = 0; i < queue.length; i += 1) {
|
||||
if ("string" != typeof queue[i][0]) {
|
||||
if (!anonId) break;
|
||||
queue[i].unshift(anonId), anonId = undef
|
||||
}
|
||||
args = queue.shift(), id = args[0], i -= 1, id in defined || id in waiting || (id in deferreds ? main.apply(undef, args) : waiting[id] = args)
|
||||
}
|
||||
anonId && (shim = getOwn(config.shim, anonId) || {}, main(anonId, shim.deps || [], shim.exportsFn))
|
||||
}
|
||||
|
||||
function makeRequire(relName, topLevel) {
|
||||
var req = function(deps, callback, errback, alt) {
|
||||
var name, cfg;
|
||||
if (topLevel && takeQueue(), "string" == typeof deps) {
|
||||
if (handlers[deps]) return handlers[deps](relName);
|
||||
if (!((name = makeMap(deps, relName, !0).id) in defined)) throw new Error("Not loaded: " + name);
|
||||
return defined[name]
|
||||
}
|
||||
return deps && !Array.isArray(deps) && (cfg = deps, deps = undef, Array.isArray(callback) && (deps = callback, callback = errback, errback = alt), topLevel) ? req.config(cfg)(deps, callback, errback) : (callback = callback || function() {
|
||||
return slice.call(arguments, 0)
|
||||
}, asyncResolve.then(function() {
|
||||
return takeQueue(), main(undef, deps || [], callback, errback, relName)
|
||||
}))
|
||||
};
|
||||
return req.isBrowser = "undefined" != typeof document && "undefined" != typeof navigator, req.nameToUrl = function(moduleName, ext, skipExt) {
|
||||
var paths, syms, i, parentModule, url, parentPath, bundleId, pkgMain = getOwn(config.pkgs, moduleName);
|
||||
if (pkgMain && (moduleName = pkgMain), bundleId = getOwn(bundlesMap, moduleName)) return req.nameToUrl(bundleId, ext, skipExt);
|
||||
if (urlRegExp.test(moduleName)) url = moduleName + (ext || "");
|
||||
else {
|
||||
for (paths = config.paths, syms = moduleName.split("/"), i = syms.length; i > 0; i -= 1)
|
||||
if (parentModule = syms.slice(0, i).join("/"), parentPath = getOwn(paths, parentModule)) {
|
||||
Array.isArray(parentPath) && (parentPath = parentPath[0]), syms.splice(0, i, parentPath);
|
||||
break
|
||||
} url = syms.join("/"), url += ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? "" : ".js"), url = ("/" === url.charAt(0) || url.match(/^[\w\+\.\-]+:/) ? "" : config.baseUrl) + url
|
||||
}
|
||||
return config.urlArgs && !/^blob\:/.test(url) ? url + config.urlArgs(moduleName, url) : url
|
||||
}, req.toUrl = function(moduleNamePlusExt) {
|
||||
var ext, index = moduleNamePlusExt.lastIndexOf("."),
|
||||
segment = moduleNamePlusExt.split("/")[0],
|
||||
isRelative = "." === segment || ".." === segment;
|
||||
return -1 !== index && (!isRelative || index > 1) && (ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length), moduleNamePlusExt = moduleNamePlusExt.substring(0, index)), req.nameToUrl(normalize(moduleNamePlusExt, relName), ext, !0)
|
||||
}, req.defined = function(id) {
|
||||
return makeMap(id, relName, !0).id in defined
|
||||
}, req.specified = function(id) {
|
||||
return (id = makeMap(id, relName, !0).id) in defined || id in deferreds
|
||||
}, req
|
||||
}
|
||||
|
||||
function resolve(name, d, value) {
|
||||
name && (defined[name] = value, requirejs.onResourceLoad && requirejs.onResourceLoad(context, d.map, d.deps)), d.finished = !0, d.resolve(value)
|
||||
}
|
||||
|
||||
function reject(d, err) {
|
||||
d.finished = !0, d.rejected = !0, d.reject(err)
|
||||
}
|
||||
|
||||
function makeNormalize(relName) {
|
||||
return function(name) {
|
||||
return normalize(name, relName, !0)
|
||||
}
|
||||
}
|
||||
|
||||
function defineModule(d) {
|
||||
d.factoryCalled = !0;
|
||||
var ret, name = d.map.id;
|
||||
try {
|
||||
ret = context.execCb(name, d.factory, d.values, defined[name])
|
||||
} catch (err) {
|
||||
return reject(d, err)
|
||||
}
|
||||
name ? ret === undef && (d.cjsModule ? ret = d.cjsModule.exports : d.usingExports && (ret = defined[name])) : requireDeferreds.splice(requireDeferreds.indexOf(d), 1), resolve(name, d, ret)
|
||||
}
|
||||
|
||||
function depFinished(val, i) {
|
||||
this.rejected || this.depDefined[i] || (this.depDefined[i] = !0, this.depCount += 1, this.values[i] = val, this.depending || this.depCount !== this.depMax || defineModule(this))
|
||||
}
|
||||
|
||||
function makeDefer(name, calculatedMap) {
|
||||
var d = {};
|
||||
return d.promise = new Promise(function(resolve, reject) {
|
||||
d.resolve = resolve, d.reject = function(err) {
|
||||
name || requireDeferreds.splice(requireDeferreds.indexOf(d), 1), reject(err)
|
||||
}
|
||||
}), d.map = name ? calculatedMap || makeMap(name) : {}, d.depCount = 0, d.depMax = 0, d.values = [], d.depDefined = [], d.depFinished = depFinished, d.map.pr && (d.deps = [makeMap(d.map.pr)]), d
|
||||
}
|
||||
|
||||
function getDefer(name, calculatedMap) {
|
||||
var d;
|
||||
return name ? (d = name in deferreds && deferreds[name]) || (d = deferreds[name] = makeDefer(name, calculatedMap)) : (d = makeDefer(), requireDeferreds.push(d)), d
|
||||
}
|
||||
|
||||
function makeErrback(d, name) {
|
||||
return function(err) {
|
||||
d.rejected || (err.dynaId || (err.dynaId = "id" + (errCount += 1), err.requireModules = [name]), reject(d, err))
|
||||
}
|
||||
}
|
||||
|
||||
function waitForDep(depMap, relName, d, i) {
|
||||
d.depMax += 1, callDep(depMap, relName).then(function(val) {
|
||||
d.depFinished(val, i)
|
||||
}, makeErrback(d, depMap.id)).catch(makeErrback(d, d.map.id))
|
||||
}
|
||||
|
||||
function makeLoad(id) {
|
||||
function load(value) {
|
||||
fromTextCalled || resolve(id, getDefer(id), value)
|
||||
}
|
||||
var fromTextCalled;
|
||||
return load.error = function(err) {
|
||||
reject(getDefer(id), err)
|
||||
}, load.fromText = function(text, textAlt) {
|
||||
var execError, d = getDefer(id),
|
||||
map = makeMap(makeMap(id).n),
|
||||
plainId = map.id;
|
||||
fromTextCalled = !0, d.factory = function(p, val) {
|
||||
return val
|
||||
}, textAlt && (text = textAlt), hasProp(config.config, id) && (config.config[plainId] = config.config[id]);
|
||||
try {
|
||||
req.exec(text)
|
||||
} catch (e) {
|
||||
execError = new Error("fromText eval for " + plainId + " failed: " + e), execError.requireType = "fromtexteval", reject(d, execError)
|
||||
}
|
||||
takeQueue(plainId), d.deps = [map], waitForDep(map, null, d, d.deps.length)
|
||||
}, load
|
||||
}
|
||||
|
||||
function callPlugin(plugin, map, relName) {
|
||||
plugin.load(map.n, makeRequire(relName), makeLoad(map.id), config)
|
||||
}
|
||||
|
||||
function splitPrefix(name) {
|
||||
var prefix, index = name ? name.indexOf("!") : -1;
|
||||
return index > -1 && (prefix = name.substring(0, index), name = name.substring(index + 1, name.length)), [prefix, name]
|
||||
}
|
||||
|
||||
function breakCycle(d, traced, processed) {
|
||||
var id = d.map.id;
|
||||
traced[id] = !0, !d.finished && d.deps && d.deps.forEach(function(depMap) {
|
||||
var depId = depMap.id,
|
||||
dep = !hasProp(handlers, depId) && getDefer(depId, depMap);
|
||||
!dep || dep.finished || processed[depId] || (hasProp(traced, depId) ? d.deps.forEach(function(depMap, i) {
|
||||
depMap.id === depId && d.depFinished(defined[depId], i)
|
||||
}) : breakCycle(dep, traced, processed))
|
||||
}), processed[id] = !0
|
||||
}
|
||||
|
||||
function check(d) {
|
||||
var err, mid, dfd, notFinished = [],
|
||||
waitInterval = 1e3 * config.waitSeconds,
|
||||
expired = waitInterval && startTime + waitInterval < (new Date).getTime();
|
||||
if (0 === loadCount && (d ? d.finished || breakCycle(d, {}, {}) : requireDeferreds.length && requireDeferreds.forEach(function(d) {
|
||||
breakCycle(d, {}, {})
|
||||
})), expired) {
|
||||
for (mid in deferreds) dfd = deferreds[mid], dfd.finished || notFinished.push(dfd.map.id);
|
||||
err = new Error("Timeout for modules: " + notFinished), err.requireModules = notFinished, err.requireType = "timeout", notFinished.forEach(function(id) {
|
||||
reject(getDefer(id), err)
|
||||
})
|
||||
} else(loadCount || requireDeferreds.length) && (checkingLater || (checkingLater = !0, setTimeout(function() {
|
||||
checkingLater = !1, check()
|
||||
}, 70)))
|
||||
}
|
||||
|
||||
function delayedError(e) {
|
||||
console.log(e.stack);
|
||||
return setTimeout(function() {
|
||||
e.dynaId && trackedErrors[e.dynaId] || (trackedErrors[e.dynaId] = !0, req.onError(e))
|
||||
}), e
|
||||
}
|
||||
var req, main, makeMap, callDep, handlers, checkingLater, load, context, defined = obj(),
|
||||
waiting = obj(),
|
||||
config = {
|
||||
waitSeconds: 7,
|
||||
baseUrl: "./",
|
||||
paths: {},
|
||||
bundles: {},
|
||||
pkgs: {},
|
||||
shim: {},
|
||||
config: {}
|
||||
},
|
||||
mapCache = obj(),
|
||||
requireDeferreds = [],
|
||||
deferreds = obj(),
|
||||
calledDefine = obj(),
|
||||
calledPlugin = obj(),
|
||||
loadCount = 0,
|
||||
startTime = (new Date).getTime(),
|
||||
errCount = 0,
|
||||
trackedErrors = obj(),
|
||||
urlFetched = obj(),
|
||||
bundlesMap = obj(),
|
||||
asyncResolve = Promise.resolve(undefined);
|
||||
return load = "function" == typeof importScripts ? function(map) {
|
||||
var url = map.url;
|
||||
urlFetched[url] || (urlFetched[url] = !0, getDefer(map.id), importScripts(url), takeQueue(map.id))
|
||||
} : function(map) {
|
||||
var script, id = map.id,
|
||||
url = map.url;
|
||||
urlFetched[url] || (urlFetched[url] = !0, script = document.createElement("script"), script.setAttribute("data-requiremodule", id), script.type = config.scriptType || "text/javascript", script.charset = "utf-8", script.async = !0, loadCount += 1, script.addEventListener("load", function() {
|
||||
loadCount -= 1, takeQueue(id)
|
||||
}, !1), script.addEventListener("error", function() {
|
||||
loadCount -= 1;
|
||||
var err, pathConfig = getOwn(config.paths, id);
|
||||
if (pathConfig && Array.isArray(pathConfig) && pathConfig.length > 1) {
|
||||
script.parentNode.removeChild(script), pathConfig.shift();
|
||||
var d = getDefer(id);
|
||||
d.map = makeMap(id), d.map.url = req.nameToUrl(id), load(d.map)
|
||||
} else err = new Error("Load failed: " + id + ": " + script.src), err.requireModules = [id], err.requireType = "scripterror", reject(getDefer(id), err)
|
||||
}, !1), script.src = url, 10 === document.documentMode ? asap.then(function() {
|
||||
document.head.appendChild(script)
|
||||
}) : document.head.appendChild(script))
|
||||
}, callDep = function(map, relName) {
|
||||
var args, bundleId, name = map.id,
|
||||
shim = config.shim[name];
|
||||
if (name in waiting) args = waiting[name], delete waiting[name], main.apply(undef, args);
|
||||
else if (!(name in deferreds))
|
||||
if (map.pr) {
|
||||
if (!(bundleId = getOwn(bundlesMap, name))) return callDep(makeMap(map.pr)).then(function(plugin) {
|
||||
var newMap = map.prn ? map : makeMap(name, relName, !0),
|
||||
newId = newMap.id,
|
||||
shim = getOwn(config.shim, newId);
|
||||
return newId in calledPlugin || (calledPlugin[newId] = !0, shim && shim.deps ? req(shim.deps, function() {
|
||||
callPlugin(plugin, newMap, relName)
|
||||
}) : callPlugin(plugin, newMap, relName)), getDefer(newId).promise
|
||||
});
|
||||
map.url = req.nameToUrl(bundleId), load(map)
|
||||
} else shim && shim.deps ? req(shim.deps, function() {
|
||||
load(map)
|
||||
}) : load(map);
|
||||
return getDefer(name).promise
|
||||
}, makeMap = function(name, relName, applyMap) {
|
||||
if ("string" != typeof name) return name;
|
||||
var plugin, url, parts, prefix, result, prefixNormalized, cacheKey = name + " & " + (relName || "") + " & " + !!applyMap;
|
||||
return parts = splitPrefix(name), prefix = parts[0], name = parts[1], !prefix && cacheKey in mapCache ? mapCache[cacheKey] : (prefix && (prefix = normalize(prefix, relName, applyMap), plugin = prefix in defined && defined[prefix]), prefix ? plugin && plugin.normalize ? (name = plugin.normalize(name, makeNormalize(relName)), prefixNormalized = !0) : name = -1 === name.indexOf("!") ? normalize(name, relName, applyMap) : name : (name = normalize(name, relName, applyMap), parts = splitPrefix(name), prefix = parts[0], name = parts[1], url = req.nameToUrl(name)), result = {
|
||||
id: prefix ? prefix + "!" + name : name,
|
||||
n: name,
|
||||
pr: prefix,
|
||||
url: url,
|
||||
prn: prefix && prefixNormalized
|
||||
}, prefix || (mapCache[cacheKey] = result), result)
|
||||
}, handlers = {
|
||||
require: function(name) {
|
||||
return makeRequire(name)
|
||||
},
|
||||
exports: function(name) {
|
||||
var e = defined[name];
|
||||
return void 0 !== e ? e : defined[name] = {}
|
||||
},
|
||||
module: function(name) {
|
||||
return {
|
||||
id: name,
|
||||
uri: "",
|
||||
exports: handlers.exports(name),
|
||||
config: function() {
|
||||
return getOwn(config.config, name) || {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, main = function(name, deps, factory, errback, relName) {
|
||||
if (name) {
|
||||
if (name in calledDefine) return;
|
||||
calledDefine[name] = !0
|
||||
}
|
||||
var d = getDefer(name);
|
||||
return deps && !Array.isArray(deps) && (factory = deps, deps = []), deps = deps ? slice.call(deps, 0) : null, errback || (hasProp(config, "defaultErrback") ? config.defaultErrback && (errback = config.defaultErrback) : errback = delayedError), errback && d.promise.catch(errback), relName = relName || name, "function" == typeof factory ? (!deps.length && factory.length && (factory.toString().replace(commentRegExp, commentReplace).replace(cjsRequireRegExp, function(match, dep) {
|
||||
deps.push(dep)
|
||||
}), deps = (1 === factory.length ? ["require"] : ["require", "exports", "module"]).concat(deps)), d.factory = factory, d.deps = deps, d.depending = !0, deps.forEach(function(depName, i) {
|
||||
var depMap;
|
||||
deps[i] = depMap = makeMap(depName, relName, !0), depName = depMap.id, "require" === depName ? d.values[i] = handlers.require(name) : "exports" === depName ? (d.values[i] = handlers.exports(name), d.usingExports = !0) : "module" === depName ? d.values[i] = d.cjsModule = handlers.module(name) : void 0 === depName ? d.values[i] = void 0 : waitForDep(depMap, relName, d, i)
|
||||
}), d.depending = !1, d.depCount === d.depMax && defineModule(d)) : name && resolve(name, d, factory), startTime = (new Date).getTime(), name || check(d), d.promise
|
||||
}, req = makeRequire(null, !0), req.config = function(cfg) {
|
||||
if (cfg.context && cfg.context !== contextName) {
|
||||
var existingContext = getOwn(contexts, cfg.context);
|
||||
return existingContext ? existingContext.req.config(cfg) : newContext(cfg.context).config(cfg)
|
||||
}
|
||||
if (mapCache = obj(), cfg.baseUrl && "/" !== cfg.baseUrl.charAt(cfg.baseUrl.length - 1) && (cfg.baseUrl += "/"), "string" == typeof cfg.urlArgs) {
|
||||
var urlArgs = cfg.urlArgs;
|
||||
cfg.urlArgs = function(id, url) {
|
||||
return (-1 === url.indexOf("?") ? "?" : "&") + urlArgs
|
||||
}
|
||||
}
|
||||
var shim = config.shim,
|
||||
objs = {
|
||||
paths: !0,
|
||||
bundles: !0,
|
||||
config: !0,
|
||||
map: !0
|
||||
};
|
||||
return eachProp(cfg, function(value, prop) {
|
||||
objs[prop] ? (config[prop] || (config[prop] = {}), mixin(config[prop], value, !0, !0)) : config[prop] = value
|
||||
}), cfg.bundles && eachProp(cfg.bundles, function(value, prop) {
|
||||
value.forEach(function(v) {
|
||||
v !== prop && (bundlesMap[v] = prop)
|
||||
})
|
||||
}), cfg.shim && (eachProp(cfg.shim, function(value, id) {
|
||||
Array.isArray(value) && (value = {
|
||||
deps: value
|
||||
}), !value.exports && !value.init || value.exportsFn || (value.exportsFn = makeShimExports(value)), shim[id] = value
|
||||
}), config.shim = shim), cfg.packages && cfg.packages.forEach(function(pkgObj) {
|
||||
var location, name;
|
||||
pkgObj = "string" == typeof pkgObj ? {
|
||||
name: pkgObj
|
||||
} : pkgObj, name = pkgObj.name, location = pkgObj.location, location && (config.paths[name] = pkgObj.location), config.pkgs[name] = pkgObj.name + "/" + (pkgObj.main || "main").replace(currDirRegExp, "").replace(jsSuffixRegExp, "")
|
||||
}), (cfg.deps || cfg.callback) && req(cfg.deps, cfg.callback), req
|
||||
}, req.onError = function(err) {
|
||||
throw err
|
||||
}, context = {
|
||||
id: contextName,
|
||||
defined: defined,
|
||||
waiting: waiting,
|
||||
config: config,
|
||||
deferreds: deferreds,
|
||||
req: req,
|
||||
execCb: function(name, callback, args, exports) {
|
||||
return callback.apply(exports, args)
|
||||
}
|
||||
}, contexts[contextName] = context, req
|
||||
}
|
||||
if (!Promise) throw new Error("No Promise implementation available");
|
||||
var topReq, dataMain, src, subPath, bootstrapConfig = requirejs || require,
|
||||
hasOwn = Object.prototype.hasOwnProperty,
|
||||
contexts = {},
|
||||
queue = [],
|
||||
currDirRegExp = /^\.\//,
|
||||
urlRegExp = /^\/|\:|\?|\.js$/,
|
||||
commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,
|
||||
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
|
||||
jsSuffixRegExp = /\.js$/,
|
||||
slice = Array.prototype.slice;
|
||||
if ("function" != typeof requirejs) {
|
||||
var asap = Promise.resolve(void 0);
|
||||
requirejs = topReq = newContext("_"), "function" != typeof require && (require = topReq), topReq.exec = function(text) {
|
||||
return eval(text)
|
||||
}, topReq.contexts = contexts, define = function() {
|
||||
queue.push(slice.call(arguments, 0))
|
||||
}, define.amd = {
|
||||
jQuery: !0
|
||||
}, bootstrapConfig && topReq.config(bootstrapConfig), topReq.isBrowser && !contexts._.config.skipDataMain && (dataMain = document.querySelectorAll("script[data-main]")[0], (dataMain = dataMain && dataMain.getAttribute("data-main")) && (dataMain = dataMain.replace(jsSuffixRegExp, ""), bootstrapConfig && bootstrapConfig.baseUrl || -1 !== dataMain.indexOf("!") || (src = dataMain.split("/"), dataMain = src.pop(), subPath = src.length ? src.join("/") + "/" : "./", topReq.config({
|
||||
baseUrl: subPath
|
||||
})), topReq([dataMain])))
|
||||
}
|
||||
}(this, "undefined" != typeof Promise ? Promise : void 0);
|
||||
@@ -1,5 +1,5 @@
|
||||
//TODO: (vitorsemeano) modify this lines for webpack
|
||||
define(["libraries/apiclient/apiclientcore", "localassetmanager"], function(ApiClient, localassetmanager) {
|
||||
define(["bower_components/apiclient/apiclientcore", "localassetmanager"], function(ApiClient, localassetmanager) {
|
||||
"use strict";
|
||||
|
||||
if ("cordova" !== window.appMode && "android" !== window.appMode) {
|
||||
@@ -59,8 +59,8 @@ define(["libraries/apiclient/apiclientcore", "localassetmanager"], function(ApiC
|
||||
})
|
||||
}
|
||||
|
||||
function ApiClientEx(serverAddress, clientName, applicationVersion, deviceName, deviceId) {
|
||||
ApiClient.call(this, serverAddress, clientName, applicationVersion, deviceName, deviceId)
|
||||
function ApiClientEx(serverAddress, clientName, applicationVersion, deviceName, deviceId, devicePixelRatio) {
|
||||
ApiClient.call(this, serverAddress, clientName, applicationVersion, deviceName, deviceId, devicePixelRatio)
|
||||
}
|
||||
var localPrefix = "local:",
|
||||
localViewPrefix = "localview:";
|
||||
@@ -233,4 +233,4 @@ define(["libraries/apiclient/apiclientcore", "localassetmanager"], function(ApiC
|
||||
}
|
||||
return ApiClient.prototype.getItemDownloadUrl.call(this, itemId)
|
||||
}, ApiClientEx
|
||||
});
|
||||
});
|
||||
@@ -58,23 +58,9 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
return request.data && ("string" == typeof request.data ? fetchRequest.body = request.data : (fetchRequest.body = paramsToString(request.data), contentType = contentType || "application/x-www-form-urlencoded; charset=UTF-8")), contentType && (headers["Content-Type"] = contentType), request.timeout ? fetchWithTimeout(request.url, fetchRequest, request.timeout) : fetch(request.url, fetchRequest)
|
||||
}
|
||||
|
||||
function ApiClient(serverAddress, appName, appVersion, deviceName, deviceId) {
|
||||
if (!serverAddress) {
|
||||
throw new Error("Must supply a serverAddress");
|
||||
}
|
||||
|
||||
console.debug("ApiClient serverAddress: " + serverAddress);
|
||||
console.debug("ApiClient appName: " + appName);
|
||||
console.debug("ApiClient appVersion: " + appVersion);
|
||||
console.debug("ApiClient deviceName: " + deviceName);
|
||||
console.debug("ApiClient deviceId: " + deviceId);
|
||||
|
||||
this._serverInfo = {};
|
||||
this._serverAddress = serverAddress;
|
||||
this._deviceId = deviceId;
|
||||
this._deviceName = deviceName;
|
||||
this._appName = appName;
|
||||
this._appVersion = appVersion;
|
||||
function ApiClient(serverAddress, appName, appVersion, deviceName, deviceId, devicePixelRatio) {
|
||||
if (!serverAddress) throw new Error("Must supply a serverAddress");
|
||||
console.log("ApiClient serverAddress: " + serverAddress), console.log("ApiClient appName: " + appName), console.log("ApiClient appVersion: " + appVersion), console.log("ApiClient deviceName: " + deviceName), console.log("ApiClient deviceId: " + deviceId), this._serverInfo = {}, this._serverAddress = serverAddress, this._deviceId = deviceId, this._deviceName = deviceName, this._appName = appName, this._appVersion = appVersion, this._devicePixelRatio = devicePixelRatio
|
||||
}
|
||||
|
||||
function setSavedEndpointInfo(instance, info) {
|
||||
@@ -82,14 +68,13 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
}
|
||||
|
||||
function getTryConnectPromise(instance, url, state, resolve, reject) {
|
||||
console.debug("getTryConnectPromise " + url);
|
||||
fetchWithTimeout(instance.getUrl("system/info/public", null, url), {
|
||||
console.log("getTryConnectPromise " + url), fetchWithTimeout(instance.getUrl("system/info/public", null, url), {
|
||||
method: "GET",
|
||||
accept: "application/json"
|
||||
}, 15e3).then(function() {
|
||||
state.resolved || (state.resolved = !0, console.debug("Reconnect succeeded to " + url), instance.serverAddress(url), resolve())
|
||||
state.resolved || (state.resolved = !0, console.log("Reconnect succeeded to " + url), instance.serverAddress(url), resolve())
|
||||
}, function() {
|
||||
state.resolved || (console.error("Reconnect failed to " + url), ++state.rejects >= state.numAddresses && reject())
|
||||
state.resolved || (console.log("Reconnect failed to " + url), ++state.rejects >= state.numAddresses && reject())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -106,7 +91,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
}), addressesStrings.push(addresses[addresses.length - 1].url)), serverInfo.RemoteAddress && -1 === addressesStrings.indexOf(serverInfo.RemoteAddress) && (addresses.push({
|
||||
url: serverInfo.RemoteAddress,
|
||||
timeout: 200
|
||||
}), addressesStrings.push(addresses[addresses.length - 1].url)), console.debug("tryReconnect: " + addressesStrings.join("|")), new Promise(function(resolve, reject) {
|
||||
}), addressesStrings.push(addresses[addresses.length - 1].url)), console.log("tryReconnect: " + addressesStrings.join("|")), new Promise(function(resolve, reject) {
|
||||
var state = {};
|
||||
state.numAddresses = addresses.length, state.rejects = 0, addresses.map(function(url) {
|
||||
setTimeout(function() {
|
||||
@@ -118,7 +103,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
|
||||
function tryReconnect(instance, retryCount) {
|
||||
return retryCount = retryCount || 0, retryCount >= 20 ? Promise.reject() : tryReconnectInternal(instance).catch(function(err) {
|
||||
return console.error("error in tryReconnectInternal: " + (err || "")), new Promise(function(resolve, reject) {
|
||||
return console.log("error in tryReconnectInternal: " + (err || "")), new Promise(function(resolve, reject) {
|
||||
setTimeout(function() {
|
||||
tryReconnect(instance, retryCount + 1).then(resolve, reject)
|
||||
}, 500)
|
||||
@@ -154,7 +139,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
|
||||
function onWebSocketOpen() {
|
||||
var instance = this;
|
||||
console.debug("web socket connection opened"), events.trigger(instance, "websocketopen")
|
||||
console.log("web socket connection opened"), events.trigger(instance, "websocketopen")
|
||||
}
|
||||
|
||||
function onWebSocketError() {
|
||||
@@ -164,12 +149,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
|
||||
function setSocketOnClose(apiClient, socket) {
|
||||
socket.onclose = function() {
|
||||
console.debug("web socket closed");
|
||||
if (apiClient._webSocket === socket) {
|
||||
console.debug("nulling out web socket");
|
||||
apiClient._webSocket = null;
|
||||
}
|
||||
setTimeout(function() {
|
||||
console.log("web socket closed"), apiClient._webSocket === socket && (console.log("nulling out web socket"), apiClient._webSocket = null), setTimeout(function() {
|
||||
events.trigger(apiClient, "websocketclose")
|
||||
}, 0)
|
||||
}
|
||||
@@ -217,7 +197,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
}
|
||||
|
||||
function normalizeImageOptions(instance, options) {
|
||||
var ratio = window.devicePixelRatio;
|
||||
var ratio = instance._devicePixelRatio || 1;
|
||||
ratio && (options.minScale && (ratio = Math.max(options.minScale, ratio)), options.width && (options.width = Math.round(options.width * ratio)), options.height && (options.height = Math.round(options.height * ratio)), options.maxWidth && (options.maxWidth = Math.round(options.maxWidth * ratio)), options.maxHeight && (options.maxHeight = Math.round(options.maxHeight * ratio))), options.quality = options.quality || instance.getDefaultImageQuality(options.type), instance.normalizeImageOptions && instance.normalizeImageOptions(options)
|
||||
}
|
||||
|
||||
@@ -264,24 +244,24 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
var lowered = url.toLowerCase();
|
||||
return "/" !== name.charAt(0) && (url += "/"), url += name, params && (params = paramsToString(params)) && (url += "?" + params), url
|
||||
}, ApiClient.prototype.fetchWithFailover = function(request, enableReconnection) {
|
||||
console.debug("Requesting " + request.url), request.timeout = 3e4;
|
||||
console.log("Requesting " + request.url), request.timeout = 3e4;
|
||||
var instance = this;
|
||||
return getFetchPromise(request).then(function(response) {
|
||||
return instance.lastFetch = (new Date).getTime(), response.status < 400 ? "json" === request.dataType || "application/json" === request.headers.accept ? response.json() : "text" === request.dataType || 0 === (response.headers.get("Content-Type") || "").toLowerCase().indexOf("text/") ? response.text() : response : (onFetchFail(instance, request.url, response), Promise.reject(response))
|
||||
}, function(error) {
|
||||
if (error ? console.error("Request failed to " + request.url + " " + (error.status || "") + " " + error.toString()) : console.error("Request timed out to " + request.url), error && error.status || !enableReconnection) throw console.error("Reporting request failure"), onFetchFail(instance, request.url, {}), error;
|
||||
console.debug("Attempting reconnection");
|
||||
if (error ? console.log("Request failed to " + request.url + " " + (error.status || "") + " " + error.toString()) : console.log("Request timed out to " + request.url), error && error.status || !enableReconnection) throw console.log("Reporting request failure"), onFetchFail(instance, request.url, {}), error;
|
||||
console.log("Attempting reconnection");
|
||||
var previousServerAddress = instance.serverAddress();
|
||||
return tryReconnect(instance).then(function() {
|
||||
return console.debug("Reconnect succeesed"), request.url = request.url.replace(previousServerAddress, instance.serverAddress()), instance.fetchWithFailover(request, !1)
|
||||
return console.log("Reconnect succeesed"), request.url = request.url.replace(previousServerAddress, instance.serverAddress()), instance.fetchWithFailover(request, !1)
|
||||
}, function(innerError) {
|
||||
throw console.error("Reconnect failed"), onFetchFail(instance, request.url, {}), innerError
|
||||
throw console.log("Reconnect failed"), onFetchFail(instance, request.url, {}), innerError
|
||||
})
|
||||
})
|
||||
}, ApiClient.prototype.fetch = function(request, includeAuthorization) {
|
||||
if (!request) throw new Error("Request cannot be null");
|
||||
if (request.headers = request.headers || {}, !1 !== includeAuthorization && this.setRequestHeaders(request.headers), !1 === this.enableAutomaticNetworking || "GET" !== request.type) {
|
||||
console.debug("Requesting url without automatic networking: " + request.url);
|
||||
console.log("Requesting url without automatic networking: " + request.url);
|
||||
var instance = this;
|
||||
return getFetchPromise(request).then(function(response) {
|
||||
return instance.lastFetch = (new Date).getTime(), response.status < 400 ? "json" === request.dataType || "application/json" === request.headers.accept ? response.json() : "text" === request.dataType || 0 === (response.headers.get("Content-Type") || "").toLowerCase().indexOf("text/") ? response.text() : response : (onFetchFail(instance, request.url, response), Promise.reject(response))
|
||||
@@ -360,7 +340,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
if (!this.isWebSocketOpenOrConnecting() && this.isWebSocketSupported()) try {
|
||||
this.openWebSocket()
|
||||
} catch (err) {
|
||||
console.error("error opening web socket: " + err)
|
||||
console.log("Error opening web socket: " + err)
|
||||
}
|
||||
};
|
||||
var messageIdsReceived = {};
|
||||
@@ -368,14 +348,14 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
var accessToken = this.accessToken();
|
||||
if (!accessToken) throw new Error("Cannot open web socket without access token.");
|
||||
var url = this.getUrl("socket");
|
||||
url = replaceAll(url, "emby/socket", "embywebsocket"), url = replaceAll(url, "https:", "wss:"), url = replaceAll(url, "http:", "ws:"), url += "?api_key=" + accessToken, url += "&deviceId=" + this.deviceId(), console.debug("opening web socket with url: " + url);
|
||||
url = replaceAll(url, "emby/socket", "embywebsocket"), url = replaceAll(url, "https:", "wss:"), url = replaceAll(url, "http:", "ws:"), url += "?api_key=" + accessToken, url += "&deviceId=" + this.deviceId(), console.log("opening web socket with url: " + url);
|
||||
var webSocket = new WebSocket(url);
|
||||
webSocket.onmessage = onWebSocketMessage.bind(this), webSocket.onopen = onWebSocketOpen.bind(this), webSocket.onerror = onWebSocketError.bind(this), setSocketOnClose(this, webSocket), this._webSocket = webSocket
|
||||
}, ApiClient.prototype.closeWebSocket = function() {
|
||||
var socket = this._webSocket;
|
||||
socket && socket.readyState === WebSocket.OPEN && socket.close()
|
||||
}, ApiClient.prototype.sendWebSocketMessage = function(name, data) {
|
||||
console.debug("Sending web socket message: " + name);
|
||||
console.log("Sending web socket message: " + name);
|
||||
var msg = {
|
||||
MessageType: name
|
||||
};
|
||||
@@ -407,7 +387,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
}, ApiClient.prototype.updateServerInfo = function(server, serverUrl) {
|
||||
if (null == server) throw new Error("server cannot be null");
|
||||
if (this.serverInfo(server), !serverUrl) throw new Error("serverUrl cannot be null. serverInfo: " + JSON.stringify(server));
|
||||
console.debug("Setting server address to " + serverUrl), this.serverAddress(serverUrl)
|
||||
console.log("Setting server address to " + serverUrl), this.serverAddress(serverUrl)
|
||||
}, ApiClient.prototype.isWebSocketSupported = function() {
|
||||
try {
|
||||
return null != WebSocket
|
||||
@@ -2,7 +2,7 @@ define([], function() {
|
||||
"use strict";
|
||||
|
||||
function onCachePutFail(e) {
|
||||
console.error("cannot put to a cache: " + e);
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
function updateCache(instance) {
|
||||
@@ -45,9 +45,9 @@ define([], function() {
|
||||
self.caches.open("embydata").then(onCacheOpened.bind(this));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("error opening cache: " + err);
|
||||
console.log("Error opening cache: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
return new MyStore;
|
||||
});
|
||||
});
|
||||
747
src/bower_components/apiclient/connectionmanager.js
vendored
Normal file
747
src/bower_components/apiclient/connectionmanager.js
vendored
Normal file
@@ -0,0 +1,747 @@
|
||||
define(["events", "apiclient", "appStorage"], function(events, apiClientFactory, appStorage) {
|
||||
"use strict";
|
||||
|
||||
function getServerAddress(server, mode) {
|
||||
switch (mode) {
|
||||
case ConnectionMode.Local:
|
||||
return server.LocalAddress;
|
||||
case ConnectionMode.Manual:
|
||||
return server.ManualAddress;
|
||||
case ConnectionMode.Remote:
|
||||
return server.RemoteAddress;
|
||||
default:
|
||||
return server.ManualAddress || server.LocalAddress || server.RemoteAddress
|
||||
}
|
||||
}
|
||||
|
||||
function paramsToString(params) {
|
||||
var values = [];
|
||||
for (var key in params) {
|
||||
var value = params[key];
|
||||
null !== value && void 0 !== value && "" !== value && values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value))
|
||||
}
|
||||
return values.join("&")
|
||||
}
|
||||
|
||||
function resolveFailure(instance, resolve) {
|
||||
resolve({
|
||||
State: "Unavailable",
|
||||
ConnectUser: instance.connectUser()
|
||||
})
|
||||
}
|
||||
|
||||
function mergeServers(credentialProvider, list1, list2) {
|
||||
for (var i = 0, length = list2.length; i < length; i++) credentialProvider.addOrUpdateServer(list1, list2[i]);
|
||||
return list1
|
||||
}
|
||||
|
||||
function updateServerInfo(server, systemInfo) {
|
||||
server.Name = systemInfo.ServerName, systemInfo.Id && (server.Id = systemInfo.Id), systemInfo.LocalAddress && (server.LocalAddress = systemInfo.LocalAddress)
|
||||
}
|
||||
|
||||
function getEmbyServerUrl(baseUrl, handler) {
|
||||
return baseUrl + "/" + handler
|
||||
}
|
||||
|
||||
function getFetchPromise(request) {
|
||||
var headers = request.headers || {};
|
||||
"json" === request.dataType && (headers.accept = "application/json");
|
||||
var fetchRequest = {
|
||||
headers: headers,
|
||||
method: request.type,
|
||||
credentials: "same-origin"
|
||||
},
|
||||
contentType = request.contentType;
|
||||
return request.data && ("string" == typeof request.data ? fetchRequest.body = request.data : (fetchRequest.body = paramsToString(request.data), contentType = contentType || "application/x-www-form-urlencoded; charset=UTF-8")), contentType && (headers["Content-Type"] = contentType), request.timeout ? fetchWithTimeout(request.url, fetchRequest, request.timeout) : fetch(request.url, fetchRequest)
|
||||
}
|
||||
|
||||
function fetchWithTimeout(url, options, timeoutMs) {
|
||||
return console.log("fetchWithTimeout: timeoutMs: " + timeoutMs + ", url: " + url), new Promise(function(resolve, reject) {
|
||||
var timeout = setTimeout(reject, timeoutMs);
|
||||
options = options || {}, options.credentials = "same-origin", fetch(url, options).then(function(response) {
|
||||
clearTimeout(timeout), console.log("fetchWithTimeout: succeeded connecting to url: " + url), resolve(response)
|
||||
}, function(error) {
|
||||
clearTimeout(timeout), console.log("fetchWithTimeout: timed out connecting to url: " + url), reject()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function ajax(request) {
|
||||
if (!request) throw new Error("Request cannot be null");
|
||||
return request.headers = request.headers || {}, console.log("ConnectionManager requesting url: " + request.url), getFetchPromise(request).then(function(response) {
|
||||
return console.log("ConnectionManager response status: " + response.status + ", url: " + request.url), response.status < 400 ? "json" === request.dataType || "application/json" === request.headers.accept ? response.json() : response : Promise.reject(response)
|
||||
}, function(err) {
|
||||
throw console.log("ConnectionManager request failed to url: " + request.url), err
|
||||
})
|
||||
}
|
||||
|
||||
function getConnectUrl(handler) {
|
||||
return "https://connect.emby.media/service/" + handler
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var reg = new RegExp(strReplace, "ig");
|
||||
return originalString.replace(reg, strWith)
|
||||
}
|
||||
|
||||
function normalizeAddress(address) {
|
||||
return address = address.trim(), 0 !== address.toLowerCase().indexOf("http") && (address = "http://" + address), address = replaceAll(address, "Http:", "http:"), address = replaceAll(address, "Https:", "https:")
|
||||
}
|
||||
|
||||
function stringEqualsIgnoreCase(str1, str2) {
|
||||
return (str1 || "").toLowerCase() === (str2 || "").toLowerCase()
|
||||
}
|
||||
|
||||
function compareVersions(a, b) {
|
||||
a = a.split("."), b = b.split(".");
|
||||
for (var i = 0, length = Math.max(a.length, b.length); i < length; i++) {
|
||||
var aVal = parseInt(a[i] || "0"),
|
||||
bVal = parseInt(b[i] || "0");
|
||||
if (aVal < bVal) return -1;
|
||||
if (aVal > bVal) return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
var defaultTimeout = 2e4,
|
||||
ConnectionMode = {
|
||||
Local: 0,
|
||||
Remote: 1,
|
||||
Manual: 2
|
||||
},
|
||||
ConnectionManager = function(credentialProvider, appName, appVersion, deviceName, deviceId, capabilities, devicePixelRatio) {
|
||||
function onConnectUserSignIn(user) {
|
||||
connectUser = user, events.trigger(self, "connectusersignedin", [user])
|
||||
}
|
||||
|
||||
function onAuthenticated(apiClient, result, options, saveCredentials) {
|
||||
var credentials = credentialProvider.credentials(),
|
||||
servers = credentials.Servers.filter(function(s) {
|
||||
return s.Id === result.ServerId
|
||||
}),
|
||||
server = servers.length ? servers[0] : apiClient.serverInfo();
|
||||
return !1 !== options.updateDateLastAccessed && (server.DateLastAccessed = (new Date).getTime()), server.Id = result.ServerId, saveCredentials ? (server.UserId = result.User.Id, server.AccessToken = result.AccessToken) : (server.UserId = null, server.AccessToken = null), credentialProvider.addOrUpdateServer(credentials.Servers, server), credentialProvider.credentials(credentials), apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection, apiClient.serverInfo(server), afterConnected(apiClient, options), onLocalUserSignIn(server, apiClient.serverAddress(), result.User)
|
||||
}
|
||||
|
||||
function afterConnected(apiClient, options) {
|
||||
options = options || {}, !1 !== options.reportCapabilities && apiClient.reportCapabilities(capabilities), apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection, !1 !== options.enableWebSocket && (console.log("calling apiClient.ensureWebSocket"), apiClient.ensureWebSocket())
|
||||
}
|
||||
|
||||
function onLocalUserSignIn(server, serverUrl, user) {
|
||||
return self._getOrAddApiClient(server, serverUrl), (self.onLocalUserSignedIn ? self.onLocalUserSignedIn.call(self, user) : Promise.resolve()).then(function() {
|
||||
events.trigger(self, "localusersignedin", [user])
|
||||
})
|
||||
}
|
||||
|
||||
function ensureConnectUser(credentials) {
|
||||
return connectUser && connectUser.Id === credentials.ConnectUserId ? Promise.resolve() : credentials.ConnectUserId && credentials.ConnectAccessToken ? (connectUser = null, getConnectUser(credentials.ConnectUserId, credentials.ConnectAccessToken).then(function(user) {
|
||||
return onConnectUserSignIn(user), Promise.resolve()
|
||||
}, function() {
|
||||
return Promise.resolve()
|
||||
})) : Promise.resolve()
|
||||
}
|
||||
|
||||
function getConnectUser(userId, accessToken) {
|
||||
if (!userId) throw new Error("null userId");
|
||||
if (!accessToken) throw new Error("null accessToken");
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: "https://connect.emby.media/service/user?id=" + userId,
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion,
|
||||
"X-Connect-UserToken": accessToken
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function addAuthenticationInfoFromConnect(server, serverUrl, credentials) {
|
||||
if (!server.ExchangeToken) throw new Error("server.ExchangeToken cannot be null");
|
||||
if (!credentials.ConnectUserId) throw new Error("credentials.ConnectUserId cannot be null");
|
||||
var url = getEmbyServerUrl(serverUrl, "Connect/Exchange?format=json&ConnectUserId=" + credentials.ConnectUserId),
|
||||
auth = 'MediaBrowser Client="' + appName + '", Device="' + deviceName + '", DeviceId="' + deviceId + '", Version="' + appVersion + '"';
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-MediaBrowser-Token": server.ExchangeToken,
|
||||
"X-Emby-Authorization": auth
|
||||
}
|
||||
}).then(function(auth) {
|
||||
return server.UserId = auth.LocalUserId, server.AccessToken = auth.AccessToken, auth
|
||||
}, function() {
|
||||
return server.UserId = null, server.AccessToken = null, Promise.reject()
|
||||
})
|
||||
}
|
||||
|
||||
function validateAuthentication(server, serverUrl) {
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: getEmbyServerUrl(serverUrl, "System/Info"),
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-MediaBrowser-Token": server.AccessToken
|
||||
}
|
||||
}).then(function(systemInfo) {
|
||||
return updateServerInfo(server, systemInfo), Promise.resolve()
|
||||
}, function() {
|
||||
return server.UserId = null, server.AccessToken = null, Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function getImageUrl(localUser) {
|
||||
if (connectUser && connectUser.ImageUrl) return {
|
||||
url: connectUser.ImageUrl
|
||||
};
|
||||
if (localUser && localUser.PrimaryImageTag) {
|
||||
return {
|
||||
url: self.getApiClient(localUser).getUserImageUrl(localUser.Id, {
|
||||
tag: localUser.PrimaryImageTag,
|
||||
type: "Primary"
|
||||
}),
|
||||
supportsParams: !0
|
||||
}
|
||||
}
|
||||
return {
|
||||
url: null,
|
||||
supportsParams: !1
|
||||
}
|
||||
}
|
||||
|
||||
function logoutOfServer(apiClient) {
|
||||
var serverInfo = apiClient.serverInfo() || {},
|
||||
logoutInfo = {
|
||||
serverId: serverInfo.Id
|
||||
};
|
||||
return apiClient.logout().then(function() {
|
||||
events.trigger(self, "localusersignedout", [logoutInfo])
|
||||
}, function() {
|
||||
events.trigger(self, "localusersignedout", [logoutInfo])
|
||||
})
|
||||
}
|
||||
|
||||
function getConnectServers(credentials) {
|
||||
return console.log("Begin getConnectServers"), credentials.ConnectAccessToken && credentials.ConnectUserId ? ajax({
|
||||
type: "GET",
|
||||
url: "https://connect.emby.media/service/servers?userId=" + credentials.ConnectUserId,
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion,
|
||||
"X-Connect-UserToken": credentials.ConnectAccessToken
|
||||
}
|
||||
}).then(function(servers) {
|
||||
return servers.map(function(i) {
|
||||
return {
|
||||
ExchangeToken: i.AccessKey,
|
||||
ConnectServerId: i.Id,
|
||||
Id: i.SystemId,
|
||||
Name: i.Name,
|
||||
RemoteAddress: i.Url,
|
||||
LocalAddress: i.LocalAddress,
|
||||
UserLinkType: "guest" === (i.UserType || "").toLowerCase() ? "Guest" : "LinkedUser"
|
||||
}
|
||||
})
|
||||
}, function() {
|
||||
return credentials.Servers.slice(0).filter(function(s) {
|
||||
return s.ExchangeToken
|
||||
})
|
||||
}) : Promise.resolve([])
|
||||
}
|
||||
|
||||
function filterServers(servers, connectServers) {
|
||||
return servers.filter(function(server) {
|
||||
return !server.ExchangeToken || connectServers.filter(function(connectServer) {
|
||||
return server.Id === connectServer.Id
|
||||
}).length > 0
|
||||
})
|
||||
}
|
||||
|
||||
function findServers() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var onFinish = function(foundServers) {
|
||||
var servers = foundServers.map(function(foundServer) {
|
||||
var info = {
|
||||
Id: foundServer.Id,
|
||||
LocalAddress: convertEndpointAddressToManualAddress(foundServer) || foundServer.Address,
|
||||
Name: foundServer.Name
|
||||
};
|
||||
return info.LastConnectionMode = info.ManualAddress ? ConnectionMode.Manual : ConnectionMode.Local, info
|
||||
});
|
||||
resolve(servers)
|
||||
};
|
||||
|
||||
if (window.NativeShell && typeof window.NativeShell.findServers === 'function') {
|
||||
window.NativeShell.findServers(1e3).then(onFinish, function() {
|
||||
onFinish([])
|
||||
});
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function convertEndpointAddressToManualAddress(info) {
|
||||
if (info.Address && info.EndpointAddress) {
|
||||
var address = info.EndpointAddress.split(":")[0],
|
||||
parts = info.Address.split(":");
|
||||
if (parts.length > 1) {
|
||||
var portString = parts[parts.length - 1];
|
||||
isNaN(parseInt(portString)) || (address += ":" + portString)
|
||||
}
|
||||
return normalizeAddress(address)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function getTryConnectPromise(url, connectionMode, state, resolve, reject) {
|
||||
console.log("getTryConnectPromise " + url), ajax({
|
||||
url: getEmbyServerUrl(url, "system/info/public"),
|
||||
timeout: defaultTimeout,
|
||||
type: "GET",
|
||||
dataType: "json"
|
||||
}).then(function(result) {
|
||||
state.resolved || (state.resolved = !0, console.log("Reconnect succeeded to " + url), resolve({
|
||||
url: url,
|
||||
connectionMode: connectionMode,
|
||||
data: result
|
||||
}))
|
||||
}, function() {
|
||||
state.resolved || (console.log("Reconnect failed to " + url), ++state.rejects >= state.numAddresses && reject())
|
||||
})
|
||||
}
|
||||
|
||||
function tryReconnect(serverInfo) {
|
||||
var addresses = [],
|
||||
addressesStrings = [];
|
||||
return !serverInfo.manualAddressOnly && serverInfo.LocalAddress && -1 === addressesStrings.indexOf(serverInfo.LocalAddress) && (addresses.push({
|
||||
url: serverInfo.LocalAddress,
|
||||
mode: ConnectionMode.Local,
|
||||
timeout: 0
|
||||
}), addressesStrings.push(addresses[addresses.length - 1].url)), serverInfo.ManualAddress && -1 === addressesStrings.indexOf(serverInfo.ManualAddress) && (addresses.push({
|
||||
url: serverInfo.ManualAddress,
|
||||
mode: ConnectionMode.Manual,
|
||||
timeout: 100
|
||||
}), addressesStrings.push(addresses[addresses.length - 1].url)), !serverInfo.manualAddressOnly && serverInfo.RemoteAddress && -1 === addressesStrings.indexOf(serverInfo.RemoteAddress) && (addresses.push({
|
||||
url: serverInfo.RemoteAddress,
|
||||
mode: ConnectionMode.Remote,
|
||||
timeout: 200
|
||||
}), addressesStrings.push(addresses[addresses.length - 1].url)), console.log("tryReconnect: " + addressesStrings.join("|")), new Promise(function(resolve, reject) {
|
||||
var state = {};
|
||||
state.numAddresses = addresses.length, state.rejects = 0, addresses.map(function(url) {
|
||||
setTimeout(function() {
|
||||
state.resolved || getTryConnectPromise(url.url, url.mode, state, resolve, reject)
|
||||
}, url.timeout)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function onSuccessfulConnection(server, systemInfo, connectionMode, serverUrl, options, resolve) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
options = options || {}, credentials.ConnectAccessToken && !1 !== options.enableAutoLogin ? ensureConnectUser(credentials).then(function() {
|
||||
server.ExchangeToken ? addAuthenticationInfoFromConnect(server, serverUrl, credentials).then(function() {
|
||||
afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !0, options, resolve)
|
||||
}, function() {
|
||||
afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !0, options, resolve)
|
||||
}) : afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !0, options, resolve)
|
||||
}) : afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !0, options, resolve)
|
||||
}
|
||||
|
||||
function afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, verifyLocalAuthentication, options, resolve) {
|
||||
if (options = options || {}, !1 === options.enableAutoLogin) server.UserId = null, server.AccessToken = null;
|
||||
else if (verifyLocalAuthentication && server.AccessToken && !1 !== options.enableAutoLogin) return void validateAuthentication(server, serverUrl).then(function() {
|
||||
afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !1, options, resolve)
|
||||
});
|
||||
updateServerInfo(server, systemInfo), server.LastConnectionMode = connectionMode, !1 !== options.updateDateLastAccessed && (server.DateLastAccessed = (new Date).getTime()), credentialProvider.addOrUpdateServer(credentials.Servers, server), credentialProvider.credentials(credentials);
|
||||
var result = {
|
||||
Servers: []
|
||||
};
|
||||
result.ApiClient = self._getOrAddApiClient(server, serverUrl), result.ApiClient.setSystemInfo(systemInfo), result.State = server.AccessToken && !1 !== options.enableAutoLogin ? "SignedIn" : "ServerSignIn", result.Servers.push(server), result.ApiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection, result.ApiClient.updateServerInfo(server, serverUrl);
|
||||
var resolveActions = function() {
|
||||
resolve(result), events.trigger(self, "connected", [result])
|
||||
};
|
||||
"SignedIn" === result.State ? (afterConnected(result.ApiClient, options), result.ApiClient.getCurrentUser().then(function(user) {
|
||||
onLocalUserSignIn(server, serverUrl, user).then(resolveActions, resolveActions)
|
||||
}, resolveActions)) : resolveActions()
|
||||
}
|
||||
|
||||
function getCacheKey(feature, apiClient, options) {
|
||||
options = options || {};
|
||||
var viewOnly = options.viewOnly,
|
||||
cacheKey = "regInfo-" + apiClient.serverId();
|
||||
return viewOnly && (cacheKey += "-viewonly"), cacheKey
|
||||
}
|
||||
|
||||
function addAppInfoToConnectRequest(request) {
|
||||
request.headers = request.headers || {}, request.headers["X-Application"] = appName + "/" + appVersion
|
||||
}
|
||||
|
||||
function exchangePin(pinInfo) {
|
||||
if (!pinInfo) throw new Error("pinInfo cannot be null");
|
||||
var request = {
|
||||
type: "POST",
|
||||
url: getConnectUrl("pin/authenticate"),
|
||||
data: {
|
||||
deviceId: pinInfo.DeviceId,
|
||||
pin: pinInfo.Pin
|
||||
},
|
||||
dataType: "json"
|
||||
};
|
||||
return addAppInfoToConnectRequest(request), ajax(request)
|
||||
}
|
||||
console.log("Begin ConnectionManager constructor");
|
||||
var self = this;
|
||||
this._apiClients = [];
|
||||
var connectUser;
|
||||
self.connectUser = function() {
|
||||
return connectUser
|
||||
}, self._minServerVersion = "3.2.33", self.appVersion = function() {
|
||||
return appVersion
|
||||
}, self.appName = function() {
|
||||
return appName
|
||||
}, self.capabilities = function() {
|
||||
return capabilities
|
||||
}, self.deviceId = function() {
|
||||
return deviceId
|
||||
}, self.credentialProvider = function() {
|
||||
return credentialProvider
|
||||
}, self.connectUserId = function() {
|
||||
return credentialProvider.credentials().ConnectUserId
|
||||
}, self.connectToken = function() {
|
||||
return credentialProvider.credentials().ConnectAccessToken
|
||||
}, self.getServerInfo = function(id) {
|
||||
return credentialProvider.credentials().Servers.filter(function(s) {
|
||||
return s.Id === id
|
||||
})[0]
|
||||
}, self.getLastUsedServer = function() {
|
||||
var servers = credentialProvider.credentials().Servers;
|
||||
return servers.sort(function(a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0)
|
||||
}), servers.length ? servers[0] : null
|
||||
}, self.addApiClient = function(apiClient) {
|
||||
self._apiClients.push(apiClient);
|
||||
var existingServers = credentialProvider.credentials().Servers.filter(function(s) {
|
||||
return stringEqualsIgnoreCase(s.ManualAddress, apiClient.serverAddress()) || stringEqualsIgnoreCase(s.LocalAddress, apiClient.serverAddress()) || stringEqualsIgnoreCase(s.RemoteAddress, apiClient.serverAddress())
|
||||
}),
|
||||
existingServer = existingServers.length ? existingServers[0] : apiClient.serverInfo();
|
||||
if (existingServer.DateLastAccessed = (new Date).getTime(), existingServer.LastConnectionMode = ConnectionMode.Manual, existingServer.ManualAddress = apiClient.serverAddress(), apiClient.manualAddressOnly && (existingServer.manualAddressOnly = !0), apiClient.serverInfo(existingServer), apiClient.onAuthenticated = function(instance, result) {
|
||||
return onAuthenticated(instance, result, {}, !0)
|
||||
}, !existingServers.length) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
credentials.Servers = [existingServer], credentialProvider.credentials(credentials)
|
||||
}
|
||||
events.trigger(self, "apiclientcreated", [apiClient])
|
||||
}, self.clearData = function() {
|
||||
console.log("connection manager clearing data"), connectUser = null;
|
||||
var credentials = credentialProvider.credentials();
|
||||
credentials.ConnectAccessToken = null, credentials.ConnectUserId = null, credentials.Servers = [], credentialProvider.credentials(credentials)
|
||||
}, self._getOrAddApiClient = function(server, serverUrl) {
|
||||
var apiClient = self.getApiClient(server.Id);
|
||||
return apiClient || (apiClient = new apiClientFactory(serverUrl, appName, appVersion, deviceName, deviceId, devicePixelRatio), self._apiClients.push(apiClient), apiClient.serverInfo(server), apiClient.onAuthenticated = function(instance, result) {
|
||||
return onAuthenticated(instance, result, {}, !0)
|
||||
}, events.trigger(self, "apiclientcreated", [apiClient])), console.log("returning instance from getOrAddApiClient"), apiClient
|
||||
}, self.getOrCreateApiClient = function(serverId) {
|
||||
var credentials = credentialProvider.credentials(),
|
||||
servers = credentials.Servers.filter(function(s) {
|
||||
return stringEqualsIgnoreCase(s.Id, serverId)
|
||||
});
|
||||
if (!servers.length) throw new Error("Server not found: " + serverId);
|
||||
var server = servers[0];
|
||||
return self._getOrAddApiClient(server, getServerAddress(server, server.LastConnectionMode))
|
||||
}, self.user = function(apiClient) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function onLocalUserDone(e) {
|
||||
var image = getImageUrl(localUser);
|
||||
resolve({
|
||||
localUser: localUser,
|
||||
name: connectUser ? connectUser.Name : localUser ? localUser.Name : null,
|
||||
imageUrl: image.url,
|
||||
supportsImageParams: image.supportsParams,
|
||||
connectUser: connectUser
|
||||
})
|
||||
}
|
||||
|
||||
function onEnsureConnectUserDone() {
|
||||
apiClient && apiClient.getCurrentUserId() ? apiClient.getCurrentUser().then(function(u) {
|
||||
localUser = u, onLocalUserDone()
|
||||
}, onLocalUserDone) : onLocalUserDone()
|
||||
}
|
||||
var localUser, credentials = credentialProvider.credentials();
|
||||
!credentials.ConnectUserId || !credentials.ConnectAccessToken || apiClient && apiClient.getCurrentUserId() ? onEnsureConnectUserDone() : ensureConnectUser(credentials).then(onEnsureConnectUserDone, onEnsureConnectUserDone)
|
||||
})
|
||||
}, self.logout = function() {
|
||||
console.log("begin connectionManager loguot");
|
||||
for (var promises = [], i = 0, length = self._apiClients.length; i < length; i++) {
|
||||
var apiClient = self._apiClients[i];
|
||||
apiClient.accessToken() && promises.push(logoutOfServer(apiClient))
|
||||
}
|
||||
return Promise.all(promises).then(function() {
|
||||
for (var credentials = credentialProvider.credentials(), servers = credentials.Servers.filter(function(u) {
|
||||
return "Guest" !== u.UserLinkType
|
||||
}), j = 0, numServers = servers.length; j < numServers; j++) {
|
||||
var server = servers[j];
|
||||
server.UserId = null, server.AccessToken = null, server.ExchangeToken = null
|
||||
}
|
||||
credentials.Servers = servers, credentials.ConnectAccessToken = null, credentials.ConnectUserId = null, credentialProvider.credentials(credentials), connectUser && (connectUser = null, events.trigger(self, "connectusersignedout"))
|
||||
})
|
||||
}, self.getSavedServers = function() {
|
||||
var credentials = credentialProvider.credentials(),
|
||||
servers = credentials.Servers.slice(0);
|
||||
return servers.sort(function(a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0)
|
||||
}), servers
|
||||
}, self.getAvailableServers = function() {
|
||||
console.log("Begin getAvailableServers");
|
||||
var credentials = credentialProvider.credentials();
|
||||
return Promise.all([getConnectServers(credentials), findServers()]).then(function(responses) {
|
||||
var connectServers = responses[0],
|
||||
foundServers = responses[1],
|
||||
servers = credentials.Servers.slice(0);
|
||||
return mergeServers(credentialProvider, servers, foundServers), mergeServers(credentialProvider, servers, connectServers), servers = filterServers(servers, connectServers), servers.sort(function(a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0)
|
||||
}), credentials.Servers = servers, credentialProvider.credentials(credentials), servers
|
||||
})
|
||||
}, self.connectToServers = function(servers, options) {
|
||||
console.log("Begin connectToServers, with " + servers.length + " servers");
|
||||
var firstServer = servers.length ? servers[0] : null;
|
||||
return firstServer ? self.connectToServer(firstServer, options).then(function(result) {
|
||||
return "Unavailable" === result.State && (result.State = "ServerSelection"), console.log("resolving connectToServers with result.State: " + result.State), result
|
||||
}) : Promise.resolve({
|
||||
Servers: servers,
|
||||
State: servers.length || self.connectUser() ? "ServerSelection" : "ConnectSignIn",
|
||||
ConnectUser: self.connectUser()
|
||||
})
|
||||
}, self.connectToServer = function(server, options) {
|
||||
return console.log("begin connectToServer"), new Promise(function(resolve, reject) {
|
||||
options = options || {}, tryReconnect(server).then(function(result) {
|
||||
var serverUrl = result.url,
|
||||
connectionMode = result.connectionMode;
|
||||
result = result.data, 1 === compareVersions(self.minServerVersion(), result.Version) ? (console.log("minServerVersion requirement not met. Server version: " + result.Version), resolve({
|
||||
State: "ServerUpdateNeeded",
|
||||
Servers: [server]
|
||||
})) : server.Id && result.Id !== server.Id ? (console.log("http request succeeded, but found a different server Id than what was expected"), resolveFailure(self, resolve)) : onSuccessfulConnection(server, result, connectionMode, serverUrl, options, resolve)
|
||||
}, function() {
|
||||
resolveFailure(self, resolve)
|
||||
})
|
||||
})
|
||||
}, self.connectToAddress = function(address, options) {
|
||||
function onFail() {
|
||||
return console.log("connectToAddress " + address + " failed"), Promise.resolve({
|
||||
State: "Unavailable",
|
||||
ConnectUser: instance.connectUser()
|
||||
})
|
||||
}
|
||||
if (!address) return Promise.reject();
|
||||
address = normalizeAddress(address);
|
||||
var instance = this,
|
||||
server = {
|
||||
ManualAddress: address,
|
||||
LastConnectionMode: ConnectionMode.Manual
|
||||
};
|
||||
return self.connectToServer(server, options).catch(onFail)
|
||||
}, self.loginToConnect = function(username, password) {
|
||||
return username && password ? ajax({
|
||||
type: "POST",
|
||||
url: "https://connect.emby.media/service/user/authenticate",
|
||||
data: {
|
||||
nameOrEmail: username,
|
||||
rawpw: password
|
||||
},
|
||||
dataType: "json",
|
||||
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
}).then(function(result) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
return credentials.ConnectAccessToken = result.AccessToken, credentials.ConnectUserId = result.User.Id, credentialProvider.credentials(credentials), onConnectUserSignIn(result.User), result
|
||||
}) : Promise.reject()
|
||||
}, self.signupForConnect = function(options) {
|
||||
var email = options.email,
|
||||
username = options.username,
|
||||
password = options.password,
|
||||
passwordConfirm = options.passwordConfirm;
|
||||
if (!email) return Promise.reject({
|
||||
errorCode: "invalidinput"
|
||||
});
|
||||
if (!username) return Promise.reject({
|
||||
errorCode: "invalidinput"
|
||||
});
|
||||
if (!password) return Promise.reject({
|
||||
errorCode: "invalidinput"
|
||||
});
|
||||
if (!passwordConfirm) return Promise.reject({
|
||||
errorCode: "passwordmatch"
|
||||
});
|
||||
if (password !== passwordConfirm) return Promise.reject({
|
||||
errorCode: "passwordmatch"
|
||||
});
|
||||
var data = {
|
||||
email: email,
|
||||
userName: username,
|
||||
rawpw: password
|
||||
};
|
||||
return options.grecaptcha && (data.grecaptcha = options.grecaptcha), ajax({
|
||||
type: "POST",
|
||||
url: "https://connect.emby.media/service/register",
|
||||
data: data,
|
||||
dataType: "json",
|
||||
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion,
|
||||
"X-CONNECT-TOKEN": "CONNECT-REGISTER"
|
||||
}
|
||||
}).catch(function(response) {
|
||||
try {
|
||||
return response.json()
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
}).then(function(result) {
|
||||
if (result && result.Status) return "SUCCESS" === result.Status ? Promise.resolve(result) : Promise.reject({
|
||||
errorCode: result.Status
|
||||
});
|
||||
Promise.reject()
|
||||
})
|
||||
}, self.getUserInvitations = function() {
|
||||
var connectToken = self.connectToken();
|
||||
if (!connectToken) throw new Error("null connectToken");
|
||||
if (!self.connectUserId()) throw new Error("null connectUserId");
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: "https://connect.emby.media/service/servers?userId=" + self.connectUserId() + "&status=Waiting",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Connect-UserToken": connectToken,
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
})
|
||||
}, self.deleteServer = function(serverId) {
|
||||
if (!serverId) throw new Error("null serverId");
|
||||
var server = credentialProvider.credentials().Servers.filter(function(s) {
|
||||
return s.Id === serverId
|
||||
});
|
||||
return server = server.length ? server[0] : null, new Promise(function(resolve, reject) {
|
||||
function onDone() {
|
||||
var credentials = credentialProvider.credentials();
|
||||
credentials.Servers = credentials.Servers.filter(function(s) {
|
||||
return s.Id !== serverId
|
||||
}), credentialProvider.credentials(credentials), resolve()
|
||||
}
|
||||
if (!server.ConnectServerId) return void onDone();
|
||||
var connectToken = self.connectToken(),
|
||||
connectUserId = self.connectUserId();
|
||||
if (!connectToken || !connectUserId) return void onDone();
|
||||
ajax({
|
||||
type: "DELETE",
|
||||
url: "https://connect.emby.media/service/serverAuthorizations?serverId=" + server.ConnectServerId + "&userId=" + connectUserId,
|
||||
headers: {
|
||||
"X-Connect-UserToken": connectToken,
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
}).then(onDone, onDone)
|
||||
})
|
||||
}, self.rejectServer = function(serverId) {
|
||||
var connectToken = self.connectToken();
|
||||
if (!serverId) throw new Error("null serverId");
|
||||
if (!connectToken) throw new Error("null connectToken");
|
||||
if (!self.connectUserId()) throw new Error("null connectUserId");
|
||||
var url = "https://connect.emby.media/service/serverAuthorizations?serverId=" + serverId + "&userId=" + self.connectUserId();
|
||||
return fetch(url, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"X-Connect-UserToken": connectToken,
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
})
|
||||
}, self.acceptServer = function(serverId) {
|
||||
var connectToken = self.connectToken();
|
||||
if (!serverId) throw new Error("null serverId");
|
||||
if (!connectToken) throw new Error("null connectToken");
|
||||
if (!self.connectUserId()) throw new Error("null connectUserId");
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: "https://connect.emby.media/service/ServerAuthorizations/accept?serverId=" + serverId + "&userId=" + self.connectUserId(),
|
||||
headers: {
|
||||
"X-Connect-UserToken": connectToken,
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
})
|
||||
}, self.resetRegistrationInfo = function(apiClient) {
|
||||
var cacheKey = getCacheKey("themes", apiClient, {
|
||||
viewOnly: !0
|
||||
});
|
||||
appStorage.removeItem(cacheKey), cacheKey = getCacheKey("themes", apiClient, {
|
||||
viewOnly: !1
|
||||
}), appStorage.removeItem(cacheKey)
|
||||
}, self.getRegistrationInfo = function(feature, apiClient, options) {
|
||||
var cacheKey = getCacheKey(feature, apiClient, options);
|
||||
appStorage.setItem(cacheKey, JSON.stringify({
|
||||
lastValidDate: new Date().getTime(),
|
||||
deviceId: self.deviceId()
|
||||
}));
|
||||
return Promise.resolve();
|
||||
}, self.createPin = function() {
|
||||
var request = {
|
||||
type: "POST",
|
||||
url: getConnectUrl("pin"),
|
||||
data: {
|
||||
deviceId: deviceId
|
||||
},
|
||||
dataType: "json"
|
||||
};
|
||||
return addAppInfoToConnectRequest(request), ajax(request)
|
||||
}, self.getPinStatus = function(pinInfo) {
|
||||
if (!pinInfo) throw new Error("pinInfo cannot be null");
|
||||
var queryString = {
|
||||
deviceId: pinInfo.DeviceId,
|
||||
pin: pinInfo.Pin
|
||||
},
|
||||
request = {
|
||||
type: "GET",
|
||||
url: getConnectUrl("pin") + "?" + paramsToString(queryString),
|
||||
dataType: "json"
|
||||
};
|
||||
return addAppInfoToConnectRequest(request), ajax(request)
|
||||
}, self.exchangePin = function(pinInfo) {
|
||||
if (!pinInfo) throw new Error("pinInfo cannot be null");
|
||||
return exchangePin(pinInfo).then(function(result) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
return credentials.ConnectAccessToken = result.AccessToken, credentials.ConnectUserId = result.UserId, credentialProvider.credentials(credentials), ensureConnectUser(credentials)
|
||||
})
|
||||
}
|
||||
};
|
||||
return ConnectionManager.prototype.connect = function(options) {
|
||||
console.log("Begin connect");
|
||||
var instance = this;
|
||||
return instance.getAvailableServers().then(function(servers) {
|
||||
return instance.connectToServers(servers, options)
|
||||
})
|
||||
}, ConnectionManager.prototype.isLoggedIntoConnect = function() {
|
||||
return !(!this.connectToken() || !this.connectUserId())
|
||||
}, ConnectionManager.prototype.getApiClients = function() {
|
||||
for (var servers = this.getSavedServers(), i = 0, length = servers.length; i < length; i++) {
|
||||
var server = servers[i];
|
||||
server.Id && this._getOrAddApiClient(server, getServerAddress(server, server.LastConnectionMode))
|
||||
}
|
||||
return this._apiClients
|
||||
}, ConnectionManager.prototype.getApiClient = function(item) {
|
||||
if (!item) throw new Error("item or serverId cannot be null");
|
||||
return item.ServerId && (item = item.ServerId), this._apiClients.filter(function(a) {
|
||||
var serverInfo = a.serverInfo();
|
||||
return !serverInfo || serverInfo.Id === item
|
||||
})[0]
|
||||
}, ConnectionManager.prototype.minServerVersion = function(val) {
|
||||
return val && (this._minServerVersion = val), this._minServerVersion
|
||||
}, ConnectionManager.prototype.handleMessageReceived = function(msg) {
|
||||
var serverId = msg.ServerId;
|
||||
if (serverId) {
|
||||
var apiClient = this.getApiClient(serverId);
|
||||
if (apiClient) {
|
||||
if ("string" == typeof msg.Data) try {
|
||||
msg.Data = JSON.parse(msg.Data)
|
||||
} catch (err) {}
|
||||
apiClient.handleMessageReceived(msg)
|
||||
}
|
||||
}
|
||||
}, ConnectionManager
|
||||
});
|
||||
@@ -4,7 +4,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
function ensure(instance, data) {
|
||||
if (!instance._credentials) {
|
||||
var json = appStorage.getItem(instance.key) || "{}";
|
||||
console.debug("credentials initialized with: " + json), instance._credentials = JSON.parse(json), instance._credentials.Servers = instance._credentials.Servers || []
|
||||
console.log("credentials initialized with: " + json), instance._credentials = JSON.parse(json), instance._credentials.Servers = instance._credentials.Servers || []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,4 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||
})[0];
|
||||
return existing ? (existing.DateLastAccessed = Math.max(existing.DateLastAccessed || 0, server.DateLastAccessed || 0), existing.UserLinkType = server.UserLinkType, server.AccessToken && (existing.AccessToken = server.AccessToken, existing.UserId = server.UserId), server.ExchangeToken && (existing.ExchangeToken = server.ExchangeToken), server.RemoteAddress && (existing.RemoteAddress = server.RemoteAddress), server.ManualAddress && (existing.ManualAddress = server.ManualAddress), server.LocalAddress && (existing.LocalAddress = server.LocalAddress), server.Name && (existing.Name = server.Name), null != server.LastConnectionMode && (existing.LastConnectionMode = server.LastConnectionMode), server.ConnectServerId && (existing.ConnectServerId = server.ConnectServerId), existing) : (list.push(server), server)
|
||||
}, Credentials
|
||||
});
|
||||
});
|
||||
@@ -27,4 +27,4 @@ define([], function() {
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -2,7 +2,7 @@ define(["filerepository", "itemrepository", "useractionrepository", "transferman
|
||||
"use strict";
|
||||
|
||||
function getLocalItem(serverId, itemId) {
|
||||
return console.debug("localassetmanager: begin getLocalItem"), itemrepository.get(serverId, itemId)
|
||||
return console.log("[lcoalassetmanager] Begin getLocalItem"), itemrepository.get(serverId, itemId)
|
||||
}
|
||||
|
||||
function recordUserAction(action) {
|
||||
@@ -25,7 +25,7 @@ define(["filerepository", "itemrepository", "useractionrepository", "transferman
|
||||
}
|
||||
|
||||
function getServerItems(serverId) {
|
||||
return console.debug("localassetmanager: begin getServerItems"), itemrepository.getAll(serverId)
|
||||
return console.log("[localassetmanager] Begin getServerItems"), itemrepository.getAll(serverId)
|
||||
}
|
||||
|
||||
function getItemsFromIds(serverId, ids) {
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"main": "apiclient.js"
|
||||
}
|
||||
}
|
||||
@@ -42,4 +42,4 @@ define([], function() {
|
||||
getItemFileSize: getItemFileSize,
|
||||
getImageUrl: getImageUrl
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -120,4 +120,4 @@ define([], function() {
|
||||
getAll: getAll,
|
||||
getServerItemTypes: getServerItemTypes
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -3,7 +3,7 @@ define(["connectionManager"], function(connectionManager) {
|
||||
var isSyncing;
|
||||
return {
|
||||
sync: function(options) {
|
||||
return console.debug("localSync.sync starting..."), isSyncing ? Promise.resolve() : (isSyncing = !0, new Promise(function(resolve, reject) {
|
||||
return console.log("localSync.sync starting..."), isSyncing ? Promise.resolve() : (isSyncing = !0, new Promise(function(resolve, reject) {
|
||||
require(["multiserversync", "appSettings"], function(MultiServerSync, appSettings) {
|
||||
options = options || {}, options.cameraUploadServers = appSettings.cameraUploadServers(), (new MultiServerSync).sync(connectionManager, options).then(function() {
|
||||
isSyncing = null, resolve()
|
||||
@@ -14,4 +14,4 @@ define(["connectionManager"], function(connectionManager) {
|
||||
}))
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -2,9 +2,9 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
"use strict";
|
||||
|
||||
function processDownloadStatus(apiClient, serverInfo, options) {
|
||||
return console.debug("mediasync: begin processDownloadStatus"), localassetmanager.resyncTransfers().then(function() {
|
||||
return console.log("[mediasync] Begin processDownloadStatus"), localassetmanager.resyncTransfers().then(function() {
|
||||
return localassetmanager.getServerItems(serverInfo.Id).then(function(items) {
|
||||
console.debug("mediasync: begin processDownloadStatus getServerItems completed");
|
||||
console.log("[mediasync] Begin processDownloadStatus getServerItems completed");
|
||||
var p = Promise.resolve(),
|
||||
cnt = 0;
|
||||
return items.filter(function(item) {
|
||||
@@ -14,9 +14,7 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
return reportTransfer(apiClient, item)
|
||||
}), cnt++
|
||||
}), p.then(function() {
|
||||
console.debug("mediasync: exit processDownloadStatus");
|
||||
console.debug("items reported: " + cnt.toString());
|
||||
return Promise.resolve();
|
||||
return console.log("[mediasync] Exit processDownloadStatus. Items reported: " + cnt.toString()), Promise.resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -25,39 +23,39 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
function reportTransfer(apiClient, item) {
|
||||
return localassetmanager.getItemFileSize(item.LocalPath).then(function(size) {
|
||||
return size > 0 ? apiClient.reportSyncJobItemTransferred(item.SyncJobItemId).then(function() {
|
||||
return item.SyncStatus = "synced", console.debug("mediasync: reportSyncJobItemTransferred called for " + item.LocalPath), localassetmanager.addOrUpdateLocalItem(item)
|
||||
return item.SyncStatus = "synced", console.log("[mediasync] reportSyncJobItemTransferred called for " + item.LocalPath), localassetmanager.addOrUpdateLocalItem(item)
|
||||
}, function(error) {
|
||||
return console.error("mediasync: mediasync error on reportSyncJobItemTransferred", error), item.SyncStatus = "error", localassetmanager.addOrUpdateLocalItem(item)
|
||||
return console.error("[mediasync] Mediasync error on reportSyncJobItemTransferred", error), item.SyncStatus = "error", localassetmanager.addOrUpdateLocalItem(item)
|
||||
}) : localassetmanager.isDownloadFileInQueue(item.LocalPath).then(function(result) {
|
||||
return result ? Promise.resolve() : (console.debug("mediasync: reportTransfer: Size is 0 and download no longer in queue. Deleting item."), localassetmanager.removeLocalItem(item).then(function() {
|
||||
return console.debug("mediasync: reportTransfer: Item deleted."), Promise.resolve()
|
||||
return result ? Promise.resolve() : (console.log("[mediasync] reportTransfer: Size is 0 and download no longer in queue. Deleting item."), localassetmanager.removeLocalItem(item).then(function() {
|
||||
return console.log("[mediasync] reportTransfer: Item deleted."), Promise.resolve()
|
||||
}, function(err2) {
|
||||
return console.debug("mediasync: reportTransfer: Failed to delete item.", err2), Promise.resolve()
|
||||
return console.log("[mediasync] reportTransfer: Failed to delete item.", err2), Promise.resolve()
|
||||
}))
|
||||
})
|
||||
}, function(error) {
|
||||
return console.error("mediasync: reportTransfer: error on getItemFileSize. Deleting item.", error), localassetmanager.removeLocalItem(item).then(function() {
|
||||
return console.debug("mediasync: reportTransfer: Item deleted."), Promise.resolve()
|
||||
return console.error("[mediasync] reportTransfer: error on getItemFileSize. Deleting item.", error), localassetmanager.removeLocalItem(item).then(function() {
|
||||
return console.log("[mediasync] reportTransfer: Item deleted."), Promise.resolve()
|
||||
}, function(err2) {
|
||||
return console.error("mediasync: reportTransfer: Failed to delete item.", err2), Promise.resolve()
|
||||
return console.log("[mediasync] reportTransfer: Failed to delete item.", err2), Promise.resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function reportOfflineActions(apiClient, serverInfo) {
|
||||
return console.debug("mediasync: begin reportOfflineActions"), localassetmanager.getUserActions(serverInfo.Id).then(function(actions) {
|
||||
return console.log("[mediasync] Begin reportOfflineActions"), localassetmanager.getUserActions(serverInfo.Id).then(function(actions) {
|
||||
return actions.length ? apiClient.reportOfflineActions(actions).then(function() {
|
||||
return localassetmanager.deleteUserActions(actions).then(function() {
|
||||
return console.debug("mediasync: exit reportOfflineActions (actions reported and deleted.)"), Promise.resolve()
|
||||
return console.log("[mediasync] Exit reportOfflineActions (actions reported and deleted.)"), Promise.resolve()
|
||||
})
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error on apiClient.reportOfflineActions: " + err.toString()), localassetmanager.deleteUserActions(actions)
|
||||
}) : (console.debug("mediasync: exit reportOfflineActions (no actions)"), Promise.resolve())
|
||||
return console.error("[mediasync] error on apiClient.reportOfflineActions: " + err.toString()), localassetmanager.deleteUserActions(actions)
|
||||
}) : (console.log("[mediasync] Exit reportOfflineActions (no actions)"), Promise.resolve())
|
||||
})
|
||||
}
|
||||
|
||||
function syncData(apiClient, serverInfo) {
|
||||
return console.debug("mediasync: begin syncData"), localassetmanager.getServerItems(serverInfo.Id).then(function(items) {
|
||||
return console.log("[mediasync] Begin syncData"), localassetmanager.getServerItems(serverInfo.Id).then(function(items) {
|
||||
var completedItems = items.filter(function(item) {
|
||||
return item && ("synced" === item.SyncStatus || "error" === item.SyncStatus)
|
||||
}),
|
||||
@@ -69,16 +67,16 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
};
|
||||
return apiClient.syncData(request).then(function(result) {
|
||||
return afterSyncData(apiClient, serverInfo, result).then(function() {
|
||||
return console.debug("mediasync: exit syncData"), Promise.resolve()
|
||||
return console.log("[mediasync] Exit syncData"), Promise.resolve()
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error in syncData: " + err.toString()), Promise.resolve()
|
||||
return console.error("[mediasync] Error in syncData: " + err.toString()), Promise.resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function afterSyncData(apiClient, serverInfo, syncDataResult) {
|
||||
console.debug("mediasync: begin afterSyncData");
|
||||
console.log("[mediasync] Begin afterSyncData");
|
||||
var p = Promise.resolve();
|
||||
return syncDataResult.ItemIdsToRemove && syncDataResult.ItemIdsToRemove.length > 0 && syncDataResult.ItemIdsToRemove.forEach(function(itemId) {
|
||||
p = p.then(function() {
|
||||
@@ -87,25 +85,25 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
}), p = p.then(function() {
|
||||
return removeObsoleteContainerItems(serverInfo.Id)
|
||||
}), p.then(function() {
|
||||
return console.debug("mediasync: exit afterSyncData"), Promise.resolve()
|
||||
return console.log("[mediasync] Exit afterSyncData"), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function removeObsoleteContainerItems(serverId) {
|
||||
return console.debug("mediasync: begin removeObsoleteContainerItems"), localassetmanager.removeObsoleteContainerItems(serverId)
|
||||
return console.log("[mediasync] Begin removeObsoleteContainerItems"), localassetmanager.removeObsoleteContainerItems(serverId)
|
||||
}
|
||||
|
||||
function removeLocalItem(itemId, serverId) {
|
||||
return console.debug("mediasync: begin removeLocalItem"), localassetmanager.getLocalItem(serverId, itemId).then(function(item) {
|
||||
return console.log("[mediasync] Begin removeLocalItem"), localassetmanager.getLocalItem(serverId, itemId).then(function(item) {
|
||||
return item ? localassetmanager.removeLocalItem(item) : Promise.resolve()
|
||||
}, function(err2) {
|
||||
return console.error("mediasync: removeLocalItem: Failed: ", err2), Promise.resolve()
|
||||
return console.error("[mediasync] removeLocalItem: Failed: ", err2), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function getNewMedia(apiClient, downloadCount) {
|
||||
return console.debug("mediasync: begin getNewMedia"), apiClient.getReadySyncItems(apiClient.deviceId()).then(function(jobItems) {
|
||||
console.debug("mediasync: getReadySyncItems returned " + jobItems.length + " items");
|
||||
return console.log("[mediasync] Begin getNewMedia"), apiClient.getReadySyncItems(apiClient.deviceId()).then(function(jobItems) {
|
||||
console.log("[mediasync] getReadySyncItems returned " + jobItems.length + " items");
|
||||
var p = Promise.resolve(),
|
||||
currentCount = downloadCount;
|
||||
return jobItems.forEach(function(jobItem) {
|
||||
@@ -113,15 +111,15 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
return getNewItem(jobItem, apiClient)
|
||||
}))
|
||||
}), p.then(function() {
|
||||
return console.debug("mediasync: exit getNewMedia"), Promise.resolve()
|
||||
return console.log("[mediasync] Exit getNewMedia"), Promise.resolve()
|
||||
})
|
||||
}, function(err) {
|
||||
return console.error("mediasync: getReadySyncItems: Failed: ", err), Promise.resolve()
|
||||
return console.error("[mediasync] getReadySyncItems: Failed: ", err), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function afterMediaDownloaded(apiClient, jobItem, localItem) {
|
||||
return console.debug("mediasync: begin afterMediaDownloaded"), getImages(apiClient, jobItem, localItem).then(function() {
|
||||
return console.log("[mediasync] Begin afterMediaDownloaded"), getImages(apiClient, jobItem, localItem).then(function() {
|
||||
var libraryItem = jobItem.Item;
|
||||
return downloadParentItems(apiClient, jobItem, libraryItem).then(function() {
|
||||
return getSubtitles(apiClient, jobItem, localItem)
|
||||
@@ -130,21 +128,21 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
}
|
||||
|
||||
function createLocalItem(libraryItem, jobItem) {
|
||||
console.debug("localassetmanager: begin createLocalItem");
|
||||
console.log("[localassetmanager] Begin createLocalItem");
|
||||
var item = {
|
||||
Item: libraryItem,
|
||||
ItemId: libraryItem.Id,
|
||||
ServerId: libraryItem.ServerId,
|
||||
Id: libraryItem.Id
|
||||
};
|
||||
return jobItem && (item.SyncJobItemId = jobItem.SyncJobItemId), console.debug("localassetmanager: end createLocalItem"), item
|
||||
return jobItem && (item.SyncJobItemId = jobItem.SyncJobItemId), console.log("[localassetmanager] End createLocalItem"), item
|
||||
}
|
||||
|
||||
function getNewItem(jobItem, apiClient) {
|
||||
console.debug("mediasync: begin getNewItem");
|
||||
console.log("[mediasync] Begin getNewItem");
|
||||
var libraryItem = jobItem.Item;
|
||||
return localassetmanager.getLocalItem(libraryItem.ServerId, libraryItem.Id).then(function(existingItem) {
|
||||
if (existingItem && ("queued" === existingItem.SyncStatus || "transferring" === existingItem.SyncStatus || "synced" === existingItem.SyncStatus) && (console.debug("mediasync: getNewItem: getLocalItem found existing item"), localassetmanager.enableBackgroundCompletion())) return Promise.resolve();
|
||||
if (existingItem && ("queued" === existingItem.SyncStatus || "transferring" === existingItem.SyncStatus || "synced" === existingItem.SyncStatus) && (console.log("[mediasync] getNewItem: getLocalItem found existing item"), localassetmanager.enableBackgroundCompletion())) return Promise.resolve();
|
||||
libraryItem.CanDelete = !1, libraryItem.CanDownload = !1, libraryItem.SupportsSync = !1, libraryItem.People = [], libraryItem.Chapters = [], libraryItem.Studios = [], libraryItem.SpecialFeatureCount = null, libraryItem.LocalTrailerCount = null, libraryItem.RemoteTrailers = [];
|
||||
var localItem = createLocalItem(libraryItem, jobItem);
|
||||
return localItem.SyncStatus = "queued", downloadMedia(apiClient, jobItem, localItem)
|
||||
@@ -171,7 +169,7 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
return localassetmanager.addOrUpdateLocalItem(localItem).then(function() {
|
||||
return Promise.resolve(localItem)
|
||||
}, function(err) {
|
||||
return console.error("mediasync: downloadItem failed: " + err.toString()), Promise.resolve(null)
|
||||
return console.error("[mediasync] downloadItem failed: " + err.toString()), Promise.resolve(null)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -185,12 +183,12 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
}
|
||||
|
||||
function downloadMedia(apiClient, jobItem, localItem) {
|
||||
console.debug("mediasync: downloadMedia: start.");
|
||||
console.log("[mediasync] downloadMedia: start.");
|
||||
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/File", {
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
return ensureLocalPathParts(localItem, jobItem), localassetmanager.downloadFile(url, localItem).then(function(result) {
|
||||
console.debug("mediasync: downloadMedia-downloadFile returned path: " + result.path);
|
||||
console.log("[mediasync] downloadMedia-downloadFile returned path: " + result.path);
|
||||
var localPath = result.path,
|
||||
libraryItem = localItem.Item;
|
||||
if (localPath && libraryItem.MediaSources)
|
||||
@@ -202,18 +200,18 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
return afterMediaDownloaded(apiClient, jobItem, localItem).then(function() {
|
||||
return result.isComplete ? (localItem.SyncStatus = "synced", reportTransfer(apiClient, localItem)) : Promise.resolve()
|
||||
}, function(err) {
|
||||
return console.debug("mediasync: downloadMedia: afterMediaDownloaded failed: " + err), Promise.reject(err)
|
||||
return console.log("[mediasync] downloadMedia: afterMediaDownloaded failed: " + err), Promise.reject(err)
|
||||
})
|
||||
}, function(err) {
|
||||
return console.debug("mediasync: downloadMedia: addOrUpdateLocalItem failed: " + err), Promise.reject(err)
|
||||
return console.log("[mediasync] downloadMedia: addOrUpdateLocalItem failed: " + err), Promise.reject(err)
|
||||
})
|
||||
}, function(err) {
|
||||
return console.debug("mediasync: downloadMedia: localassetmanager.downloadFile failed: " + err), Promise.reject(err)
|
||||
return console.log("[mediasync] downloadMedia: localassetmanager.downloadFile failed: " + err), Promise.reject(err)
|
||||
})
|
||||
}
|
||||
|
||||
function getImages(apiClient, jobItem, localItem) {
|
||||
console.debug("mediasync: begin getImages");
|
||||
console.log("[mediasync] Begin getImages");
|
||||
var p = Promise.resolve(),
|
||||
libraryItem = localItem.Item,
|
||||
serverId = libraryItem.ServerId,
|
||||
@@ -251,15 +249,15 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
})), libraryItem.ParentPrimaryImageItemId && libraryItem.ParentPrimaryImageTag && (p = p.then(function() {
|
||||
return downloadImage(localItem, apiClient, serverId, libraryItem.ParentPrimaryImageItemId, libraryItem.ParentPrimaryImageTag, "Primary")
|
||||
})), p.then(function() {
|
||||
return console.debug("mediasync: finished getImages"), localassetmanager.addOrUpdateLocalItem(localItem)
|
||||
return console.log("[mediasync] Finished getImages"), localassetmanager.addOrUpdateLocalItem(localItem)
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error getImages: " + err.toString()), Promise.resolve()
|
||||
return console.log("[mediasync] Error getImages: " + err.toString()), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function downloadImage(localItem, apiClient, serverId, itemId, imageTag, imageType, index) {
|
||||
return index = index || 0, localassetmanager.hasImage(serverId, itemId, imageType, index).then(function(hasImage) {
|
||||
if (hasImage) return console.debug("mediasync: downloadImage - skip existing: " + itemId + " " + imageType + "_" + index.toString()), Promise.resolve();
|
||||
if (hasImage) return console.log("[mediasync] downloadImage - skip existing: " + itemId + " " + imageType + "_" + index.toString()), Promise.resolve();
|
||||
var maxWidth = 400;
|
||||
"backdrop" === imageType && (maxWidth = null);
|
||||
var imageUrl = apiClient.getScaledImageUrl(itemId, {
|
||||
@@ -268,18 +266,18 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
maxWidth: maxWidth,
|
||||
api_key: apiClient.accessToken()
|
||||
});
|
||||
return console.debug("mediasync: downloadImage " + itemId + " " + imageType + "_" + index.toString()), localassetmanager.downloadImage(localItem, imageUrl, serverId, itemId, imageType, index).then(function(result) {
|
||||
return console.log("[mediasync] downloadImage " + itemId + " " + imageType + "_" + index.toString()), localassetmanager.downloadImage(localItem, imageUrl, serverId, itemId, imageType, index).then(function(result) {
|
||||
return Promise.resolve(result)
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error downloadImage: " + err.toString()), Promise.resolve()
|
||||
return console.log("[mediasync] Error downloadImage: " + err.toString()), Promise.resolve()
|
||||
})
|
||||
}, function(err) {
|
||||
return console.error("mediasync: error downloadImage: " + err.toString()), Promise.resolve()
|
||||
return console.log("[mediasync] Error downloadImage: " + err.toString()), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function getSubtitles(apiClient, jobItem, localItem) {
|
||||
if (console.debug("mediasync: begin getSubtitles"), !jobItem.Item.MediaSources.length) return console.debug("mediasync: cannot download subtitles because video has no media source info."), Promise.resolve();
|
||||
if (console.log("[mediasync] Begin getSubtitles"), !jobItem.Item.MediaSources.length) return console.log("[mediasync] Cannot download subtitles because video has no media source info."), Promise.resolve();
|
||||
var files = jobItem.AdditionalFiles.filter(function(f) {
|
||||
return "Subtitles" === f.Type
|
||||
}),
|
||||
@@ -290,16 +288,16 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
return getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource)
|
||||
})
|
||||
}), p.then(function() {
|
||||
return console.debug("mediasync: exit getSubtitles"), Promise.resolve()
|
||||
return console.log("[mediasync] Exit getSubtitles"), Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) {
|
||||
console.debug("mediasync: begin getItemSubtitle");
|
||||
console.log("[mediasync] Begin getItemSubtitle");
|
||||
var subtitleStream = mediaSource.MediaStreams.filter(function(m) {
|
||||
return "Subtitle" === m.Type && m.Index === file.Index
|
||||
})[0];
|
||||
if (!subtitleStream) return console.debug("mediasync: cannot download subtitles because matching stream info was not found."), Promise.resolve();
|
||||
if (!subtitleStream) return console.log("[mediasync] Cannot download subtitles because matching stream info was not found."), Promise.resolve();
|
||||
var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/AdditionalFiles", {
|
||||
Name: file.Name,
|
||||
api_key: apiClient.accessToken()
|
||||
@@ -313,7 +311,7 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
}
|
||||
|
||||
function checkLocalFileExistence(apiClient, serverInfo, options) {
|
||||
return options.checkFileExistence ? (console.debug("mediasync: begin checkLocalFileExistence"), localassetmanager.getServerItems(serverInfo.Id).then(function(items) {
|
||||
return options.checkFileExistence ? (console.log("[mediasync] Begin checkLocalFileExistence"), localassetmanager.getServerItems(serverInfo.Id).then(function(items) {
|
||||
var completedItems = items.filter(function(item) {
|
||||
return item && ("synced" === item.SyncStatus || "error" === item.SyncStatus)
|
||||
}),
|
||||
@@ -334,13 +332,13 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
return function() {
|
||||
var self = this;
|
||||
"string" == typeof webWorkerBaseUrl && -1 !== webWorkerBaseUrl.indexOf("ms-appx://") ? self.sync = function(apiClient, serverInfo, options) {
|
||||
return console.debug("mediasync: start sync"), checkLocalFileExistence(apiClient, serverInfo, options).then(function() {
|
||||
return console.log("[mediasync]************************************* Start sync"), checkLocalFileExistence(apiClient, serverInfo, options).then(function() {
|
||||
return processDownloadStatus(apiClient, serverInfo, options).then(function() {
|
||||
return localassetmanager.getDownloadItemCount().then(function(downloadCount) {
|
||||
return !0 === options.syncCheckProgressOnly && downloadCount > 2 ? Promise.resolve() : reportOfflineActions(apiClient, serverInfo).then(function() {
|
||||
return getNewMedia(apiClient, downloadCount).then(function() {
|
||||
return syncData(apiClient, serverInfo).then(function() {
|
||||
return console.debug("mediasync: Exit sync"), Promise.resolve()
|
||||
return console.log("[mediasync]************************************* Exit sync"), Promise.resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -350,7 +348,7 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
console.error(err.toString())
|
||||
})
|
||||
} : self.sync = function(apiClient, serverInfo, options) {
|
||||
return console.debug("mediasync: Start sync"), checkLocalFileExistence(apiClient, serverInfo, options).then(function() {
|
||||
return console.log("[mediasync]************************************* Start sync"), checkLocalFileExistence(apiClient, serverInfo, options).then(function() {
|
||||
return syncData(apiClient, serverInfo).then(function() {
|
||||
return processDownloadStatus(apiClient, serverInfo, options).then(function() {
|
||||
return localassetmanager.getDownloadItemCount().then(function(downloadCount) {
|
||||
@@ -367,4 +365,4 @@ define(["localassetmanager"], function(localassetmanager) {
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
22
src/bower_components/apiclient/sync/multiserversync.js
vendored
Normal file
22
src/bower_components/apiclient/sync/multiserversync.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
define(["serversync"], function(ServerSync) {
|
||||
"use strict";
|
||||
|
||||
function syncNext(connectionManager, servers, index, options, resolve, reject) {
|
||||
var length = servers.length;
|
||||
if (index >= length) return console.log("MultiServerSync.sync complete"), void resolve();
|
||||
var server = servers[index];
|
||||
console.log("Creating ServerSync to server: " + server.Id), (new ServerSync).sync(connectionManager, server, options).then(function() {
|
||||
console.log("ServerSync succeeded to server: " + server.Id), syncNext(connectionManager, servers, index + 1, options, resolve, reject)
|
||||
}, function(err) {
|
||||
console.log("ServerSync failed to server: " + server.Id + ". " + err), syncNext(connectionManager, servers, index + 1, options, resolve, reject)
|
||||
})
|
||||
}
|
||||
|
||||
function MultiServerSync() {}
|
||||
return MultiServerSync.prototype.sync = function(connectionManager, options) {
|
||||
return console.log("MultiServerSync.sync starting..."), new Promise(function(resolve, reject) {
|
||||
var servers = connectionManager.getSavedServers();
|
||||
syncNext(connectionManager, servers, 0, options, resolve, reject)
|
||||
})
|
||||
}, MultiServerSync
|
||||
});
|
||||
@@ -2,11 +2,11 @@ define([], function() {
|
||||
"use strict";
|
||||
|
||||
function performSync(connectionManager, server, options) {
|
||||
console.debug("ServerSync.performSync to server: " + server.Id), options = options || {};
|
||||
console.log("ServerSync.performSync to server: " + server.Id), options = options || {};
|
||||
var cameraUploadServers = options.cameraUploadServers || [];
|
||||
console.debug("ServerSync cameraUploadServers: " + JSON.stringify(cameraUploadServers));
|
||||
console.log("ServerSync cameraUploadServers: " + JSON.stringify(cameraUploadServers));
|
||||
var uploadPhotos = -1 !== cameraUploadServers.indexOf(server.Id);
|
||||
return console.debug("ServerSync uploadPhotos: " + uploadPhotos), (uploadPhotos ? uploadContent(connectionManager, server, options) : Promise.resolve()).then(function() {
|
||||
return console.log("ServerSync uploadPhotos: " + uploadPhotos), (uploadPhotos ? uploadContent(connectionManager, server, options) : Promise.resolve()).then(function() {
|
||||
return syncMedia(connectionManager, server, options)
|
||||
})
|
||||
}
|
||||
@@ -26,7 +26,7 @@ define([], function() {
|
||||
|
||||
function ServerSync() {}
|
||||
return ServerSync.prototype.sync = function(connectionManager, server, options) {
|
||||
if (!server.AccessToken && !server.ExchangeToken) return console.debug("Skipping sync to server " + server.Id + " because there is no saved authentication information."), Promise.resolve();
|
||||
if (!server.AccessToken && !server.ExchangeToken) return console.log("Skipping sync to server " + server.Id + " because there is no saved authentication information."), Promise.resolve();
|
||||
var connectionOptions = {
|
||||
updateDateLastAccessed: !1,
|
||||
enableWebSocket: !1,
|
||||
@@ -34,9 +34,9 @@ define([], function() {
|
||||
enableAutomaticBitrateDetection: !1
|
||||
};
|
||||
return connectionManager.connectToServer(server, connectionOptions).then(function(result) {
|
||||
return "SignedIn" === result.State ? performSync(connectionManager, server, options) : (console.error("Unable to connect to server id: " + server.Id), Promise.reject())
|
||||
return "SignedIn" === result.State ? performSync(connectionManager, server, options) : (console.log("Unable to connect to server id: " + server.Id), Promise.reject())
|
||||
}, function(err) {
|
||||
throw console.error("Unable to connect to server id: " + server.Id), err
|
||||
throw console.log("Unable to connect to server id: " + server.Id), err
|
||||
})
|
||||
}, ServerSync
|
||||
});
|
||||
});
|
||||
@@ -27,4 +27,4 @@ define([], function() {
|
||||
resyncTransfers: resyncTransfers,
|
||||
getDownloadItemCount: getDownloadItemCount
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -105,4 +105,4 @@ define([], function() {
|
||||
getAll: getAll,
|
||||
getByServerId: getByServerId
|
||||
}
|
||||
});
|
||||
});
|
||||
12
src/bower_components/document-register-element/basic.html
vendored
Normal file
12
src/bower_components/document-register-element/basic.html
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>testing my-element</title>
|
||||
<script src="build/document-register-element.js"></script>
|
||||
<script src="test/my-element.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<my-element>
|
||||
some content
|
||||
</my-element>
|
||||
</body>
|
||||
246
src/bower_components/document-register-element/build/document-register-element.js
vendored
Normal file
246
src/bower_components/document-register-element/build/document-register-element.js
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
/*! (C) WebReflection Mit Style License */
|
||||
(function(e, t, n, r) {
|
||||
"use strict";
|
||||
|
||||
function rt(e, t) {
|
||||
for (var n = 0, r = e.length; n < r; n++) vt(e[n], t)
|
||||
}
|
||||
|
||||
function it(e) {
|
||||
for (var t = 0, n = e.length, r; t < n; t++) r = e[t], nt(r, b[ot(r)])
|
||||
}
|
||||
|
||||
function st(e) {
|
||||
return function(t) {
|
||||
j(t) && (vt(t, e), rt(t.querySelectorAll(w), e))
|
||||
}
|
||||
}
|
||||
|
||||
function ot(e) {
|
||||
var t = e.getAttribute("is"),
|
||||
n = e.nodeName.toUpperCase(),
|
||||
r = S.call(y, t ? v + t.toUpperCase() : d + n);
|
||||
return t && -1 < r && !ut(n, t) ? -1 : r
|
||||
}
|
||||
|
||||
function ut(e, t) {
|
||||
return -1 < w.indexOf(e + '[is="' + t + '"]')
|
||||
}
|
||||
|
||||
function at(e) {
|
||||
var t = e.currentTarget,
|
||||
n = e.attrChange,
|
||||
r = e.attrName,
|
||||
i = e.target;
|
||||
Q && (!i || i === t) && t.attributeChangedCallback && r !== "style" && e.prevValue !== e.newValue && t.attributeChangedCallback(r, n === e[a] ? null : e.prevValue, n === e[l] ? null : e.newValue)
|
||||
}
|
||||
|
||||
function ft(e) {
|
||||
var t = st(e);
|
||||
return function(e) {
|
||||
X.push(t, e.target)
|
||||
}
|
||||
}
|
||||
|
||||
function lt(e) {
|
||||
K && (K = !1, e.currentTarget.removeEventListener(h, lt)), rt((e.target || t).querySelectorAll(w), e.detail === o ? o : s), B && pt()
|
||||
}
|
||||
|
||||
function ct(e, t) {
|
||||
var n = this;
|
||||
q.call(n, e, t), G.call(n, {
|
||||
target: n
|
||||
})
|
||||
}
|
||||
|
||||
function ht(e, t) {
|
||||
D(e, t), et ? et.observe(e, z) : (J && (e.setAttribute = ct, e[i] = Z(e), e.addEventListener(p, G)), e.addEventListener(c, at)), e.createdCallback && Q && (e.created = !0, e.createdCallback(), e.created = !1)
|
||||
}
|
||||
|
||||
function pt() {
|
||||
for (var e, t = 0, n = F.length; t < n; t++) e = F[t], E.contains(e) || (n--, F.splice(t--, 1), vt(e, o))
|
||||
}
|
||||
|
||||
function dt(e) {
|
||||
throw new Error("A " + e + " type is already registered")
|
||||
}
|
||||
|
||||
function vt(e, t) {
|
||||
var n, r = ot(e); - 1 < r && (tt(e, b[r]), r = 0, t === s && !e[s] ? (e[o] = !1, e[s] = !0, r = 1, B && S.call(F, e) < 0 && F.push(e)) : t === o && !e[o] && (e[s] = !1, e[o] = !0, r = 1), r && (n = e[t + "Callback"]) && n.call(e))
|
||||
}
|
||||
if (r in t) return;
|
||||
var i = "__" + r + (Math.random() * 1e5 >> 0),
|
||||
s = "attached",
|
||||
o = "detached",
|
||||
u = "extends",
|
||||
a = "ADDITION",
|
||||
f = "MODIFICATION",
|
||||
l = "REMOVAL",
|
||||
c = "DOMAttrModified",
|
||||
h = "DOMContentLoaded",
|
||||
p = "DOMSubtreeModified",
|
||||
d = "<",
|
||||
v = "=",
|
||||
m = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/,
|
||||
g = ["ANNOTATION-XML", "COLOR-PROFILE", "FONT-FACE", "FONT-FACE-SRC", "FONT-FACE-URI", "FONT-FACE-FORMAT", "FONT-FACE-NAME", "MISSING-GLYPH"],
|
||||
y = [],
|
||||
b = [],
|
||||
w = "",
|
||||
E = t.documentElement,
|
||||
S = y.indexOf || function(e) {
|
||||
for (var t = this.length; t-- && this[t] !== e;);
|
||||
return t
|
||||
},
|
||||
x = n.prototype,
|
||||
T = x.hasOwnProperty,
|
||||
N = x.isPrototypeOf,
|
||||
C = n.defineProperty,
|
||||
k = n.getOwnPropertyDescriptor,
|
||||
L = n.getOwnPropertyNames,
|
||||
A = n.getPrototypeOf,
|
||||
O = n.setPrototypeOf,
|
||||
M = !!n.__proto__,
|
||||
_ = n.create || function mt(e) {
|
||||
return e ? (mt.prototype = e, new mt) : this
|
||||
},
|
||||
D = O || (M ? function(e, t) {
|
||||
return e.__proto__ = t, e
|
||||
} : L && k ? function() {
|
||||
function e(e, t) {
|
||||
for (var n, r = L(t), i = 0, s = r.length; i < s; i++) n = r[i], T.call(e, n) || C(e, n, k(t, n))
|
||||
}
|
||||
return function(t, n) {
|
||||
do e(t, n); while ((n = A(n)) && !N.call(n, t));
|
||||
return t
|
||||
}
|
||||
}() : function(e, t) {
|
||||
for (var n in t) e[n] = t[n];
|
||||
return e
|
||||
}),
|
||||
P = e.MutationObserver || e.WebKitMutationObserver,
|
||||
H = (e.HTMLElement || e.Element || e.Node).prototype,
|
||||
B = !N.call(H, E),
|
||||
j = B ? function(e) {
|
||||
return e.nodeType === 1
|
||||
} : function(e) {
|
||||
return N.call(H, e)
|
||||
},
|
||||
F = B && [],
|
||||
I = H.cloneNode,
|
||||
q = H.setAttribute,
|
||||
R = H.removeAttribute,
|
||||
U = t.createElement,
|
||||
z = P && {
|
||||
attributes: !0,
|
||||
characterData: !0,
|
||||
attributeOldValue: !0
|
||||
},
|
||||
W = P || function(e) {
|
||||
J = !1, E.removeEventListener(c, W)
|
||||
},
|
||||
X, V = e.requestAnimationFrame || e.webkitRequestAnimationFrame || e.mozRequestAnimationFrame || e.msRequestAnimationFrame || function(e) {
|
||||
setTimeout(e, 10)
|
||||
},
|
||||
$ = !1,
|
||||
J = !0,
|
||||
K = !0,
|
||||
Q = !0,
|
||||
G, Y, Z, et, tt, nt;
|
||||
O || M ? (tt = function(e, t) {
|
||||
N.call(t, e) || ht(e, t)
|
||||
}, nt = ht) : (tt = function(e, t) {
|
||||
e[i] || (e[i] = n(!0), ht(e, t))
|
||||
}, nt = tt), B ? (J = !1, function() {
|
||||
var e = k(H, "addEventListener"),
|
||||
t = e.value,
|
||||
n = function(e) {
|
||||
var t = new CustomEvent(c, {
|
||||
bubbles: !0
|
||||
});
|
||||
t.attrName = e, t.prevValue = this.getAttribute(e), t.newValue = null, t[l] = t.attrChange = 2, R.call(this, e), this.dispatchEvent(t)
|
||||
},
|
||||
r = function(e, t) {
|
||||
var n = this.hasAttribute(e),
|
||||
r = n && this.getAttribute(e),
|
||||
i = new CustomEvent(c, {
|
||||
bubbles: !0
|
||||
});
|
||||
q.call(this, e, t), i.attrName = e, i.prevValue = n ? r : null, i.newValue = t, n ? i[f] = i.attrChange = 1 : i[a] = i.attrChange = 0, this.dispatchEvent(i)
|
||||
},
|
||||
s = function(e) {
|
||||
var t = e.currentTarget,
|
||||
n = t[i],
|
||||
r = e.propertyName,
|
||||
s;
|
||||
n.hasOwnProperty(r) && (n = n[r], s = new CustomEvent(c, {
|
||||
bubbles: !0
|
||||
}), s.attrName = n.name, s.prevValue = n.value || null, s.newValue = n.value = t[r] || null, s.prevValue == null ? s[a] = s.attrChange = 0 : s[f] = s.attrChange = 1, t.dispatchEvent(s))
|
||||
};
|
||||
e.value = function(e, o, u) {
|
||||
e === c && this.attributeChangedCallback && this.setAttribute !== r && (this[i] = {
|
||||
className: {
|
||||
name: "class",
|
||||
value: this.className
|
||||
}
|
||||
}, this.setAttribute = r, this.removeAttribute = n, t.call(this, "propertychange", s)), t.call(this, e, o, u)
|
||||
}, C(H, "addEventListener", e)
|
||||
}()) : P || (E.addEventListener(c, W), E.setAttribute(i, 1), E.removeAttribute(i), J && (G = function(e) {
|
||||
var t = this,
|
||||
n, r, s;
|
||||
if (t === e.target) {
|
||||
n = t[i], t[i] = r = Z(t);
|
||||
for (s in r) {
|
||||
if (!(s in n)) return Y(0, t, s, n[s], r[s], a);
|
||||
if (r[s] !== n[s]) return Y(1, t, s, n[s], r[s], f)
|
||||
}
|
||||
for (s in n)
|
||||
if (!(s in r)) return Y(2, t, s, n[s], r[s], l)
|
||||
}
|
||||
}, Y = function(e, t, n, r, i, s) {
|
||||
var o = {
|
||||
attrChange: e,
|
||||
currentTarget: t,
|
||||
attrName: n,
|
||||
prevValue: r,
|
||||
newValue: i
|
||||
};
|
||||
o[s] = e, at(o)
|
||||
}, Z = function(e) {
|
||||
for (var t, n, r = {}, i = e.attributes, s = 0, o = i.length; s < o; s++) t = i[s], n = t.name, n !== "setAttribute" && (r[n] = t.value);
|
||||
return r
|
||||
})), t[r] = function(n, r) {
|
||||
c = n.toUpperCase(), $ || ($ = !0, P ? (et = function(e, t) {
|
||||
function n(e, t) {
|
||||
for (var n = 0, r = e.length; n < r; t(e[n++]));
|
||||
}
|
||||
return new P(function(r) {
|
||||
for (var i, s, o, u = 0, a = r.length; u < a; u++) i = r[u], i.type === "childList" ? (n(i.addedNodes, e), n(i.removedNodes, t)) : (s = i.target, Q && s.attributeChangedCallback && i.attributeName !== "style" && (o = s.getAttribute(i.attributeName), o !== i.oldValue && s.attributeChangedCallback(i.attributeName, i.oldValue, o)))
|
||||
})
|
||||
}(st(s), st(o)), et.observe(t, {
|
||||
childList: !0,
|
||||
subtree: !0
|
||||
})) : (X = [], V(function E() {
|
||||
while (X.length) X.shift().call(null, X.shift());
|
||||
V(E)
|
||||
}), t.addEventListener("DOMNodeInserted", ft(s)), t.addEventListener("DOMNodeRemoved", ft(o))), t.addEventListener(h, lt), t.addEventListener("readystatechange", lt), t.createElement = function(e, n) {
|
||||
var r = U.apply(t, arguments),
|
||||
i = "" + e,
|
||||
s = S.call(y, (n ? v : d) + (n || i).toUpperCase()),
|
||||
o = -1 < s;
|
||||
return n && (r.setAttribute("is", n = n.toLowerCase()), o && (o = ut(i.toUpperCase(), n))), Q = !t.createElement.innerHTMLHelper, o && nt(r, b[s]), r
|
||||
}, H.cloneNode = function(e) {
|
||||
var t = I.call(this, !!e),
|
||||
n = ot(t);
|
||||
return -1 < n && nt(t, b[n]), e && it(t.querySelectorAll(w)), t
|
||||
}), -2 < S.call(y, v + c) + S.call(y, d + c) && dt(n);
|
||||
if (!m.test(c) || -1 < S.call(g, c)) throw new Error("The type " + n + " is invalid");
|
||||
var i = function() {
|
||||
return f ? t.createElement(l, c) : t.createElement(l)
|
||||
},
|
||||
a = r || x,
|
||||
f = T.call(a, u),
|
||||
l = f ? r[u].toUpperCase() : c,
|
||||
c, p;
|
||||
return f && -1 < S.call(y, d + l) && dt(l), p = y.push((f ? v : d) + c) - 1, w = w.concat(w.length ? "," : "", f ? l + '[is="' + n.toLowerCase() + '"]' : l), i.prototype = b[p] = T.call(a, "prototype") ? a.prototype : _(H), rt(t.querySelectorAll(w), s), i
|
||||
}
|
||||
})(window, document, Object, "registerElement");
|
||||
263
src/bower_components/fetch/fetch.js
vendored
Normal file
263
src/bower_components/fetch/fetch.js
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
! 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);
|
||||
@@ -15,4 +15,4 @@ window.queryString = {}, window.queryString.extract = function(maybeUrl) {
|
||||
return encodeURIComponent(key) + "=" + encodeURIComponent(val2)
|
||||
}).join("&") : encodeURIComponent(key) + "=" + encodeURIComponent(val)
|
||||
}).join("&") : ""
|
||||
};
|
||||
};
|
||||
@@ -80,4 +80,4 @@ describe(".parse()", function() {
|
||||
qs.extract(void 0)
|
||||
}, TypeError)
|
||||
})
|
||||
});
|
||||
});
|
||||
607
src/bower_components/requirejs/require.js
vendored
Normal file
607
src/bower_components/requirejs/require.js
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
var requirejs, require, define;
|
||||
! function(global, setTimeout) {
|
||||
function commentReplace(match, singlePrefix) {
|
||||
return singlePrefix || ""
|
||||
}
|
||||
|
||||
function isFunction(it) {
|
||||
return "[object Function]" === ostring.call(it)
|
||||
}
|
||||
|
||||
function isArray(it) {
|
||||
return "[object Array]" === ostring.call(it)
|
||||
}
|
||||
|
||||
function each(ary, func) {
|
||||
if (ary) {
|
||||
var i;
|
||||
for (i = 0; i < ary.length && (!ary[i] || !func(ary[i], i, ary)); i += 1);
|
||||
}
|
||||
}
|
||||
|
||||
function eachReverse(ary, func) {
|
||||
if (ary) {
|
||||
var i;
|
||||
for (i = ary.length - 1; i > -1 && (!ary[i] || !func(ary[i], i, ary)); i -= 1);
|
||||
}
|
||||
}
|
||||
|
||||
function hasProp(obj, prop) {
|
||||
return hasOwn.call(obj, prop)
|
||||
}
|
||||
|
||||
function getOwn(obj, prop) {
|
||||
return hasProp(obj, prop) && obj[prop]
|
||||
}
|
||||
|
||||
function eachProp(obj, func) {
|
||||
var prop;
|
||||
for (prop in obj)
|
||||
if (hasProp(obj, prop) && func(obj[prop], prop)) break
|
||||
}
|
||||
|
||||
function mixin(target, source, force, deepStringMixin) {
|
||||
return source && eachProp(source, function(value, prop) {
|
||||
!force && hasProp(target, prop) || (!deepStringMixin || "object" != typeof value || !value || isArray(value) || isFunction(value) || value instanceof RegExp ? target[prop] = value : (target[prop] || (target[prop] = {}), mixin(target[prop], value, force, deepStringMixin)))
|
||||
}), target
|
||||
}
|
||||
|
||||
function bind(obj, fn) {
|
||||
return function() {
|
||||
return fn.apply(obj, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
function scripts() {
|
||||
return document.getElementsByTagName("script")
|
||||
}
|
||||
|
||||
function defaultOnError(err) {
|
||||
throw err
|
||||
}
|
||||
|
||||
function getGlobal(value) {
|
||||
if (!value) return value;
|
||||
var g = global;
|
||||
return each(value.split("."), function(part) {
|
||||
g = g[part]
|
||||
}), g
|
||||
}
|
||||
|
||||
function makeError(id, msg, err, requireModules) {
|
||||
var e = new Error(msg + "\nhttp://requirejs.org/docs/errors.html#" + id);
|
||||
return e.requireType = id, e.requireModules = requireModules, err && (e.originalError = err), e
|
||||
}
|
||||
|
||||
function newContext(contextName) {
|
||||
function trimDots(ary) {
|
||||
var i, part;
|
||||
for (i = 0; i < ary.length; i++)
|
||||
if ("." === (part = ary[i])) ary.splice(i, 1), i -= 1;
|
||||
else if (".." === part) {
|
||||
if (0 === i || 1 === i && ".." === ary[2] || ".." === ary[i - 1]) continue;
|
||||
i > 0 && (ary.splice(i - 1, 2), i -= 2)
|
||||
}
|
||||
}
|
||||
|
||||
function normalize(name, baseName, applyMap) {
|
||||
var mapValue, nameParts, i, j, nameSegment, lastIndex, foundMap, foundI, foundStarMap, starI, normalizedBaseParts, baseParts = baseName && baseName.split("/"),
|
||||
map = config.map,
|
||||
starMap = map && map["*"];
|
||||
if (name && (name = name.split("/"), lastIndex = name.length - 1, config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex]) && (name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, "")), "." === name[0].charAt(0) && baseParts && (normalizedBaseParts = baseParts.slice(0, baseParts.length - 1), name = normalizedBaseParts.concat(name)), trimDots(name), name = name.join("/")), applyMap && map && (baseParts || starMap)) {
|
||||
nameParts = name.split("/");
|
||||
outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
|
||||
if (nameSegment = nameParts.slice(0, i).join("/"), baseParts)
|
||||
for (j = baseParts.length; j > 0; j -= 1)
|
||||
if ((mapValue = getOwn(map, baseParts.slice(0, j).join("/"))) && (mapValue = getOwn(mapValue, nameSegment))) {
|
||||
foundMap = mapValue, foundI = i;
|
||||
break outerLoop
|
||||
}! foundStarMap && starMap && getOwn(starMap, nameSegment) && (foundStarMap = getOwn(starMap, nameSegment), starI = i)
|
||||
}!foundMap && foundStarMap && (foundMap = foundStarMap, foundI = starI), foundMap && (nameParts.splice(0, foundI, foundMap), name = nameParts.join("/"))
|
||||
}
|
||||
return getOwn(config.pkgs, name) || name
|
||||
}
|
||||
|
||||
function removeScript(name) {
|
||||
isBrowser && each(scripts(), function(scriptNode) {
|
||||
if (scriptNode.getAttribute("data-requiremodule") === name && scriptNode.getAttribute("data-requirecontext") === context.contextName) return scriptNode.parentNode.removeChild(scriptNode), !0
|
||||
})
|
||||
}
|
||||
|
||||
function hasPathFallback(id) {
|
||||
var pathConfig = getOwn(config.paths, id);
|
||||
if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) return pathConfig.shift(), context.require.undef(id), context.makeRequire(null, {
|
||||
skipMap: !0
|
||||
})([id]), !0
|
||||
}
|
||||
|
||||
function splitPrefix(name) {
|
||||
var prefix, index = name ? name.indexOf("!") : -1;
|
||||
return index > -1 && (prefix = name.substring(0, index), name = name.substring(index + 1, name.length)), [prefix, name]
|
||||
}
|
||||
|
||||
function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
|
||||
var url, pluginModule, suffix, nameParts, prefix = null,
|
||||
parentName = parentModuleMap ? parentModuleMap.name : null,
|
||||
originalName = name,
|
||||
isDefine = !0,
|
||||
normalizedName = "";
|
||||
return name || (isDefine = !1, name = "_@r" + (requireCounter += 1)), nameParts = splitPrefix(name), prefix = nameParts[0], name = nameParts[1], prefix && (prefix = normalize(prefix, parentName, applyMap), pluginModule = getOwn(defined, prefix)), name && (prefix ? normalizedName = isNormalized ? name : pluginModule && pluginModule.normalize ? pluginModule.normalize(name, function(name) {
|
||||
return normalize(name, parentName, applyMap)
|
||||
}) : -1 === name.indexOf("!") ? normalize(name, parentName, applyMap) : name : (normalizedName = normalize(name, parentName, applyMap), nameParts = splitPrefix(normalizedName), prefix = nameParts[0], normalizedName = nameParts[1], isNormalized = !0, url = context.nameToUrl(normalizedName))), suffix = !prefix || pluginModule || isNormalized ? "" : "_unnormalized" + (unnormalizedCounter += 1), {
|
||||
prefix: prefix,
|
||||
name: normalizedName,
|
||||
parentMap: parentModuleMap,
|
||||
unnormalized: !!suffix,
|
||||
url: url,
|
||||
originalName: originalName,
|
||||
isDefine: isDefine,
|
||||
id: (prefix ? prefix + "!" + normalizedName : normalizedName) + suffix
|
||||
}
|
||||
}
|
||||
|
||||
function getModule(depMap) {
|
||||
var id = depMap.id,
|
||||
mod = getOwn(registry, id);
|
||||
return mod || (mod = registry[id] = new context.Module(depMap)), mod
|
||||
}
|
||||
|
||||
function on(depMap, name, fn) {
|
||||
var id = depMap.id,
|
||||
mod = getOwn(registry, id);
|
||||
!hasProp(defined, id) || mod && !mod.defineEmitComplete ? (mod = getModule(depMap), mod.error && "error" === name ? fn(mod.error) : mod.on(name, fn)) : "defined" === name && fn(defined[id])
|
||||
}
|
||||
|
||||
function onError(err, errback) {
|
||||
var ids = err.requireModules,
|
||||
notified = !1;
|
||||
errback ? errback(err) : (each(ids, function(id) {
|
||||
var mod = getOwn(registry, id);
|
||||
mod && (mod.error = err, mod.events.error && (notified = !0, mod.emit("error", err)))
|
||||
}), notified || req.onError(err))
|
||||
}
|
||||
|
||||
function takeGlobalQueue() {
|
||||
globalDefQueue.length && (each(globalDefQueue, function(queueItem) {
|
||||
var id = queueItem[0];
|
||||
"string" == typeof id && (context.defQueueMap[id] = !0), defQueue.push(queueItem)
|
||||
}), globalDefQueue = [])
|
||||
}
|
||||
|
||||
function cleanRegistry(id) {
|
||||
delete registry[id], delete enabledRegistry[id]
|
||||
}
|
||||
|
||||
function breakCycle(mod, traced, processed) {
|
||||
var id = mod.map.id;
|
||||
mod.error ? mod.emit("error", mod.error) : (traced[id] = !0, each(mod.depMaps, function(depMap, i) {
|
||||
var depId = depMap.id,
|
||||
dep = getOwn(registry, depId);
|
||||
!dep || mod.depMatched[i] || processed[depId] || (getOwn(traced, depId) ? (mod.defineDep(i, defined[depId]), mod.check()) : breakCycle(dep, traced, processed))
|
||||
}), processed[id] = !0)
|
||||
}
|
||||
|
||||
function checkLoaded() {
|
||||
var err, usingPathFallback, waitInterval = 1e3 * config.waitSeconds,
|
||||
expired = waitInterval && context.startTime + waitInterval < (new Date).getTime(),
|
||||
noLoads = [],
|
||||
reqCalls = [],
|
||||
stillLoading = !1,
|
||||
needCycleCheck = !0;
|
||||
if (!inCheckLoaded) {
|
||||
if (inCheckLoaded = !0, eachProp(enabledRegistry, function(mod) {
|
||||
var map = mod.map,
|
||||
modId = map.id;
|
||||
if (mod.enabled && (map.isDefine || reqCalls.push(mod), !mod.error))
|
||||
if (!mod.inited && expired) hasPathFallback(modId) ? (usingPathFallback = !0, stillLoading = !0) : (noLoads.push(modId), removeScript(modId));
|
||||
else if (!mod.inited && mod.fetched && map.isDefine && (stillLoading = !0, !map.prefix)) return needCycleCheck = !1
|
||||
}), expired && noLoads.length) return err = makeError("timeout", "Load timeout for modules: " + noLoads, null, noLoads), err.contextName = context.contextName, onError(err);
|
||||
needCycleCheck && each(reqCalls, function(mod) {
|
||||
breakCycle(mod, {}, {})
|
||||
}), expired && !usingPathFallback || !stillLoading || !isBrowser && !isWebWorker || checkLoadedTimeoutId || (checkLoadedTimeoutId = setTimeout(function() {
|
||||
checkLoadedTimeoutId = 0, checkLoaded()
|
||||
}, 50)), inCheckLoaded = !1
|
||||
}
|
||||
}
|
||||
|
||||
function callGetModule(args) {
|
||||
hasProp(defined, args[0]) || getModule(makeModuleMap(args[0], null, !0)).init(args[1], args[2])
|
||||
}
|
||||
|
||||
function removeListener(node, func, name, ieName) {
|
||||
node.detachEvent && !isOpera ? ieName && node.detachEvent(ieName, func) : node.removeEventListener(name, func, !1)
|
||||
}
|
||||
|
||||
function getScriptData(evt) {
|
||||
var node = evt.currentTarget || evt.srcElement;
|
||||
return removeListener(node, context.onScriptLoad, "load", "onreadystatechange"), removeListener(node, context.onScriptError, "error"), {
|
||||
node: node,
|
||||
id: node && node.getAttribute("data-requiremodule")
|
||||
}
|
||||
}
|
||||
|
||||
function intakeDefines() {
|
||||
var args;
|
||||
for (takeGlobalQueue(); defQueue.length;) {
|
||||
if (args = defQueue.shift(), null === args[0]) return onError(makeError("mismatch", "Mismatched anonymous define() module: " + args[args.length - 1]));
|
||||
callGetModule(args)
|
||||
}
|
||||
context.defQueueMap = {}
|
||||
}
|
||||
var inCheckLoaded, Module, context, handlers, checkLoadedTimeoutId, config = {
|
||||
waitSeconds: 7,
|
||||
baseUrl: "./",
|
||||
paths: {},
|
||||
bundles: {},
|
||||
pkgs: {},
|
||||
shim: {},
|
||||
config: {}
|
||||
},
|
||||
registry = {},
|
||||
enabledRegistry = {},
|
||||
undefEvents = {},
|
||||
defQueue = [],
|
||||
defined = {},
|
||||
urlFetched = {},
|
||||
bundlesMap = {},
|
||||
requireCounter = 1,
|
||||
unnormalizedCounter = 1;
|
||||
return handlers = {
|
||||
require: function(mod) {
|
||||
return mod.require ? mod.require : mod.require = context.makeRequire(mod.map)
|
||||
},
|
||||
exports: function(mod) {
|
||||
if (mod.usingExports = !0, mod.map.isDefine) return mod.exports ? defined[mod.map.id] = mod.exports : mod.exports = defined[mod.map.id] = {}
|
||||
},
|
||||
module: function(mod) {
|
||||
return mod.module ? mod.module : mod.module = {
|
||||
id: mod.map.id,
|
||||
uri: mod.map.url,
|
||||
config: function() {
|
||||
return getOwn(config.config, mod.map.id) || {}
|
||||
},
|
||||
exports: mod.exports || (mod.exports = {})
|
||||
}
|
||||
}
|
||||
}, Module = function(map) {
|
||||
this.events = getOwn(undefEvents, map.id) || {}, this.map = map, this.shim = getOwn(config.shim, map.id), this.depExports = [], this.depMaps = [], this.depMatched = [], this.pluginMaps = {}, this.depCount = 0
|
||||
}, Module.prototype = {
|
||||
init: function(depMaps, factory, errback, options) {
|
||||
options = options || {}, this.inited || (this.factory = factory, errback ? this.on("error", errback) : this.events.error && (errback = bind(this, function(err) {
|
||||
this.emit("error", err)
|
||||
})), this.depMaps = depMaps && depMaps.slice(0), this.errback = errback, this.inited = !0, this.ignore = options.ignore, options.enabled || this.enabled ? this.enable() : this.check())
|
||||
},
|
||||
defineDep: function(i, depExports) {
|
||||
this.depMatched[i] || (this.depMatched[i] = !0, this.depCount -= 1, this.depExports[i] = depExports)
|
||||
},
|
||||
fetch: function() {
|
||||
if (!this.fetched) {
|
||||
this.fetched = !0, context.startTime = (new Date).getTime();
|
||||
var map = this.map;
|
||||
if (!this.shim) return map.prefix ? this.callPlugin() : this.load();
|
||||
context.makeRequire(this.map, {
|
||||
enableBuildCallback: !0
|
||||
})(this.shim.deps || [], bind(this, function() {
|
||||
return map.prefix ? this.callPlugin() : this.load()
|
||||
}))
|
||||
}
|
||||
},
|
||||
load: function() {
|
||||
var url = this.map.url;
|
||||
urlFetched[url] || (urlFetched[url] = !0, context.load(this.map.id, url))
|
||||
},
|
||||
check: function() {
|
||||
if (this.enabled && !this.enabling) {
|
||||
var err, cjsModule, id = this.map.id,
|
||||
depExports = this.depExports,
|
||||
exports = this.exports,
|
||||
factory = this.factory;
|
||||
if (this.inited) {
|
||||
if (this.error) this.emit("error", this.error);
|
||||
else if (!this.defining) {
|
||||
if (this.defining = !0, this.depCount < 1 && !this.defined) {
|
||||
if (isFunction(factory)) {
|
||||
if (this.events.error && this.map.isDefine || req.onError !== defaultOnError) try {
|
||||
exports = context.execCb(id, factory, depExports, exports)
|
||||
} catch (e) {
|
||||
err = e
|
||||
} else exports = context.execCb(id, factory, depExports, exports);
|
||||
if (this.map.isDefine && void 0 === exports && (cjsModule = this.module, cjsModule ? exports = cjsModule.exports : this.usingExports && (exports = this.exports)), err) return err.requireMap = this.map, err.requireModules = this.map.isDefine ? [this.map.id] : null, err.requireType = this.map.isDefine ? "define" : "require", onError(this.error = err)
|
||||
} else exports = factory;
|
||||
if (this.exports = exports, this.map.isDefine && !this.ignore && (defined[id] = exports, req.onResourceLoad)) {
|
||||
var resLoadMaps = [];
|
||||
each(this.depMaps, function(depMap) {
|
||||
resLoadMaps.push(depMap.normalizedMap || depMap)
|
||||
}), req.onResourceLoad(context, this.map, resLoadMaps)
|
||||
}
|
||||
cleanRegistry(id), this.defined = !0
|
||||
}
|
||||
this.defining = !1, this.defined && !this.defineEmitted && (this.defineEmitted = !0, this.emit("defined", this.exports), this.defineEmitComplete = !0)
|
||||
}
|
||||
} else hasProp(context.defQueueMap, id) || this.fetch()
|
||||
}
|
||||
},
|
||||
callPlugin: function() {
|
||||
var map = this.map,
|
||||
id = map.id,
|
||||
pluginMap = makeModuleMap(map.prefix);
|
||||
this.depMaps.push(pluginMap), on(pluginMap, "defined", bind(this, function(plugin) {
|
||||
var load, normalizedMap, normalizedMod, bundleId = getOwn(bundlesMap, this.map.id),
|
||||
name = this.map.name,
|
||||
parentName = this.map.parentMap ? this.map.parentMap.name : null,
|
||||
localRequire = context.makeRequire(map.parentMap, {
|
||||
enableBuildCallback: !0
|
||||
});
|
||||
return this.map.unnormalized ? (plugin.normalize && (name = plugin.normalize(name, function(name) {
|
||||
return normalize(name, parentName, !0)
|
||||
}) || ""), normalizedMap = makeModuleMap(map.prefix + "!" + name, this.map.parentMap, !0), on(normalizedMap, "defined", bind(this, function(value) {
|
||||
this.map.normalizedMap = normalizedMap, this.init([], function() {
|
||||
return value
|
||||
}, null, {
|
||||
enabled: !0,
|
||||
ignore: !0
|
||||
})
|
||||
})), void((normalizedMod = getOwn(registry, normalizedMap.id)) && (this.depMaps.push(normalizedMap), this.events.error && normalizedMod.on("error", bind(this, function(err) {
|
||||
this.emit("error", err)
|
||||
})), normalizedMod.enable()))) : bundleId ? (this.map.url = context.nameToUrl(bundleId), void this.load()) : (load = bind(this, function(value) {
|
||||
this.init([], function() {
|
||||
return value
|
||||
}, null, {
|
||||
enabled: !0
|
||||
})
|
||||
}), load.error = bind(this, function(err) {
|
||||
this.inited = !0, this.error = err, err.requireModules = [id], eachProp(registry, function(mod) {
|
||||
0 === mod.map.id.indexOf(id + "_unnormalized") && cleanRegistry(mod.map.id)
|
||||
}), onError(err)
|
||||
}), load.fromText = bind(this, function(text, textAlt) {
|
||||
var moduleName = map.name,
|
||||
moduleMap = makeModuleMap(moduleName),
|
||||
hasInteractive = useInteractive;
|
||||
textAlt && (text = textAlt), hasInteractive && (useInteractive = !1), getModule(moduleMap), hasProp(config.config, id) && (config.config[moduleName] = config.config[id]);
|
||||
try {
|
||||
req.exec(text)
|
||||
} catch (e) {
|
||||
return onError(makeError("fromtexteval", "fromText eval for " + id + " failed: " + e, e, [id]))
|
||||
}
|
||||
hasInteractive && (useInteractive = !0), this.depMaps.push(moduleMap), context.completeLoad(moduleName), localRequire([moduleName], load)
|
||||
}), void plugin.load(map.name, localRequire, load, config))
|
||||
})), context.enable(pluginMap, this), this.pluginMaps[pluginMap.id] = pluginMap
|
||||
},
|
||||
enable: function() {
|
||||
enabledRegistry[this.map.id] = this, this.enabled = !0, this.enabling = !0, each(this.depMaps, bind(this, function(depMap, i) {
|
||||
var id, mod, handler;
|
||||
if ("string" == typeof depMap) {
|
||||
if (depMap = makeModuleMap(depMap, this.map.isDefine ? this.map : this.map.parentMap, !1, !this.skipMap), this.depMaps[i] = depMap, handler = getOwn(handlers, depMap.id)) return void(this.depExports[i] = handler(this));
|
||||
this.depCount += 1, on(depMap, "defined", bind(this, function(depExports) {
|
||||
this.undefed || (this.defineDep(i, depExports), this.check())
|
||||
})), this.errback ? on(depMap, "error", bind(this, this.errback)) : this.events.error && on(depMap, "error", bind(this, function(err) {
|
||||
this.emit("error", err)
|
||||
}))
|
||||
}
|
||||
id = depMap.id, mod = registry[id], hasProp(handlers, id) || !mod || mod.enabled || context.enable(depMap, this)
|
||||
})), eachProp(this.pluginMaps, bind(this, function(pluginMap) {
|
||||
var mod = getOwn(registry, pluginMap.id);
|
||||
mod && !mod.enabled && context.enable(pluginMap, this)
|
||||
})), this.enabling = !1, this.check()
|
||||
},
|
||||
on: function(name, cb) {
|
||||
var cbs = this.events[name];
|
||||
cbs || (cbs = this.events[name] = []), cbs.push(cb)
|
||||
},
|
||||
emit: function(name, evt) {
|
||||
each(this.events[name], function(cb) {
|
||||
cb(evt)
|
||||
}), "error" === name && delete this.events[name]
|
||||
}
|
||||
}, context = {
|
||||
config: config,
|
||||
contextName: contextName,
|
||||
registry: registry,
|
||||
defined: defined,
|
||||
urlFetched: urlFetched,
|
||||
defQueue: defQueue,
|
||||
defQueueMap: {},
|
||||
Module: Module,
|
||||
makeModuleMap: makeModuleMap,
|
||||
nextTick: req.nextTick,
|
||||
onError: onError,
|
||||
configure: function(cfg) {
|
||||
if (cfg.baseUrl && "/" !== cfg.baseUrl.charAt(cfg.baseUrl.length - 1) && (cfg.baseUrl += "/"), "string" == typeof cfg.urlArgs) {
|
||||
var urlArgs = cfg.urlArgs;
|
||||
cfg.urlArgs = function(id, url) {
|
||||
return (-1 === url.indexOf("?") ? "?" : "&") + urlArgs
|
||||
}
|
||||
}
|
||||
var shim = config.shim,
|
||||
objs = {
|
||||
paths: !0,
|
||||
bundles: !0,
|
||||
config: !0,
|
||||
map: !0
|
||||
};
|
||||
eachProp(cfg, function(value, prop) {
|
||||
objs[prop] ? (config[prop] || (config[prop] = {}), mixin(config[prop], value, !0, !0)) : config[prop] = value
|
||||
}), cfg.bundles && eachProp(cfg.bundles, function(value, prop) {
|
||||
each(value, function(v) {
|
||||
v !== prop && (bundlesMap[v] = prop)
|
||||
})
|
||||
}), cfg.shim && (eachProp(cfg.shim, function(value, id) {
|
||||
isArray(value) && (value = {
|
||||
deps: value
|
||||
}), !value.exports && !value.init || value.exportsFn || (value.exportsFn = context.makeShimExports(value)), shim[id] = value
|
||||
}), config.shim = shim), cfg.packages && each(cfg.packages, function(pkgObj) {
|
||||
var location, name;
|
||||
pkgObj = "string" == typeof pkgObj ? {
|
||||
name: pkgObj
|
||||
} : pkgObj, name = pkgObj.name, location = pkgObj.location, location && (config.paths[name] = pkgObj.location), config.pkgs[name] = pkgObj.name + "/" + (pkgObj.main || "main").replace(currDirRegExp, "").replace(jsSuffixRegExp, "")
|
||||
}), eachProp(registry, function(mod, id) {
|
||||
mod.inited || mod.map.unnormalized || (mod.map = makeModuleMap(id, null, !0))
|
||||
}), (cfg.deps || cfg.callback) && context.require(cfg.deps || [], cfg.callback)
|
||||
},
|
||||
makeShimExports: function(value) {
|
||||
function fn() {
|
||||
var ret;
|
||||
return value.init && (ret = value.init.apply(global, arguments)), ret || value.exports && getGlobal(value.exports)
|
||||
}
|
||||
return fn
|
||||
},
|
||||
makeRequire: function(relMap, options) {
|
||||
function localRequire(deps, callback, errback) {
|
||||
var id, map, requireMod;
|
||||
return options.enableBuildCallback && callback && isFunction(callback) && (callback.__requireJsBuild = !0), "string" == typeof deps ? isFunction(callback) ? onError(makeError("requireargs", "Invalid require call"), errback) : relMap && hasProp(handlers, deps) ? handlers[deps](registry[relMap.id]) : req.get ? req.get(context, deps, relMap, localRequire) : (map = makeModuleMap(deps, relMap, !1, !0), id = map.id, hasProp(defined, id) ? defined[id] : onError(makeError("notloaded", 'Module name "' + id + '" has not been loaded yet for context: ' + contextName + (relMap ? "" : ". Use require([])")))) : (intakeDefines(), context.nextTick(function() {
|
||||
intakeDefines(), requireMod = getModule(makeModuleMap(null, relMap)), requireMod.skipMap = options.skipMap, requireMod.init(deps, callback, errback, {
|
||||
enabled: !0
|
||||
}), checkLoaded()
|
||||
}), localRequire)
|
||||
}
|
||||
return options = options || {}, mixin(localRequire, {
|
||||
isBrowser: isBrowser,
|
||||
toUrl: function(moduleNamePlusExt) {
|
||||
var ext, index = moduleNamePlusExt.lastIndexOf("."),
|
||||
segment = moduleNamePlusExt.split("/")[0],
|
||||
isRelative = "." === segment || ".." === segment;
|
||||
return -1 !== index && (!isRelative || index > 1) && (ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length), moduleNamePlusExt = moduleNamePlusExt.substring(0, index)), context.nameToUrl(normalize(moduleNamePlusExt, relMap && relMap.id, !0), ext, !0)
|
||||
},
|
||||
defined: function(id) {
|
||||
return hasProp(defined, makeModuleMap(id, relMap, !1, !0).id)
|
||||
},
|
||||
specified: function(id) {
|
||||
return id = makeModuleMap(id, relMap, !1, !0).id, hasProp(defined, id) || hasProp(registry, id)
|
||||
}
|
||||
}), relMap || (localRequire.undef = function(id) {
|
||||
takeGlobalQueue();
|
||||
var map = makeModuleMap(id, relMap, !0),
|
||||
mod = getOwn(registry, id);
|
||||
mod.undefed = !0, removeScript(id), delete defined[id], delete urlFetched[map.url], delete undefEvents[id], eachReverse(defQueue, function(args, i) {
|
||||
args[0] === id && defQueue.splice(i, 1)
|
||||
}), delete context.defQueueMap[id], mod && (mod.events.defined && (undefEvents[id] = mod.events), cleanRegistry(id))
|
||||
}), localRequire
|
||||
},
|
||||
enable: function(depMap) {
|
||||
getOwn(registry, depMap.id) && getModule(depMap).enable()
|
||||
},
|
||||
completeLoad: function(moduleName) {
|
||||
var found, args, mod, shim = getOwn(config.shim, moduleName) || {},
|
||||
shExports = shim.exports;
|
||||
for (takeGlobalQueue(); defQueue.length;) {
|
||||
if (args = defQueue.shift(), null === args[0]) {
|
||||
if (args[0] = moduleName, found) break;
|
||||
found = !0
|
||||
} else args[0] === moduleName && (found = !0);
|
||||
callGetModule(args)
|
||||
}
|
||||
if (context.defQueueMap = {}, mod = getOwn(registry, moduleName), !found && !hasProp(defined, moduleName) && mod && !mod.inited) {
|
||||
if (!(!config.enforceDefine || shExports && getGlobal(shExports))) return hasPathFallback(moduleName) ? void 0 : onError(makeError("nodefine", "No define call for " + moduleName, null, [moduleName]));
|
||||
callGetModule([moduleName, shim.deps || [], shim.exportsFn])
|
||||
}
|
||||
checkLoaded()
|
||||
},
|
||||
nameToUrl: function(moduleName, ext, skipExt) {
|
||||
var paths, syms, i, parentModule, url, parentPath, bundleId, pkgMain = getOwn(config.pkgs, moduleName);
|
||||
if (pkgMain && (moduleName = pkgMain), bundleId = getOwn(bundlesMap, moduleName)) return context.nameToUrl(bundleId, ext, skipExt);
|
||||
if (req.jsExtRegExp.test(moduleName)) url = moduleName + (ext || "");
|
||||
else {
|
||||
for (paths = config.paths, syms = moduleName.split("/"), i = syms.length; i > 0; i -= 1)
|
||||
if (parentModule = syms.slice(0, i).join("/"), parentPath = getOwn(paths, parentModule)) {
|
||||
isArray(parentPath) && (parentPath = parentPath[0]), syms.splice(0, i, parentPath);
|
||||
break
|
||||
} url = syms.join("/"), url += ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? "" : ".js"), url = ("/" === url.charAt(0) || url.match(/^[\w\+\.\-]+:/) ? "" : config.baseUrl) + url
|
||||
}
|
||||
return config.urlArgs && !/^blob\:/.test(url) ? url + config.urlArgs(moduleName, url) : url
|
||||
},
|
||||
load: function(id, url) {
|
||||
req.load(context, id, url)
|
||||
},
|
||||
execCb: function(name, callback, args, exports) {
|
||||
return callback.apply(exports, args)
|
||||
},
|
||||
onScriptLoad: function(evt) {
|
||||
if ("load" === evt.type || readyRegExp.test((evt.currentTarget || evt.srcElement).readyState)) {
|
||||
interactiveScript = null;
|
||||
var data = getScriptData(evt);
|
||||
context.completeLoad(data.id)
|
||||
}
|
||||
},
|
||||
onScriptError: function(evt) {
|
||||
var data = getScriptData(evt);
|
||||
if (!hasPathFallback(data.id)) {
|
||||
var parents = [];
|
||||
return eachProp(registry, function(value, key) {
|
||||
0 !== key.indexOf("_@r") && each(value.depMaps, function(depMap) {
|
||||
if (depMap.id === data.id) return parents.push(key), !0
|
||||
})
|
||||
}), onError(makeError("scripterror", 'Script error for "' + data.id + (parents.length ? '", needed by: ' + parents.join(", ") : '"'), evt, [data.id]))
|
||||
}
|
||||
}
|
||||
}, context.require = context.makeRequire(), context
|
||||
}
|
||||
|
||||
function getInteractiveScript() {
|
||||
return interactiveScript && "interactive" === interactiveScript.readyState ? interactiveScript : (eachReverse(scripts(), function(script) {
|
||||
if ("interactive" === script.readyState) return interactiveScript = script
|
||||
}), interactiveScript)
|
||||
}
|
||||
var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, version = "2.3.5",
|
||||
commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,
|
||||
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
|
||||
jsSuffixRegExp = /\.js$/,
|
||||
currDirRegExp = /^\.\//,
|
||||
op = Object.prototype,
|
||||
ostring = op.toString,
|
||||
hasOwn = op.hasOwnProperty,
|
||||
isBrowser = !("undefined" == typeof window || "undefined" == typeof navigator || !window.document),
|
||||
isWebWorker = !isBrowser && "undefined" != typeof importScripts,
|
||||
readyRegExp = isBrowser && "PLAYSTATION 3" === navigator.platform ? /^complete$/ : /^(complete|loaded)$/,
|
||||
defContextName = "_",
|
||||
isOpera = "undefined" != typeof opera && "[object Opera]" === opera.toString(),
|
||||
contexts = {},
|
||||
cfg = {},
|
||||
globalDefQueue = [],
|
||||
useInteractive = !1;
|
||||
if (void 0 === define) {
|
||||
if (void 0 !== requirejs) {
|
||||
if (isFunction(requirejs)) return;
|
||||
cfg = requirejs, requirejs = void 0
|
||||
}
|
||||
void 0 === require || isFunction(require) || (cfg = require, require = void 0), req = requirejs = function(deps, callback, errback, optional) {
|
||||
var context, config, contextName = defContextName;
|
||||
return isArray(deps) || "string" == typeof deps || (config = deps, isArray(callback) ? (deps = callback, callback = errback, errback = optional) : deps = []), config && config.context && (contextName = config.context), context = getOwn(contexts, contextName), context || (context = contexts[contextName] = req.s.newContext(contextName)), config && context.configure(config), context.require(deps, callback, errback)
|
||||
}, req.config = function(config) {
|
||||
return req(config)
|
||||
}, req.nextTick = void 0 !== setTimeout ? function(fn) {
|
||||
setTimeout(fn, 4)
|
||||
} : function(fn) {
|
||||
fn()
|
||||
}, require || (require = req), req.version = version, req.jsExtRegExp = /^\/|:|\?|\.js$/, req.isBrowser = isBrowser, s = req.s = {
|
||||
contexts: contexts,
|
||||
newContext: newContext
|
||||
}, req({}), each(["toUrl", "undef", "defined", "specified"], function(prop) {
|
||||
req[prop] = function() {
|
||||
var ctx = contexts[defContextName];
|
||||
return ctx.require[prop].apply(ctx, arguments)
|
||||
}
|
||||
}), isBrowser && (head = s.head = document.getElementsByTagName("head")[0], (baseElement = document.getElementsByTagName("base")[0]) && (head = s.head = baseElement.parentNode)), req.onError = defaultOnError, req.createNode = function(config, moduleName, url) {
|
||||
var node = config.xhtml ? document.createElementNS("http://www.w3.org/1999/xhtml", "html:script") : document.createElement("script");
|
||||
return node.type = config.scriptType || "text/javascript", node.charset = "utf-8", node.async = !0, node
|
||||
}, req.load = function(context, moduleName, url) {
|
||||
var node, config = context && context.config || {};
|
||||
if (isBrowser) return node = req.createNode(config, moduleName, url), node.setAttribute("data-requirecontext", context.contextName), node.setAttribute("data-requiremodule", moduleName), !node.attachEvent || node.attachEvent.toString && node.attachEvent.toString().indexOf("[native code") < 0 || isOpera ? (node.addEventListener("load", context.onScriptLoad, !1), node.addEventListener("error", context.onScriptError, !1)) : (useInteractive = !0, node.attachEvent("onreadystatechange", context.onScriptLoad)), node.src = url, config.onNodeCreated && config.onNodeCreated(node, config, moduleName, url), currentlyAddingScript = node, baseElement ? head.insertBefore(node, baseElement) : head.appendChild(node), currentlyAddingScript = null, node;
|
||||
if (isWebWorker) try {
|
||||
setTimeout(function() {}, 0), importScripts(url), context.completeLoad(moduleName)
|
||||
} catch (e) {
|
||||
context.onError(makeError("importscripts", "importScripts failed for " + moduleName + " at " + url, e, [moduleName]))
|
||||
}
|
||||
}, isBrowser && !cfg.skipDataMain && eachReverse(scripts(), function(script) {
|
||||
if (head || (head = script.parentNode), dataMain = script.getAttribute("data-main")) return mainScript = dataMain, cfg.baseUrl || -1 !== mainScript.indexOf("!") || (src = mainScript.split("/"), mainScript = src.pop(), subPath = src.length ? src.join("/") + "/" : "./", cfg.baseUrl = subPath), mainScript = mainScript.replace(jsSuffixRegExp, ""), req.jsExtRegExp.test(mainScript) && (mainScript = dataMain), cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript], !0
|
||||
}), define = function(name, deps, callback) {
|
||||
var node, context;
|
||||
"string" != typeof name && (callback = deps, deps = name, name = null), isArray(deps) || (callback = deps, deps = null), !deps && isFunction(callback) && (deps = [], callback.length && (callback.toString().replace(commentRegExp, commentReplace).replace(cjsRequireRegExp, function(match, dep) {
|
||||
deps.push(dep)
|
||||
}), deps = (1 === callback.length ? ["require"] : ["require", "exports", "module"]).concat(deps))), useInteractive && (node = currentlyAddingScript || getInteractiveScript()) && (name || (name = node.getAttribute("data-requiremodule")), context = contexts[node.getAttribute("data-requirecontext")]), context ? (context.defQueue.push([name, deps, callback]), context.defQueueMap[name] = !0) : globalDefQueue.push([name, deps, callback])
|
||||
}, define.amd = {
|
||||
jQuery: !0
|
||||
}, req.exec = function(text) {
|
||||
return eval(text)
|
||||
}, req(cfg)
|
||||
}
|
||||
}(this, "undefined" == typeof setTimeout ? void 0 : setTimeout);
|
||||
1571
src/bower_components/webcomponentsjs/webcomponents-lite.min.js
vendored
Normal file
1571
src/bower_components/webcomponentsjs/webcomponents-lite.min.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,100 +4,33 @@
|
||||
// Use define from require.js not webpack's define
|
||||
var _define = window.define;
|
||||
|
||||
// document-register-element
|
||||
var docRegister = require("document-register-element");
|
||||
_define("document-register-element", function() {
|
||||
return docRegister;
|
||||
});
|
||||
|
||||
// fetch
|
||||
var fetch = require("whatwg-fetch");
|
||||
_define("fetch", function() {
|
||||
return fetch
|
||||
});
|
||||
|
||||
// flvjs
|
||||
var flvjs = require("flv.js/dist/flv").default;
|
||||
_define("flvjs", function() {
|
||||
return flvjs;
|
||||
});
|
||||
|
||||
// jstree
|
||||
var jstree = require("jstree");
|
||||
require("jstree/dist/themes/default/style.css");
|
||||
_define("jstree", function() {
|
||||
return jstree;
|
||||
});
|
||||
_define("jstree", function() { return jstree; });
|
||||
|
||||
// jquery
|
||||
var jquery = require("jquery");
|
||||
_define("jQuery", function() {
|
||||
return jquery;
|
||||
});
|
||||
_define("jQuery", function() { return jquery; });
|
||||
|
||||
// hlsjs
|
||||
var hlsjs = require("hls.js");
|
||||
_define("hlsjs", function() {
|
||||
return hlsjs;
|
||||
});
|
||||
_define("hlsjs", function() { return hlsjs; });
|
||||
|
||||
// howler
|
||||
var howler = require("howler");
|
||||
_define("howler", function() {
|
||||
return howler;
|
||||
});
|
||||
|
||||
// resize-observer-polyfill
|
||||
var resize = require("resize-observer-polyfill").default;
|
||||
_define("resize-observer-polyfill", function() {
|
||||
return resize;
|
||||
});
|
||||
|
||||
// shaka
|
||||
var shaka = require("shaka-player");
|
||||
_define("shaka", function() {
|
||||
return shaka;
|
||||
});
|
||||
_define("howler", function() { return howler; });
|
||||
|
||||
// swiper
|
||||
var swiper = require("swiper/js/swiper");
|
||||
require("swiper/css/swiper.min.css");
|
||||
_define("swiper", function() {
|
||||
return swiper;
|
||||
});
|
||||
var swiper = require("swiper");
|
||||
require("swiper/dist/css/swiper.min.css");
|
||||
_define("swiper", function() { return swiper; });
|
||||
|
||||
// sortable
|
||||
var sortable = require("sortablejs").default;
|
||||
_define("sortable", function() {
|
||||
return sortable;
|
||||
});
|
||||
|
||||
// webcomponents
|
||||
var webcomponents = require("webcomponents.js/webcomponents-lite");
|
||||
_define("webcomponents", function() {
|
||||
return webcomponents
|
||||
});
|
||||
var sortable = require("sortablejs");
|
||||
_define("sortable", function() { return sortable; });
|
||||
|
||||
// libjass
|
||||
var libjass = require("libjass");
|
||||
require("libjass/libjass.css");
|
||||
_define("libjass", function() {
|
||||
return libjass;
|
||||
});
|
||||
|
||||
// libass-wasm
|
||||
var libass_wasm = require("libass-wasm");
|
||||
_define("JavascriptSubtitlesOctopus", function() {
|
||||
return libass_wasm;
|
||||
});
|
||||
|
||||
// material-icons
|
||||
var material_icons = require("material-design-icons-iconfont/dist/material-design-icons.css");
|
||||
_define("material-icons", function() {
|
||||
return material_icons;
|
||||
});
|
||||
|
||||
var jellyfin_noto = require("jellyfin-noto");
|
||||
_define("jellyfin-noto", function () {
|
||||
return jellyfin_noto;
|
||||
});
|
||||
_define("libjass", function() { return libjass; });
|
||||
|
||||
@@ -1,33 +1,19 @@
|
||||
define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "formDialogStyle"], function (dialogHelper, datetime) {
|
||||
define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "formDialogStyle"], function(dialogHelper, datetime) {
|
||||
"use strict";
|
||||
|
||||
function getDisplayTime(hours) {
|
||||
var minutes = 0;
|
||||
var pct = hours % 1;
|
||||
|
||||
if (pct) {
|
||||
minutes = parseInt(60 * pct);
|
||||
}
|
||||
|
||||
return datetime.getDisplayTime(new Date(2000, 1, 1, hours, minutes, 0, 0));
|
||||
var minutes = 0,
|
||||
pct = hours % 1;
|
||||
return pct && (minutes = parseInt(60 * pct)), datetime.getDisplayTime(new Date(2e3, 1, 1, hours, minutes, 0, 0))
|
||||
}
|
||||
|
||||
function populateHours(context) {
|
||||
var html = "";
|
||||
|
||||
for (var i = 0; i < 24; i++) {
|
||||
html += '<option value="' + i + '">' + getDisplayTime(i) + "</option>";
|
||||
}
|
||||
|
||||
html += '<option value="24">' + getDisplayTime(0) + "</option>";
|
||||
context.querySelector("#selectStart").innerHTML = html;
|
||||
context.querySelector("#selectEnd").innerHTML = html;
|
||||
for (var html = "", i = 0; i < 24; i++) html += '<option value="' + i + '">' + getDisplayTime(i) + "</option>";
|
||||
html += '<option value="24">' + getDisplayTime(0) + "</option>", context.querySelector("#selectStart").innerHTML = html, context.querySelector("#selectEnd").innerHTML = html
|
||||
}
|
||||
|
||||
function loadSchedule(context, schedule) {
|
||||
context.querySelector("#selectDay").value = schedule.DayOfWeek || "Sunday";
|
||||
context.querySelector("#selectStart").value = schedule.StartHour || 0;
|
||||
context.querySelector("#selectEnd").value = schedule.EndHour || 0;
|
||||
context.querySelector("#selectDay").value = schedule.DayOfWeek || "Sunday", context.querySelector("#selectStart").value = schedule.StartHour || 0, context.querySelector("#selectEnd").value = schedule.EndHour || 0
|
||||
}
|
||||
|
||||
function submitSchedule(context, options) {
|
||||
@@ -36,54 +22,30 @@ define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "f
|
||||
StartHour: context.querySelector("#selectStart").value,
|
||||
EndHour: context.querySelector("#selectEnd").value
|
||||
};
|
||||
|
||||
if (parseFloat(updatedSchedule.StartHour) >= parseFloat(updatedSchedule.EndHour)) {
|
||||
return void alert(Globalize.translate("ErrorMessageStartHourGreaterThanEnd"));
|
||||
}
|
||||
|
||||
context.submitted = true;
|
||||
options.schedule = Object.assign(options.schedule, updatedSchedule);
|
||||
dialogHelper.close(context);
|
||||
if (parseFloat(updatedSchedule.StartHour) >= parseFloat(updatedSchedule.EndHour)) return void alert(Globalize.translate("ErrorMessageStartHourGreaterThanEnd"));
|
||||
context.submitted = !0, options.schedule = Object.assign(options.schedule, updatedSchedule), dialogHelper.close(context)
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "components/accessschedule/accessschedule.template.html", true);
|
||||
|
||||
xhr.onload = function (e) {
|
||||
var template = this.response;
|
||||
var dlg = dialogHelper.createDialog({
|
||||
removeOnClose: true,
|
||||
size: "small"
|
||||
});
|
||||
show: function(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open("GET", "components/accessschedule/accessschedule.template.html", !0), xhr.onload = function(e) {
|
||||
var template = this.response,
|
||||
dlg = dialogHelper.createDialog({
|
||||
removeOnClose: !0,
|
||||
size: "small"
|
||||
});
|
||||
dlg.classList.add("formDialog");
|
||||
var html = "";
|
||||
html += Globalize.translateDocument(template);
|
||||
dlg.innerHTML = html;
|
||||
populateHours(dlg);
|
||||
loadSchedule(dlg, options.schedule);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.addEventListener("close", function () {
|
||||
if (dlg.submitted) {
|
||||
resolve(options.schedule);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
dlg.querySelector(".btnCancel").addEventListener("click", function (e) {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
dlg.querySelector("form").addEventListener("submit", function (e) {
|
||||
submitSchedule(dlg, options);
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
html += Globalize.translateDocument(template), dlg.innerHTML = html, populateHours(dlg), loadSchedule(dlg, options.schedule), dialogHelper.open(dlg), dlg.addEventListener("close", function() {
|
||||
dlg.submitted ? resolve(options.schedule) : reject()
|
||||
}), dlg.querySelector(".btnCancel").addEventListener("click", function(e) {
|
||||
dialogHelper.close(dlg)
|
||||
}), dlg.querySelector("form").addEventListener("submit", function(e) {
|
||||
return submitSchedule(dlg, options), e.preventDefault(), !1
|
||||
})
|
||||
}, xhr.send()
|
||||
})
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,7 +1,5 @@
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1">
|
||||
<i class="material-icons arrow_back"></i>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
${HeaderAccessSchedule}
|
||||
</h3>
|
||||
@@ -38,4 +36,4 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -4,7 +4,7 @@
|
||||
padding: 0;
|
||||
border: none;
|
||||
max-height: 84%;
|
||||
border-radius: 0.1em !important;
|
||||
border-radius: .1em !important;
|
||||
}
|
||||
|
||||
.actionsheet-not-fullscreen {
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
.actionSheetContent {
|
||||
margin: 0 !important;
|
||||
padding: 0.4em 0 !important;
|
||||
padding: .4em 0 !important;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -37,15 +37,14 @@
|
||||
box-shadow: none;
|
||||
flex-shrink: 0;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.actionSheetMenuItem:focus {
|
||||
transform: none !important;
|
||||
}
|
||||
.actionSheetMenuItem:focus {
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.actionsheetListItemBody {
|
||||
padding: 0.4em 1em 0.4em 0.6em !important;
|
||||
padding: .4em 1em .4em .6em !important;
|
||||
}
|
||||
|
||||
.actionSheetItemText {
|
||||
@@ -59,13 +58,13 @@
|
||||
}
|
||||
|
||||
.actionSheetItemAsideText {
|
||||
opacity: 0.7;
|
||||
opacity: .7;
|
||||
font-size: 90%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
flex-shrink: 0;
|
||||
margin-left: 5em;
|
||||
margin-right: 0.5em;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.actionSheetScroller {
|
||||
@@ -83,14 +82,14 @@
|
||||
}
|
||||
|
||||
.actionsheetDivider {
|
||||
height: 0.07em;
|
||||
margin: 0.25em 0;
|
||||
height: .07em;
|
||||
margin: .25em 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.actionSheetTitle {
|
||||
margin: 0.6em 0 0.7em !important;
|
||||
padding: 0 0.9em;
|
||||
margin: .6em 0 .7em !important;
|
||||
padding: 0 .9em;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
@@ -100,16 +99,16 @@
|
||||
}
|
||||
|
||||
.actionsheetMenuItemIcon {
|
||||
margin: 0 0.85em 0 0.45em !important;
|
||||
margin: 0 .85em 0 .45em !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.actionsheet-xlargeFont {
|
||||
font-size: 112% !important;
|
||||
font-size: 112%!important;
|
||||
}
|
||||
|
||||
.btnCloseActionSheet {
|
||||
position: fixed;
|
||||
top: 0.75em;
|
||||
left: 0.5em;
|
||||
top: .75em;
|
||||
left: .5em;
|
||||
}
|
||||
|
||||
@@ -139,9 +139,7 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-bu
|
||||
style += "min-width:" + minWidth + "px;";
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
var option;
|
||||
var i, length, option;
|
||||
var renderIcon = false;
|
||||
var icons = [];
|
||||
var itemIcon;
|
||||
@@ -158,7 +156,7 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-bu
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><i class="material-icons arrow_back"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
}
|
||||
|
||||
// If any items have an icon, give them all an icon just to make sure they're all lined up evenly
|
||||
@@ -226,9 +224,10 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-bu
|
||||
|
||||
if (itemIcon) {
|
||||
|
||||
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons">' + itemIcon + '</i>';
|
||||
} else if (renderIcon && !center) {
|
||||
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons" style="visibility:hidden;">check</i>';
|
||||
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon">' + itemIcon + '</i>';
|
||||
}
|
||||
else if (renderIcon && !center) {
|
||||
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon" style="visibility:hidden;">check</i>';
|
||||
}
|
||||
|
||||
html += '<div class="listItemBody actionsheetListItemBody">';
|
||||
@@ -357,4 +356,4 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-bu
|
||||
return {
|
||||
show: show
|
||||
};
|
||||
});
|
||||
});
|
||||
3
src/components/actionsheet/package.json
Normal file
3
src/components/actionsheet/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "actionsheet.js"
|
||||
}
|
||||
@@ -1,157 +1,96 @@
|
||||
define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotifications", "connectionManager", "emby-button", "listViewStyle"], function (events, globalize, dom, datetime, userSettings, serverNotifications, connectionManager) {
|
||||
define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotifications", "connectionManager", "emby-button", "listViewStyle"], function(events, globalize, dom, datetime, userSettings, serverNotifications, connectionManager) {
|
||||
"use strict";
|
||||
|
||||
function getEntryHtml(entry, apiClient) {
|
||||
var html = "";
|
||||
html += '<div class="listItem listItem-border">';
|
||||
var color = "#00a4dc";
|
||||
var icon = "notifications";
|
||||
|
||||
var icon = "notifications";
|
||||
if ("Error" == entry.Severity || "Fatal" == entry.Severity || "Warn" == entry.Severity) {
|
||||
color = "#cc0000";
|
||||
icon = "notification_important";
|
||||
}
|
||||
|
||||
if (entry.UserId && entry.UserPrimaryImageTag) {
|
||||
html += '<i class="listItemIcon material-icons" style="width:2em!important;height:2em!important;padding:0;color:transparent;background-color:' + color + ";background-image:url('" + apiClient.getUserImageUrl(entry.UserId, {
|
||||
html += '<i class="listItemIcon md-icon" style="width:2em!important;height:2em!important;padding:0;color:transparent;background-color:' + color + ";background-image:url('" + apiClient.getUserImageUrl(entry.UserId, {
|
||||
type: "Primary",
|
||||
tag: entry.UserPrimaryImageTag
|
||||
tag: entry.UserPrimaryImageTag,
|
||||
height: 40
|
||||
}) + "');background-repeat:no-repeat;background-position:center center;background-size: cover;\">dvr</i>"
|
||||
} else {
|
||||
html += '<i class="listItemIcon material-icons" style="background-color:' + color + '">' + icon + '</i>';
|
||||
html += '<i class="listItemIcon md-icon" style="background-color:' + color + '">' + icon + '</i>';
|
||||
}
|
||||
|
||||
html += '<div class="listItemBody three-line">';
|
||||
html += '<div class="listItemBodyText">';
|
||||
html += entry.Name;
|
||||
html += "</div>";
|
||||
html += '<div class="listItemBodyText secondary">';
|
||||
var date = datetime.parseISO8601Date(entry.Date, true);
|
||||
html += datetime.toLocaleString(date).toLowerCase();
|
||||
html += "</div>";
|
||||
html += '<div class="listItemBodyText secondary listItemBodyText-nowrap">';
|
||||
html += entry.ShortOverview || "";
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
|
||||
if (entry.Overview) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnEntryInfo" data-id="' + entry.Id + '" title="' + globalize.translate("Info") + '"><i class="material-icons">info</i></button>';
|
||||
}
|
||||
|
||||
return html += "</div>";
|
||||
html += '<div class="listItemBody three-line">', html += '<div class="listItemBodyText">', html += entry.Name, html += "</div>", html += '<div class="listItemBodyText secondary">';
|
||||
var date = datetime.parseISO8601Date(entry.Date, !0);
|
||||
return html += datetime.toLocaleString(date).toLowerCase(), html += "</div>", html += '<div class="listItemBodyText secondary listItemBodyText-nowrap">', html += entry.ShortOverview || "", html += "</div>", html += "</div>", entry.Overview && (html += '<button type="button" is="paper-icon-button-light" class="btnEntryInfo" data-id="' + entry.Id + '" title="' + globalize.translate("Info") + '"><i class="md-icon">info</i></button>'), html += "</div>"
|
||||
}
|
||||
|
||||
function renderList(elem, apiClient, result, startIndex, limit) {
|
||||
elem.innerHTML = result.Items.map(function (i) {
|
||||
return getEntryHtml(i, apiClient);
|
||||
}).join("");
|
||||
elem.innerHTML = result.Items.map(function(i) {
|
||||
return getEntryHtml(i, apiClient)
|
||||
}).join("")
|
||||
}
|
||||
|
||||
function reloadData(instance, elem, apiClient, startIndex, limit) {
|
||||
if (null == startIndex) {
|
||||
startIndex = parseInt(elem.getAttribute("data-activitystartindex") || "0");
|
||||
}
|
||||
|
||||
limit = limit || parseInt(elem.getAttribute("data-activitylimit") || "7");
|
||||
var minDate = new Date();
|
||||
var hasUserId = "false" !== elem.getAttribute("data-useractivity");
|
||||
|
||||
if (hasUserId) {
|
||||
minDate.setTime(minDate.getTime() - 24 * 60 * 60 * 1000); // one day back
|
||||
} else {
|
||||
minDate.setTime(minDate.getTime() - 7 * 24 * 60 * 60 * 1000); // one week back
|
||||
}
|
||||
|
||||
ApiClient.getJSON(ApiClient.getUrl("System/ActivityLog/Entries", {
|
||||
null == startIndex && (startIndex = parseInt(elem.getAttribute("data-activitystartindex") || "0")), limit = limit || parseInt(elem.getAttribute("data-activitylimit") || "7");
|
||||
var minDate = new Date,
|
||||
hasUserId = "false" !== elem.getAttribute("data-useractivity");
|
||||
hasUserId ? minDate.setTime(minDate.getTime() - 864e5) : minDate.setTime(minDate.getTime() - 6048e5), ApiClient.getJSON(ApiClient.getUrl("System/ActivityLog/Entries", {
|
||||
startIndex: startIndex,
|
||||
limit: limit,
|
||||
minDate: minDate.toISOString(),
|
||||
hasUserId: hasUserId
|
||||
})).then(function (result) {
|
||||
elem.setAttribute("data-activitystartindex", startIndex);
|
||||
elem.setAttribute("data-activitylimit", limit);
|
||||
if (!startIndex) {
|
||||
})).then(function(result) {
|
||||
if (elem.setAttribute("data-activitystartindex", startIndex), elem.setAttribute("data-activitylimit", limit), !startIndex) {
|
||||
var activityContainer = dom.parentWithClass(elem, "activityContainer");
|
||||
|
||||
if (activityContainer) {
|
||||
if (result.Items.length) {
|
||||
activityContainer.classList.remove("hide");
|
||||
} else {
|
||||
activityContainer.classList.add("hide");
|
||||
}
|
||||
}
|
||||
activityContainer && (result.Items.length ? activityContainer.classList.remove("hide") : activityContainer.classList.add("hide"))
|
||||
}
|
||||
|
||||
instance.items = result.Items;
|
||||
renderList(elem, apiClient, result, startIndex, limit);
|
||||
});
|
||||
instance.items = result.Items, renderList(elem, apiClient, result, startIndex, limit)
|
||||
})
|
||||
}
|
||||
|
||||
function onActivityLogUpdate(e, apiClient, data) {
|
||||
var options = this.options;
|
||||
|
||||
if (options && options.serverId === apiClient.serverId()) {
|
||||
reloadData(this, options.element, apiClient);
|
||||
}
|
||||
options && options.serverId === apiClient.serverId() && reloadData(this, options.element, apiClient)
|
||||
}
|
||||
|
||||
function onListClick(e) {
|
||||
var btnEntryInfo = dom.parentWithClass(e.target, "btnEntryInfo");
|
||||
|
||||
if (btnEntryInfo) {
|
||||
var id = btnEntryInfo.getAttribute("data-id");
|
||||
var items = this.items;
|
||||
|
||||
var id = btnEntryInfo.getAttribute("data-id"),
|
||||
items = this.items;
|
||||
if (items) {
|
||||
var item = items.filter(function (i) {
|
||||
return i.Id.toString() === id;
|
||||
var item = items.filter(function(i) {
|
||||
return i.Id.toString() === id
|
||||
})[0];
|
||||
|
||||
if (item) {
|
||||
showItemOverview(item);
|
||||
}
|
||||
item && showItemOverview(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showItemOverview(item) {
|
||||
require(["alert"], function (alert) {
|
||||
require(["alert"], function(alert) {
|
||||
alert({
|
||||
text: item.Overview
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function ActivityLog(options) {
|
||||
this.options = options;
|
||||
var element = options.element;
|
||||
element.classList.add("activityLogListWidget");
|
||||
element.addEventListener("click", onListClick.bind(this));
|
||||
element.classList.add("activityLogListWidget"), element.addEventListener("click", onListClick.bind(this));
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
reloadData(this, element, apiClient);
|
||||
var onUpdate = onActivityLogUpdate.bind(this);
|
||||
this.updateFn = onUpdate;
|
||||
events.on(serverNotifications, "ActivityLogEntry", onUpdate);
|
||||
apiClient.sendMessage("ActivityLogEntryStart", "0,1500");
|
||||
this.updateFn = onUpdate, events.on(serverNotifications, "ActivityLogEntry", onUpdate), apiClient.sendMessage("ActivityLogEntryStart", "0,1500")
|
||||
}
|
||||
|
||||
ActivityLog.prototype.destroy = function () {
|
||||
return ActivityLog.prototype.destroy = function() {
|
||||
var options = this.options;
|
||||
|
||||
if (options) {
|
||||
options.element.classList.remove("activityLogListWidget");
|
||||
connectionManager.getApiClient(options.serverId).sendMessage("ActivityLogEntryStop", "0,1500");
|
||||
connectionManager.getApiClient(options.serverId).sendMessage("ActivityLogEntryStop", "0,1500")
|
||||
}
|
||||
|
||||
var onUpdate = this.updateFn;
|
||||
|
||||
if (onUpdate) {
|
||||
events.off(serverNotifications, "ActivityLogEntry", onUpdate);
|
||||
}
|
||||
|
||||
this.items = null;
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return ActivityLog;
|
||||
onUpdate && events.off(serverNotifications, "ActivityLogEntry", onUpdate), this.items = null, this.options = null
|
||||
}, ActivityLog
|
||||
});
|
||||
|
||||
@@ -35,11 +35,11 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,7 @@ define(['dom', 'focusManager'], function (dom, focusManager) {
|
||||
if (e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
if (e.shiftKey) {
|
||||
if (!!e.shiftKey) {
|
||||
return;
|
||||
}
|
||||
if (e.altKey) {
|
||||
@@ -127,4 +127,4 @@ define(['dom', 'focusManager'], function (dom, focusManager) {
|
||||
};
|
||||
|
||||
return AlphaNumericShortcuts;
|
||||
});
|
||||
});
|
||||
@@ -50,7 +50,9 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
|
||||
var vertical = element.classList.contains('alphaPicker-vertical');
|
||||
|
||||
if (!vertical) {
|
||||
if (vertical) {
|
||||
|
||||
} else {
|
||||
element.classList.add('focuscontainer-x');
|
||||
}
|
||||
|
||||
@@ -67,7 +69,8 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
|
||||
html += '<div class="' + rowClassName + '">';
|
||||
if (options.mode === 'keyboard') {
|
||||
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="material-icons alphaPickerButtonIcon space_bar"></i></button>';
|
||||
// space_bar icon
|
||||
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon"></i></button>';
|
||||
} else {
|
||||
letters = ['#'];
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
@@ -77,7 +80,8 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
|
||||
if (options.mode === 'keyboard') {
|
||||
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="material-icons alphaPickerButtonIcon">backspace</i></button>';
|
||||
// backspace icon
|
||||
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon"></i></button>';
|
||||
html += '</div>';
|
||||
|
||||
letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
@@ -226,8 +230,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
AlphaPicker.prototype.value = function (value, applyValue) {
|
||||
|
||||
var element = this.options.element;
|
||||
var btn;
|
||||
var selected;
|
||||
var btn, selected;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (value != null) {
|
||||
@@ -241,7 +244,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
try {
|
||||
btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']');
|
||||
} catch (err) {
|
||||
console.error('error in querySelector: ' + err);
|
||||
console.log('Error in querySelector: ' + err);
|
||||
}
|
||||
|
||||
if (btn && btn !== selected) {
|
||||
@@ -318,4 +321,4 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
};
|
||||
|
||||
return AlphaPicker;
|
||||
});
|
||||
});
|
||||
@@ -35,15 +35,16 @@
|
||||
font-size: inherit;
|
||||
min-width: initial;
|
||||
margin: 0;
|
||||
padding: 0.1em 0.4em;
|
||||
padding: .1em .4em;
|
||||
width: auto;
|
||||
border-radius: 0.1em;
|
||||
border-radius: .1em;
|
||||
font-weight: normal;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
@media all and (max-height: 50em) {
|
||||
|
||||
.alphaPicker-fixed {
|
||||
bottom: 5em;
|
||||
}
|
||||
@@ -55,12 +56,14 @@
|
||||
}
|
||||
|
||||
@media all and (max-height: 49em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 94%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height: 44em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 90%;
|
||||
}
|
||||
@@ -72,12 +75,14 @@
|
||||
}
|
||||
|
||||
@media all and (max-height: 37em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 82%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height: 32em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 74%;
|
||||
}
|
||||
@@ -107,17 +112,27 @@
|
||||
bottom: 1%;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-left {
|
||||
left: .4em;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-right {
|
||||
right: 0.4em;
|
||||
right: .4em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 62.5em) {
|
||||
|
||||
.alphaPicker-fixed-left {
|
||||
left: 1em;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-right {
|
||||
right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height: 31.25em) {
|
||||
|
||||
.alphaPicker-fixed {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -14,9 +14,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
},
|
||||
showSettings: function () {
|
||||
show('/settings/settings.html');
|
||||
},
|
||||
showNowPlaying: function () {
|
||||
show("/nowplaying.html");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -390,13 +387,13 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
var pathname = ctx.pathname.toLowerCase();
|
||||
|
||||
console.debug('appRouter - processing path request ' + pathname);
|
||||
console.log('appRouter - processing path request ' + pathname);
|
||||
|
||||
var isCurrentRouteStartup = currentRouteInfo ? currentRouteInfo.route.startup : true;
|
||||
var shouldExitApp = ctx.isBack && route.isDefaultRoute && isCurrentRouteStartup;
|
||||
|
||||
if (!shouldExitApp && (!apiClient || !apiClient.isLoggedIn()) && !route.anonymous) {
|
||||
console.debug('appRouter - route does not allow anonymous access, redirecting to login');
|
||||
console.log('appRouter - route does not allow anonymous access, redirecting to login');
|
||||
beginConnectionWizard();
|
||||
return;
|
||||
}
|
||||
@@ -411,10 +408,10 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
|
||||
if (apiClient && apiClient.isLoggedIn()) {
|
||||
|
||||
console.debug('appRouter - user is authenticated');
|
||||
console.log('appRouter - user is authenticated');
|
||||
|
||||
if (route.isDefaultRoute) {
|
||||
console.debug('appRouter - loading skin home page');
|
||||
console.log('appRouter - loading skin home page');
|
||||
loadUserSkinWithOptions(ctx);
|
||||
return;
|
||||
} else if (route.roles) {
|
||||
@@ -428,13 +425,18 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
}
|
||||
|
||||
console.debug('appRouter - proceeding to ' + pathname);
|
||||
console.log('appRouter - proceeding to ' + pathname);
|
||||
callback();
|
||||
}
|
||||
|
||||
function loadUserSkinWithOptions(ctx) {
|
||||
|
||||
require(['queryString'], function (queryString) {
|
||||
|
||||
//var url = options.url;
|
||||
//var index = url.indexOf('?');
|
||||
var params = queryString.parse(ctx.querystring);
|
||||
|
||||
skinManager.loadUserSkin({
|
||||
start: params.start
|
||||
});
|
||||
@@ -442,13 +444,16 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
|
||||
function validateRoles(apiClient, roles) {
|
||||
|
||||
return Promise.all(roles.split(',').map(function (role) {
|
||||
return validateRole(apiClient, role);
|
||||
}));
|
||||
}
|
||||
|
||||
function validateRole(apiClient, role) {
|
||||
|
||||
if (role === 'admin') {
|
||||
|
||||
return apiClient.getCurrentUser().then(function (user) {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
return Promise.resolve();
|
||||
@@ -475,6 +480,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
route: route,
|
||||
path: ctx.path
|
||||
};
|
||||
//next();
|
||||
|
||||
ctx.handled = true;
|
||||
}
|
||||
@@ -497,6 +503,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
|
||||
function endsWith(str, srch) {
|
||||
|
||||
return str.lastIndexOf(srch) === srch.length - 1;
|
||||
}
|
||||
|
||||
@@ -506,7 +513,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
if (endsWith(baseRoute, '/') && !endsWith(baseRoute, '://')) {
|
||||
baseRoute = baseRoute.substring(0, baseRoute.length - 1);
|
||||
}
|
||||
|
||||
function baseUrl() {
|
||||
return baseRoute;
|
||||
}
|
||||
@@ -545,21 +551,19 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
|
||||
function back() {
|
||||
|
||||
page.back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pages of "no return" (when "Go back" should behave differently, probably quitting the application).
|
||||
*/
|
||||
var startPages = ['home', 'login', 'selectserver'];
|
||||
|
||||
function canGoBack() {
|
||||
|
||||
var curr = current();
|
||||
|
||||
if (!curr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!document.querySelector('.dialogContainer') && startPages.indexOf(curr.type) !== -1) {
|
||||
if (curr.type === 'home') {
|
||||
return false;
|
||||
}
|
||||
return page.canGoBack();
|
||||
@@ -572,6 +576,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
|
||||
function show(path, options) {
|
||||
|
||||
if (path.indexOf('/') !== 0 && path.indexOf('://') === -1) {
|
||||
path = '/' + path;
|
||||
}
|
||||
@@ -580,6 +585,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
path = path.replace(baseRoute, '');
|
||||
|
||||
if (currentRouteInfo && currentRouteInfo.path === path) {
|
||||
|
||||
// can't use this with home right now due to the back menu
|
||||
if (currentRouteInfo.route.type !== 'home') {
|
||||
loading.hide();
|
||||
@@ -588,6 +594,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
resolveOnNextShow = resolve;
|
||||
page.show(path, options);
|
||||
});
|
||||
@@ -608,12 +615,14 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
|
||||
function showItem(item, serverId, options) {
|
||||
|
||||
if (typeof (item) === 'string') {
|
||||
var apiClient = serverId ? connectionManager.getApiClient(serverId) : connectionManager.currentApiClient();
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (item) {
|
||||
appRouter.showItem(item, options);
|
||||
});
|
||||
} else {
|
||||
|
||||
if (arguments.length === 2) {
|
||||
options = arguments[1];
|
||||
}
|
||||
@@ -628,6 +637,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
var allRoutes = [];
|
||||
|
||||
function addRoute(path, newRoute) {
|
||||
|
||||
page(path, getHandler(newRoute));
|
||||
allRoutes.push(newRoute);
|
||||
}
|
||||
@@ -639,6 +649,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
var backdropContainer;
|
||||
var backgroundContainer;
|
||||
function setTransparency(level) {
|
||||
|
||||
if (!backdropContainer) {
|
||||
backdropContainer = document.querySelector('.backdropContainer');
|
||||
}
|
||||
@@ -651,7 +662,8 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
document.documentElement.classList.add('transparentDocument');
|
||||
backgroundContainer.classList.add('backgroundContainer-transparent');
|
||||
backdropContainer.classList.add('hide');
|
||||
} else if (level === 'backdrop' || level === 1) {
|
||||
}
|
||||
else if (level === 'backdrop' || level === 1) {
|
||||
backdrop.externalBackdrop(true);
|
||||
document.documentElement.classList.add('transparentDocument');
|
||||
backgroundContainer.classList.add('backgroundContainer-transparent');
|
||||
@@ -665,7 +677,9 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
}
|
||||
|
||||
function pushState(state, title, url) {
|
||||
|
||||
state.navigate = false;
|
||||
|
||||
page.pushState(state, title, url);
|
||||
}
|
||||
|
||||
@@ -675,25 +689,41 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
baseRoute = baseRoute.substring(0, baseRoute.length - 1);
|
||||
}
|
||||
|
||||
console.debug('setting page base to ' + baseRoute);
|
||||
console.log('Setting page base to ' + baseRoute);
|
||||
|
||||
page.base(baseRoute);
|
||||
}
|
||||
|
||||
setBaseRoute();
|
||||
|
||||
function syncNow() {
|
||||
require(['localsync'], function (localSync) {
|
||||
localSync.sync();
|
||||
});
|
||||
}
|
||||
|
||||
function invokeShortcut(id) {
|
||||
|
||||
if (id.indexOf('library-') === 0) {
|
||||
|
||||
id = id.replace('library-', '');
|
||||
|
||||
id = id.split('_');
|
||||
|
||||
appRouter.showItem(id[0], id[1]);
|
||||
|
||||
} else if (id.indexOf('item-') === 0) {
|
||||
|
||||
id = id.replace('item-', '');
|
||||
|
||||
id = id.split('_');
|
||||
|
||||
appRouter.showItem(id[0], id[1]);
|
||||
|
||||
} else {
|
||||
|
||||
id = id.split('_');
|
||||
|
||||
appRouter.show(appRouter.getRouteUrl(id[0], {
|
||||
serverId: id[1]
|
||||
}));
|
||||
@@ -710,7 +740,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
appRouter.canGoBack = canGoBack;
|
||||
appRouter.current = current;
|
||||
appRouter.beginConnectionWizard = beginConnectionWizard;
|
||||
appRouter.invokeShortcut = invokeShortcut;
|
||||
appRouter.showItem = showItem;
|
||||
appRouter.setTransparency = setTransparency;
|
||||
appRouter.getRoutes = getRoutes;
|
||||
@@ -722,6 +751,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
|
||||
Backdrop: 1,
|
||||
Full: 2
|
||||
};
|
||||
appRouter.invokeShortcut = invokeShortcut;
|
||||
|
||||
return appRouter;
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
'use strict';
|
||||
|
||||
function getKey(name, userId) {
|
||||
|
||||
if (userId) {
|
||||
name = userId + '-' + name;
|
||||
}
|
||||
@@ -10,9 +11,11 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
}
|
||||
|
||||
function AppSettings() {
|
||||
|
||||
}
|
||||
|
||||
AppSettings.prototype.enableAutoLogin = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('enableAutoLogin', val.toString());
|
||||
}
|
||||
@@ -21,8 +24,11 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.enableAutomaticBitrateDetection = function (isInNetwork, mediaType, val) {
|
||||
|
||||
var key = 'enableautobitratebitrate-' + mediaType + '-' + isInNetwork;
|
||||
|
||||
if (val != null) {
|
||||
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
val = true;
|
||||
}
|
||||
@@ -38,8 +44,11 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.maxStreamingBitrate = function (isInNetwork, mediaType, val) {
|
||||
|
||||
var key = 'maxbitrate-' + mediaType + '-' + isInNetwork;
|
||||
|
||||
if (val != null) {
|
||||
|
||||
if (isInNetwork && mediaType === 'Audio') {
|
||||
// nothing to do, this is always a max value
|
||||
} else {
|
||||
@@ -56,6 +65,7 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.maxStaticMusicBitrate = function (val) {
|
||||
|
||||
if (val !== undefined) {
|
||||
this.set('maxStaticMusicBitrate', val);
|
||||
}
|
||||
@@ -65,15 +75,18 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.maxChromecastBitrate = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('chromecastBitrate1', val);
|
||||
}
|
||||
|
||||
val = this.get('chromecastBitrate1');
|
||||
|
||||
return val ? parseInt(val) : null;
|
||||
};
|
||||
|
||||
AppSettings.prototype.syncOnlyOnWifi = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('syncOnlyOnWifi', val.toString());
|
||||
}
|
||||
@@ -82,6 +95,7 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.syncPath = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('syncPath', val);
|
||||
}
|
||||
@@ -90,11 +104,13 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.cameraUploadServers = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('cameraUploadServers', val.join(','));
|
||||
}
|
||||
|
||||
val = this.get('cameraUploadServers');
|
||||
|
||||
if (val) {
|
||||
return val.split(',');
|
||||
}
|
||||
@@ -103,6 +119,7 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.runAtStartup = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('runatstartup', val.toString());
|
||||
}
|
||||
@@ -111,7 +128,9 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.set = function (name, value, userId) {
|
||||
|
||||
var currentValue = this.get(name, userId);
|
||||
|
||||
appStorage.setItem(getKey(name, userId), value);
|
||||
|
||||
if (currentValue !== value) {
|
||||
@@ -120,10 +139,12 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
AppSettings.prototype.get = function (name, userId) {
|
||||
|
||||
return appStorage.getItem(getKey(name, userId));
|
||||
};
|
||||
|
||||
AppSettings.prototype.enableSystemExternalPlayers = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
this.set('enableSystemExternalPlayers', val.toString());
|
||||
}
|
||||
@@ -132,4 +153,4 @@ define(['appStorage', 'events'], function (appStorage, events) {
|
||||
};
|
||||
|
||||
return new AppSettings();
|
||||
});
|
||||
});
|
||||
@@ -2,12 +2,12 @@
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
z-index: 1;
|
||||
bottom: 0;
|
||||
transition: transform 180ms linear;
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
.appfooter.headroom--unpinned {
|
||||
transform: translateY(100%) !important;
|
||||
}
|
||||
.appfooter.headroom--unpinned {
|
||||
transform: translateY(100%)!important;
|
||||
}
|
||||
@@ -2,18 +2,24 @@ define(['browser', 'css!./appfooter'], function (browser) {
|
||||
'use strict';
|
||||
|
||||
function render(options) {
|
||||
|
||||
var elem = document.createElement('div');
|
||||
|
||||
elem.classList.add('appfooter');
|
||||
|
||||
elem.classList.add('appfooter-blurred');
|
||||
|
||||
document.body.appendChild(elem);
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
function appFooter(options) {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.element = render(options);
|
||||
|
||||
self.add = function (elem) {
|
||||
self.element.appendChild(elem);
|
||||
};
|
||||
|
||||
@@ -104,7 +104,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
|
||||
function getDeviceName() {
|
||||
var 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" : browser.safari ? "Safari" : "Web Browser";
|
||||
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";
|
||||
@@ -168,25 +168,23 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
var savedResult = appSettings.get(htmlMediaAutoplayAppStorageKey);
|
||||
return "true" === savedResult || "false" !== savedResult && null;
|
||||
}
|
||||
|
||||
function supportsCue() {
|
||||
function cueSupported() {
|
||||
try {
|
||||
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;
|
||||
document.body.removeChild(style);
|
||||
document.body.removeChild(video);
|
||||
|
||||
return !!cue.length;
|
||||
} catch (err) {
|
||||
console.error("error detecting cue support: " + err);
|
||||
console.log("Error detecting cue support:" + err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -194,7 +192,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
function onAppVisible() {
|
||||
if (isHidden) {
|
||||
isHidden = false;
|
||||
console.debug("triggering app resume event");
|
||||
console.log("triggering app resume event");
|
||||
events.trigger(appHost, "resume");
|
||||
}
|
||||
}
|
||||
@@ -202,10 +200,12 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
function onAppHidden() {
|
||||
if (!isHidden) {
|
||||
isHidden = true;
|
||||
console.debug("app is hidden");
|
||||
console.log("app is hidden");
|
||||
}
|
||||
}
|
||||
|
||||
var htmlMediaAutoplayAppStorageKey = "supportshtmlmediaautoplay0";
|
||||
|
||||
var supportedFeatures = function () {
|
||||
var features = [];
|
||||
|
||||
@@ -278,9 +278,8 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
features.push("targetblank");
|
||||
// allows users to connect to more than one server
|
||||
//features.push("multiserver");
|
||||
features.push("screensaver");
|
||||
|
||||
if (!browser.orsay && !browser.tizen && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
|
||||
if (!browser.orsay && !browser.tizen && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || cueSupported())) {
|
||||
features.push("subtitleappearancesettings");
|
||||
}
|
||||
|
||||
@@ -299,48 +298,14 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
return features;
|
||||
}();
|
||||
|
||||
/**
|
||||
* Do exit according to platform
|
||||
*/
|
||||
function doExit() {
|
||||
try {
|
||||
if (window.NativeShell) {
|
||||
window.NativeShell.AppHost.exit();
|
||||
} else if (browser.tizen) {
|
||||
tizen.application.getCurrentApplication().exit();
|
||||
} else if (browser.web0s) {
|
||||
webOS.platformBack();
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("error closing application: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
var exitPromise;
|
||||
|
||||
/**
|
||||
* Ask user for exit
|
||||
*/
|
||||
function askForExit() {
|
||||
if (exitPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
require(["actionsheet"], function (actionsheet) {
|
||||
exitPromise = actionsheet.show({
|
||||
title: Globalize.translate("MessageConfirmAppExit"),
|
||||
items: [
|
||||
{id: "yes", name: Globalize.translate("Yes")},
|
||||
{id: "no", name: Globalize.translate("No")}
|
||||
]
|
||||
}).then(function (value) {
|
||||
if (value === "yes") {
|
||||
doExit();
|
||||
}
|
||||
}).finally(function () {
|
||||
exitPromise = null;
|
||||
if (supportedFeatures.indexOf("htmlvideoautoplay") === -1 && supportsHtmlMediaAutoplay() !== false) {
|
||||
require(["autoPlayDetect"], function (autoPlayDetect) {
|
||||
autoPlayDetect.supportsHtmlMediaAutoplay().then(function () {
|
||||
appSettings.set(htmlMediaAutoplayAppStorageKey, "true");
|
||||
supportedFeatures.push("htmlvideoautoplay");
|
||||
supportedFeatures.push("htmlaudioautoplay");
|
||||
}, function () {
|
||||
appSettings.set(htmlMediaAutoplayAppStorageKey, "false");
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -348,7 +313,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
var deviceId;
|
||||
var deviceName;
|
||||
var appName = "Jellyfin Web";
|
||||
var appVersion = "10.5.5";
|
||||
var appVersion = "10.4.3";
|
||||
var visibilityChange;
|
||||
var visibilityState;
|
||||
|
||||
@@ -360,10 +325,16 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
alert("setWindowState is not supported and should not be called");
|
||||
},
|
||||
exit: function () {
|
||||
if (!!window.appMode && browser.tizen) {
|
||||
askForExit();
|
||||
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 {
|
||||
doExit();
|
||||
window.close();
|
||||
}
|
||||
},
|
||||
supports: function (command) {
|
||||
@@ -374,7 +345,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase());
|
||||
},
|
||||
preferVisualCards: browser.android || browser.chrome,
|
||||
moreIcon: browser.android ? "more_vert" : "more_horiz",
|
||||
moreIcon: browser.android ? "dots-vert" : "dots-horiz",
|
||||
getSyncProfile: getSyncProfile,
|
||||
getDefaultLayout: function () {
|
||||
if (window.NativeShell) {
|
||||
@@ -423,9 +394,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var doc = self.document;
|
||||
var isHidden = false;
|
||||
|
||||
if (doc) {
|
||||
if (void 0 !== doc.visibilityState) {
|
||||
@@ -449,6 +418,8 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet
|
||||
}
|
||||
}
|
||||
|
||||
var isHidden = false;
|
||||
|
||||
if (doc) {
|
||||
doc.addEventListener(visibilityChange, function () {
|
||||
if (document[visibilityState]) {
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
define(["focusManager", "layoutManager"], function (focusManager, layoutManager) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Previously selected element.
|
||||
*/
|
||||
var activeElement;
|
||||
|
||||
/**
|
||||
* Returns true if AutoFocuser is enabled.
|
||||
*/
|
||||
function isEnabled() {
|
||||
return layoutManager.tv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start AutoFocuser
|
||||
*/
|
||||
function enable() {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener("focusin", function (e) {
|
||||
activeElement = e.target;
|
||||
});
|
||||
|
||||
console.debug("AutoFocuser enabled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an array from some source.
|
||||
*/
|
||||
var arrayFrom = Array.prototype.from || function (src) {
|
||||
return Array.prototype.slice.call(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set focus on a suitable element, taking into account the previously selected.
|
||||
*/
|
||||
function autoFocus(container) {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
container = container || document.body;
|
||||
|
||||
var candidates = [];
|
||||
|
||||
if (activeElement) {
|
||||
// These elements are recreated
|
||||
if (activeElement.classList.contains("btnPreviousPage")) {
|
||||
candidates.push(container.querySelector(".btnPreviousPage"));
|
||||
candidates.push(container.querySelector(".btnNextPage"));
|
||||
} else if (activeElement.classList.contains("btnNextPage")) {
|
||||
candidates.push(container.querySelector(".btnNextPage"));
|
||||
candidates.push(container.querySelector(".btnPreviousPage"));
|
||||
} else if (activeElement.classList.contains("btnSelectView")) {
|
||||
candidates.push(container.querySelector(".btnSelectView"));
|
||||
}
|
||||
|
||||
candidates.push(activeElement);
|
||||
}
|
||||
|
||||
candidates = candidates.concat(arrayFrom(container.querySelectorAll(".btnResume")));
|
||||
candidates = candidates.concat(arrayFrom(container.querySelectorAll(".btnPlay")));
|
||||
|
||||
var focusedElement;
|
||||
|
||||
candidates.every(function (element) {
|
||||
if (focusManager.isCurrentlyFocusable(element)) {
|
||||
focusManager.focus(element);
|
||||
focusedElement = element;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!focusedElement) {
|
||||
// FIXME: Multiple itemsContainers
|
||||
var itemsContainer = container.querySelector(".itemsContainer");
|
||||
|
||||
if (itemsContainer) {
|
||||
focusedElement = focusManager.autoFocus(itemsContainer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!focusedElement) {
|
||||
focusedElement = focusManager.autoFocus(container);
|
||||
}
|
||||
|
||||
return focusedElement;
|
||||
}
|
||||
|
||||
return {
|
||||
isEnabled: isEnabled,
|
||||
enable: enable,
|
||||
autoFocus: autoFocus
|
||||
};
|
||||
});
|
||||
@@ -1,7 +1,8 @@
|
||||
define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings", 'css!./backdrop'], function (browser, connectionManager, playbackManager, dom, userSettings) {
|
||||
define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./style'], function (browser, connectionManager, playbackManager, dom) {
|
||||
'use strict';
|
||||
|
||||
function enableAnimation(elem) {
|
||||
|
||||
if (browser.slow) {
|
||||
return false;
|
||||
}
|
||||
@@ -10,6 +11,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
}
|
||||
|
||||
function enableRotation() {
|
||||
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
@@ -23,13 +25,17 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
}
|
||||
|
||||
function Backdrop() {
|
||||
|
||||
}
|
||||
|
||||
Backdrop.prototype.load = function (url, parent, existingBackdropImage) {
|
||||
|
||||
var img = new Image();
|
||||
|
||||
var self = this;
|
||||
|
||||
img.onload = function () {
|
||||
|
||||
if (self.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
@@ -69,7 +75,6 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
|
||||
internalBackdrop(true);
|
||||
};
|
||||
|
||||
img.src = url;
|
||||
};
|
||||
|
||||
@@ -82,12 +87,14 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
};
|
||||
|
||||
Backdrop.prototype.destroy = function () {
|
||||
|
||||
this.isDestroyed = true;
|
||||
this.cancelAnimation();
|
||||
};
|
||||
|
||||
var backdropContainer;
|
||||
function getBackdropContainer() {
|
||||
|
||||
if (!backdropContainer) {
|
||||
backdropContainer = document.querySelector('.backdropContainer');
|
||||
}
|
||||
@@ -102,6 +109,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
}
|
||||
|
||||
function clearBackdrop(clearAll) {
|
||||
|
||||
clearRotation();
|
||||
|
||||
if (currentLoadingBackdrop) {
|
||||
@@ -115,7 +123,6 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
if (clearAll) {
|
||||
hasExternalBackdrop = false;
|
||||
}
|
||||
|
||||
internalBackdrop(false);
|
||||
}
|
||||
|
||||
@@ -126,8 +133,8 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
}
|
||||
return backgroundContainer;
|
||||
}
|
||||
|
||||
function setBackgroundContainerBackgroundEnabled() {
|
||||
|
||||
if (hasInternalBackdrop || hasExternalBackdrop) {
|
||||
getBackgroundContainer().classList.add('withBackdrop');
|
||||
} else {
|
||||
@@ -153,6 +160,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
|
||||
var currentLoadingBackdrop;
|
||||
function setBackdropImage(url) {
|
||||
|
||||
if (currentLoadingBackdrop) {
|
||||
currentLoadingBackdrop.destroy();
|
||||
currentLoadingBackdrop = null;
|
||||
@@ -173,27 +181,48 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
currentLoadingBackdrop = instance;
|
||||
}
|
||||
|
||||
var standardWidths = [480, 720, 1280, 1440, 1920];
|
||||
function getBackdropMaxWidth() {
|
||||
|
||||
var width = dom.getWindowSize().innerWidth;
|
||||
|
||||
if (standardWidths.indexOf(width) !== -1) {
|
||||
return width;
|
||||
}
|
||||
|
||||
var roundScreenTo = 100;
|
||||
width = Math.floor(width / roundScreenTo) * roundScreenTo;
|
||||
|
||||
return Math.min(width, 1920);
|
||||
}
|
||||
|
||||
function getItemImageUrls(item, imageOptions) {
|
||||
|
||||
imageOptions = imageOptions || {};
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
if (item.BackdropImageTags && item.BackdropImageTags.length > 0) {
|
||||
|
||||
return item.BackdropImageTags.map(function (imgTag, index) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
|
||||
type: "Backdrop",
|
||||
tag: imgTag,
|
||||
maxWidth: dom.getScreenWidth(),
|
||||
maxWidth: getBackdropMaxWidth(),
|
||||
index: index
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
|
||||
|
||||
return item.ParentBackdropImageTags.map(function (imgTag, index) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
|
||||
type: "Backdrop",
|
||||
tag: imgTag,
|
||||
maxWidth: dom.getScreenWidth(),
|
||||
maxWidth: getBackdropMaxWidth(),
|
||||
index: index
|
||||
}));
|
||||
});
|
||||
@@ -203,13 +232,17 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
}
|
||||
|
||||
function getImageUrls(items, imageOptions) {
|
||||
|
||||
var list = [];
|
||||
|
||||
var onImg = function (img) {
|
||||
list.push(img);
|
||||
};
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var itemImages = getItemImageUrls(items[i], imageOptions);
|
||||
|
||||
itemImages.forEach(onImg);
|
||||
}
|
||||
|
||||
@@ -229,35 +262,33 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
|
||||
// If you don't care about the order of the elements inside
|
||||
// the array, you should sort both arrays here.
|
||||
|
||||
for (var i = 0; i < a.length; ++i) {
|
||||
if (a[i] !== b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function enabled() {
|
||||
return userSettings.enableBackdrops();
|
||||
}
|
||||
|
||||
var rotationInterval;
|
||||
var currentRotatingImages = [];
|
||||
var currentRotationIndex = -1;
|
||||
function setBackdrops(items, imageOptions, enableImageRotation) {
|
||||
if (enabled()) {
|
||||
var images = getImageUrls(items, imageOptions);
|
||||
|
||||
if (images.length) {
|
||||
startRotation(images, enableImageRotation);
|
||||
} else {
|
||||
clearBackdrop();
|
||||
}
|
||||
var images = getImageUrls(items, imageOptions);
|
||||
|
||||
if (images.length) {
|
||||
|
||||
startRotation(images, enableImageRotation);
|
||||
|
||||
} else {
|
||||
clearBackdrop();
|
||||
}
|
||||
}
|
||||
|
||||
function startRotation(images, enableImageRotation) {
|
||||
|
||||
if (arraysEqual(images, currentRotatingImages)) {
|
||||
return;
|
||||
}
|
||||
@@ -270,11 +301,11 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
if (images.length > 1 && enableImageRotation !== false && enableRotation()) {
|
||||
rotationInterval = setInterval(onRotationInterval, 24000);
|
||||
}
|
||||
|
||||
onRotationInterval();
|
||||
}
|
||||
|
||||
function onRotationInterval() {
|
||||
|
||||
if (playbackManager.isPlayingLocally(['Video'])) {
|
||||
return;
|
||||
}
|
||||
@@ -293,29 +324,35 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', "userSettings"
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
|
||||
rotationInterval = null;
|
||||
currentRotatingImages = [];
|
||||
currentRotationIndex = -1;
|
||||
}
|
||||
|
||||
function setBackdrop(url, imageOptions) {
|
||||
if (url && typeof url !== 'string') {
|
||||
url = getImageUrls([url], imageOptions)[0];
|
||||
|
||||
if (url) {
|
||||
if (typeof url !== 'string') {
|
||||
url = getImageUrls([url], imageOptions)[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (url) {
|
||||
clearRotation();
|
||||
|
||||
setBackdropImage(url);
|
||||
|
||||
} else {
|
||||
clearBackdrop();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
setBackdrops: setBackdrops,
|
||||
setBackdrop: setBackdrop,
|
||||
clear: clearBackdrop,
|
||||
externalBackdrop: externalBackdrop
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
3
src/components/backdrop/package.json
Normal file
3
src/components/backdrop/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "backdrop.js"
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
define(["connectionManager"], function (connectionManager) {
|
||||
|
||||
return function () {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.name = "Backdrop ScreenSaver";
|
||||
self.type = "screensaver";
|
||||
self.id = "backdropscreensaver";
|
||||
self.supportsAnonymous = false;
|
||||
|
||||
var currentSlideshow;
|
||||
|
||||
self.show = function () {
|
||||
|
||||
var query = {
|
||||
ImageTypes: "Backdrop",
|
||||
EnableImageTypes: "Backdrop",
|
||||
IncludeItemTypes: "Movie,Series,MusicArtist",
|
||||
SortBy: "Random",
|
||||
Recursive: true,
|
||||
Fields: "Taglines",
|
||||
ImageTypeLimit: 1,
|
||||
StartIndex: 0,
|
||||
Limit: 200
|
||||
};
|
||||
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), query).then(function (result) {
|
||||
|
||||
if (result.Items.length) {
|
||||
|
||||
require(["slideshow"], function (slideshow) {
|
||||
|
||||
var newSlideShow = new slideshow({
|
||||
showTitle: true,
|
||||
cover: true,
|
||||
items: result.Items
|
||||
});
|
||||
|
||||
newSlideShow.show();
|
||||
currentSlideshow = newSlideShow;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.hide = function () {
|
||||
|
||||
if (currentSlideshow) {
|
||||
currentSlideshow.hide();
|
||||
currentSlideshow = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -30,6 +30,7 @@ define([], function () {
|
||||
}
|
||||
|
||||
function isMobile(userAgent) {
|
||||
|
||||
var terms = [
|
||||
'mobi',
|
||||
'ipad',
|
||||
@@ -77,10 +78,10 @@ define([], function () {
|
||||
var camel = prop.replace(/-([a-z]|[0-9])/ig, function (all, letter) {
|
||||
return (letter + '').toUpperCase();
|
||||
});
|
||||
// Create test element
|
||||
var el = document.createElement('div');
|
||||
// Check if the property is supported
|
||||
var support = (camel in el.style);
|
||||
// Create test element
|
||||
var el = document.createElement('div');
|
||||
// Assign the property and value to invoke
|
||||
// the CSS interpreter
|
||||
el.style.cssText = prop + ':' + value;
|
||||
@@ -121,8 +122,7 @@ define([], function () {
|
||||
}
|
||||
|
||||
function iOSversion() {
|
||||
// MacIntel: Apple iPad Pro 11 iOS 13.1
|
||||
if (/iP(hone|od|ad)|MacIntel/.test(navigator.platform)) {
|
||||
if (/iP(hone|od|ad)/.test(navigator.platform)) {
|
||||
// supports iOS 2.0 and later: <http://bit.ly/TJjs1V>
|
||||
var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
|
||||
return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)];
|
||||
@@ -143,16 +143,14 @@ define([], function () {
|
||||
}
|
||||
}
|
||||
|
||||
var animation = false;
|
||||
var animationstring = 'animation';
|
||||
var keyframeprefix = '';
|
||||
var domPrefixes = ['Webkit', 'O', 'Moz'];
|
||||
var pfx = '';
|
||||
var elm = document.createElement('div');
|
||||
var animation = false,
|
||||
animationstring = 'animation',
|
||||
keyframeprefix = '',
|
||||
domPrefixes = ['Webkit', 'O', 'Moz'],
|
||||
pfx = '',
|
||||
elm = document.createElement('div');
|
||||
|
||||
if (elm.style.animationName !== undefined) {
|
||||
animation = true;
|
||||
}
|
||||
if (elm.style.animationName !== undefined) { animation = true; }
|
||||
|
||||
if (animation === false && allowPrefix) {
|
||||
for (var i = 0; i < domPrefixes.length; i++) {
|
||||
@@ -205,7 +203,8 @@ define([], function () {
|
||||
|
||||
// http://www.neowin.net/news/ie11-fakes-user-agent-to-fool-gmail-in-windows-phone-81-gdr1-update
|
||||
browser = "msie";
|
||||
} else if (ua.indexOf("like gecko") !== -1 && ua.indexOf('webkit') === -1 && ua.indexOf('opera') === -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') === -1) {
|
||||
}
|
||||
else if (ua.indexOf("like gecko") !== -1 && ua.indexOf('webkit') === -1 && ua.indexOf('opera') === -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') === -1) {
|
||||
browser = "msie";
|
||||
}
|
||||
}
|
||||
@@ -271,9 +270,6 @@ define([], function () {
|
||||
|
||||
if (!browser.tizen) {
|
||||
browser.orsay = userAgent.toLowerCase().indexOf('smarthub') !== -1;
|
||||
} else {
|
||||
var v = (navigator.appVersion).match(/Tizen (\d+).(\d+)/);
|
||||
browser.tizenVersion = parseInt(v[1]);
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
@@ -305,13 +301,10 @@ define([], function () {
|
||||
|
||||
if (browser.iOS) {
|
||||
browser.iOSVersion = iOSversion();
|
||||
|
||||
if (browser.iOSVersion && browser.iOSVersion.length >= 2) {
|
||||
browser.iOSVersion = browser.iOSVersion[0] + (browser.iOSVersion[1] / 10);
|
||||
}
|
||||
browser.iOSVersion = browser.iOSVersion[0] + (browser.iOSVersion[1] / 10);
|
||||
}
|
||||
|
||||
browser.chromecast = browser.chrome && userAgent.toLowerCase().indexOf('crkey') !== -1;
|
||||
|
||||
return browser;
|
||||
});
|
||||
});
|
||||
@@ -6,31 +6,32 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
|
||||
function canPlayH265(videoTestElement, options) {
|
||||
|
||||
if (browser.tizen || browser.orsay || browser.xboxOne || browser.web0s || options.supportsHevc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
if (browser.chromecast) {
|
||||
|
||||
var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
||||
if (isChromecastUltra) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (browser.ps4) {
|
||||
return false;
|
||||
// Unfortunately haven't yet found a canPlayType for proper detection
|
||||
if (browser.iOS && (browser.iOSVersion || 0) >= 11) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !!videoTestElement.canPlayType &&
|
||||
(videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.L120"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.L120"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.0.L120"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.0.L120"').replace(/no/, ''));
|
||||
return !!(videoTestElement.canPlayType && videoTestElement.canPlayType('video/hevc; codecs="hevc, aac"').replace(/no/, ''));
|
||||
}
|
||||
|
||||
var _supportsTextTracks;
|
||||
function supportsTextTracks() {
|
||||
|
||||
if (browser.tizen || browser.orsay) {
|
||||
return true;
|
||||
}
|
||||
@@ -44,15 +45,16 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
|
||||
var _canPlayHls;
|
||||
function canPlayHls() {
|
||||
function canPlayHls(src) {
|
||||
|
||||
if (_canPlayHls == null) {
|
||||
_canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE();
|
||||
}
|
||||
|
||||
return _canPlayHls;
|
||||
}
|
||||
|
||||
function canPlayNativeHls() {
|
||||
|
||||
if (browser.tizen || browser.orsay) {
|
||||
return true;
|
||||
}
|
||||
@@ -67,66 +69,48 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
|
||||
function canPlayHlsWithMSE() {
|
||||
// text tracks don’t work with this in firefox
|
||||
return window.MediaSource != null;
|
||||
}
|
||||
|
||||
function supportsAc3(videoTestElement) {
|
||||
if (browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s) {
|
||||
if (window.MediaSource != null) {
|
||||
// text tracks don’t work with this in firefox
|
||||
return true;
|
||||
}
|
||||
|
||||
return videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/, '');
|
||||
}
|
||||
|
||||
function supportsEac3(videoTestElement) {
|
||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/, '');
|
||||
}
|
||||
|
||||
function supportsAc3InHls(videoTestElement) {
|
||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (videoTestElement.canPlayType) {
|
||||
return videoTestElement.canPlayType('application/x-mpegurl; codecs="avc1.42E01E, ac-3"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('application/vnd.apple.mpegURL; codecs="avc1.42E01E, ac-3"').replace(/no/, '');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function canPlayAudioFormat(format) {
|
||||
|
||||
var typeString;
|
||||
|
||||
if (format === 'flac') {
|
||||
if (browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp) {
|
||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
||||
return true;
|
||||
}
|
||||
} else if (format === 'wma') {
|
||||
if (browser.tizen || browser.orsay || browser.edgeUwp) {
|
||||
if (browser.edgeUwp) {
|
||||
return true;
|
||||
}
|
||||
} else if (format === 'asf') {
|
||||
if (browser.tizen || browser.web0s || browser.edgeUwp) {
|
||||
}
|
||||
|
||||
else if (format === 'wma') {
|
||||
if (browser.tizen || browser.orsay) {
|
||||
return true;
|
||||
}
|
||||
} else if (format === 'opus') {
|
||||
if (!browser.web0s) {
|
||||
typeString = 'audio/ogg; codecs="opus"';
|
||||
return !!document.createElement('audio').canPlayType(typeString).replace(/no/, '');
|
||||
if (browser.edgeUwp) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
else if (format === 'opus') {
|
||||
typeString = 'audio/ogg; codecs="opus"';
|
||||
|
||||
if (document.createElement('audio').canPlayType(typeString).replace(/no/, '')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if (format === 'alac') {
|
||||
if (browser.iOS || browser.osx) {
|
||||
return true;
|
||||
}
|
||||
} else if (format === 'mp2') {
|
||||
}
|
||||
|
||||
else if (format === 'mp2') {
|
||||
|
||||
// For now
|
||||
return false;
|
||||
}
|
||||
@@ -135,14 +119,27 @@ define(['browser'], function (browser) {
|
||||
typeString = 'audio/webm';
|
||||
} else if (format === 'mp2') {
|
||||
typeString = 'audio/mpeg';
|
||||
} else if (format === 'ogg' || format === 'oga') {
|
||||
|
||||
// chrome says probably, but seeing failures
|
||||
if (browser.chrome) {
|
||||
return false;
|
||||
}
|
||||
typeString = 'audio/' + format;
|
||||
|
||||
} else {
|
||||
typeString = 'audio/' + format;
|
||||
}
|
||||
|
||||
return !!document.createElement('audio').canPlayType(typeString).replace(/no/, '');
|
||||
if (document.createElement('audio').canPlayType(typeString).replace(/no/, '')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function testCanPlayMkv(videoTestElement) {
|
||||
|
||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
||||
return true;
|
||||
}
|
||||
@@ -152,15 +149,16 @@ define(['browser'], function (browser) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
// Unfortunately there's no real way to detect mkv support
|
||||
if (browser.chrome) {
|
||||
|
||||
// Not supported on opera tv
|
||||
if (browser.operaTv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
// Filter out browsers based on chromium that don't support mkv
|
||||
if (userAgent.indexOf('vivaldi') !== -1 || userAgent.indexOf('opera') !== -1) {
|
||||
return false;
|
||||
@@ -170,6 +168,7 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -181,15 +180,17 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
|
||||
function supportsMpeg2Video() {
|
||||
return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
||||
return browser.orsay || browser.tizen || browser.edgeUwp || browser.web0s;
|
||||
}
|
||||
|
||||
function supportsVc1() {
|
||||
return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
||||
return browser.orsay || browser.tizen || browser.edgeUwp || browser.web0s;
|
||||
}
|
||||
|
||||
function getFlvMseDirectPlayProfile() {
|
||||
|
||||
var videoAudioCodecs = ['aac'];
|
||||
|
||||
if (!browser.edge && !browser.msie) {
|
||||
videoAudioCodecs.push('mp3');
|
||||
}
|
||||
@@ -203,30 +204,23 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
|
||||
function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) {
|
||||
|
||||
var supported = false;
|
||||
var profileContainer = container;
|
||||
var videoCodecs = [];
|
||||
|
||||
switch (container) {
|
||||
|
||||
case 'asf':
|
||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
||||
supported = browser.tizen || browser.orsay || browser.edgeUwp;
|
||||
videoAudioCodecs = [];
|
||||
break;
|
||||
case 'avi':
|
||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
||||
// New Samsung TV don't support XviD/DivX
|
||||
// Explicitly add supported codecs to make other codecs be transcoded
|
||||
if (browser.tizenVersion >= 4) {
|
||||
videoCodecs.push('h264');
|
||||
if (canPlayH265(videoTestElement, options)) {
|
||||
videoCodecs.push('h265');
|
||||
videoCodecs.push('hevc');
|
||||
}
|
||||
}
|
||||
supported = browser.tizen || browser.orsay || browser.edgeUwp;
|
||||
break;
|
||||
case 'mpg':
|
||||
case 'mpeg':
|
||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
||||
supported = browser.edgeUwp || browser.tizen || browser.orsay;
|
||||
break;
|
||||
case 'flv':
|
||||
supported = browser.tizen || browser.orsay;
|
||||
@@ -242,7 +236,7 @@ define(['browser'], function (browser) {
|
||||
supported = browser.tizen || browser.orsay;
|
||||
break;
|
||||
case 'mov':
|
||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.chrome || browser.edgeUwp;
|
||||
supported = browser.tizen || browser.orsay || browser.chrome || browser.edgeUwp;
|
||||
videoCodecs.push('h264');
|
||||
break;
|
||||
case 'm2ts':
|
||||
@@ -278,21 +272,29 @@ define(['browser'], function (browser) {
|
||||
break;
|
||||
}
|
||||
|
||||
return supported ? {
|
||||
if (!supported) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
Container: profileContainer,
|
||||
Type: 'Video',
|
||||
VideoCodec: videoCodecs.join(','),
|
||||
AudioCodec: videoAudioCodecs.join(',')
|
||||
} : null;
|
||||
};
|
||||
}
|
||||
|
||||
function getMaxBitrate() {
|
||||
|
||||
return 120000000;
|
||||
}
|
||||
|
||||
function getGlobalMaxVideoBitrate() {
|
||||
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
if (browser.chromecast) {
|
||||
|
||||
var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
||||
if (isChromecastUltra) {
|
||||
return null;
|
||||
@@ -311,9 +313,9 @@ define(['browser'], function (browser) {
|
||||
try {
|
||||
var isTizenUhd = webapis.productinfo.isUdPanelSupported();
|
||||
isTizenFhd = !isTizenUhd;
|
||||
console.debug("isTizenFhd = " + isTizenFhd);
|
||||
console.log("isTizenFhd = " + isTizenFhd);
|
||||
} catch (error) {
|
||||
console.error("isUdPanelSupported() error code = " + error.code);
|
||||
console.log("isUdPanelSupported() error code = " + error.code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,9 +325,27 @@ define(['browser'], function (browser) {
|
||||
(browser.tizen && isTizenFhd ? 20000000 : null)));
|
||||
}
|
||||
|
||||
return function (options) {
|
||||
options = options || {};
|
||||
function supportsAc3(videoTestElement) {
|
||||
|
||||
if (browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/, '') && !browser.osx && !browser.iOS);
|
||||
}
|
||||
|
||||
function supportsEac3(videoTestElement) {
|
||||
|
||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/, '');
|
||||
}
|
||||
|
||||
return function (options) {
|
||||
|
||||
options = options || {};
|
||||
var physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2);
|
||||
|
||||
var bitrateSetting = getMaxBitrate();
|
||||
@@ -384,7 +404,8 @@ define(['browser'], function (browser) {
|
||||
|
||||
// This works in edge desktop, but not mobile
|
||||
// TODO: Retest this on mobile
|
||||
if (supportsAc3InHls(videoTestElement)) {
|
||||
var supportsAc3InHls = (!browser.edge || !browser.touch || browser.edgeUwp);
|
||||
if (supportsAc3InHls) {
|
||||
hlsVideoAudioCodecs.push('ac3');
|
||||
if (eAc3) {
|
||||
hlsVideoAudioCodecs.push('eac3');
|
||||
@@ -402,6 +423,7 @@ define(['browser'], function (browser) {
|
||||
|
||||
// PS4 fails to load HLS with mp3 audio
|
||||
if (!browser.ps4) {
|
||||
|
||||
// mp3 encoder only supports 2 channels, so only make that preferred if we're only requesting 2 channels
|
||||
// Also apply it for chromecast because it no longer supports AAC 5.1
|
||||
if (physicalAudioChannels <= 2) {
|
||||
@@ -409,15 +431,14 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canPlayAacVideoAudio) {
|
||||
|
||||
if (videoAudioCodecs.indexOf('aac') === -1) {
|
||||
videoAudioCodecs.push('aac');
|
||||
}
|
||||
|
||||
hlsVideoAudioCodecs.push('aac');
|
||||
}
|
||||
|
||||
if (supportsMp3VideoAudio) {
|
||||
// PS4 fails to load HLS with mp3 audio
|
||||
if (!browser.ps4) {
|
||||
@@ -433,9 +454,13 @@ define(['browser'], function (browser) {
|
||||
|
||||
var supportsDts = browser.tizen || browser.orsay || browser.web0s || options.supportsDts;
|
||||
|
||||
// DTS audio not supported in 2018 models (Tizen 4.0)
|
||||
if (browser.tizenVersion >= 4) {
|
||||
supportsDts = false;
|
||||
if (self.tizen && self.tizen.systeminfo) {
|
||||
var v = tizen.systeminfo.getCapability('http://tizen.org/feature/platform.version');
|
||||
|
||||
// DTS audio not supported in 2018 models (Tizen 4.0)
|
||||
if (v && parseFloat(v) >= parseFloat('4.0')) {
|
||||
supportsDts = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsDts) {
|
||||
@@ -481,7 +506,6 @@ define(['browser'], function (browser) {
|
||||
mp4VideoCodecs.push('h264');
|
||||
hlsVideoCodecs.push('h264');
|
||||
}
|
||||
|
||||
if (canPlayH265(videoTestElement, options)) {
|
||||
mp4VideoCodecs.push('h265');
|
||||
mp4VideoCodecs.push('hevc');
|
||||
@@ -507,7 +531,6 @@ define(['browser'], function (browser) {
|
||||
if (canPlayVp8) {
|
||||
mp4VideoCodecs.push('vp8');
|
||||
}
|
||||
|
||||
if (canPlayVp9) {
|
||||
mp4VideoCodecs.push('vp9');
|
||||
}
|
||||
@@ -546,17 +569,22 @@ define(['browser'], function (browser) {
|
||||
['opus', 'mp3', 'mp2', 'aac', 'flac', 'alac', 'webma', 'wma', 'wav', 'ogg', 'oga'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
|
||||
|
||||
if (audioFormat === 'mp2') {
|
||||
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'mp2,mp3',
|
||||
Type: 'Audio',
|
||||
AudioCodec: audioFormat
|
||||
});
|
||||
} else if (audioFormat === 'mp3') {
|
||||
}
|
||||
|
||||
else if (audioFormat === 'mp3') {
|
||||
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: audioFormat,
|
||||
Type: 'Audio',
|
||||
AudioCodec: audioFormat
|
||||
});
|
||||
|
||||
} else {
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: audioFormat === 'webma' ? 'webma,webm' : audioFormat,
|
||||
@@ -564,10 +592,11 @@ define(['browser'], function (browser) {
|
||||
});
|
||||
}
|
||||
|
||||
// aac also appears in the m4a and m4b container
|
||||
// aac also appears in the m4a container
|
||||
if (audioFormat === 'aac' || audioFormat === 'alac') {
|
||||
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'm4a,m4b',
|
||||
Container: 'm4a',
|
||||
AudioCodec: audioFormat,
|
||||
Type: 'Audio'
|
||||
});
|
||||
@@ -598,6 +627,7 @@ define(['browser'], function (browser) {
|
||||
|
||||
if (canPlayHls() && browser.enableHlsAudio !== false) {
|
||||
profile.TranscodingProfiles.push({
|
||||
|
||||
// hlsjs, edge, and android all seem to require ts container
|
||||
Container: !canPlayNativeHls() || browser.edge || browser.android ? 'ts' : 'aac',
|
||||
Type: 'Audio',
|
||||
@@ -614,6 +644,7 @@ define(['browser'], function (browser) {
|
||||
// But for static (offline sync), it will be just fine.
|
||||
// Prioritize aac higher because the encoder can accept more channels than mp3
|
||||
['aac', 'mp3', 'opus', 'wav'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
|
||||
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: audioFormat,
|
||||
Type: 'Audio',
|
||||
@@ -625,6 +656,7 @@ define(['browser'], function (browser) {
|
||||
});
|
||||
|
||||
['opus', 'mp3', 'aac', 'wav'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
|
||||
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: audioFormat,
|
||||
Type: 'Audio',
|
||||
@@ -659,7 +691,7 @@ define(['browser'], function (browser) {
|
||||
});
|
||||
}
|
||||
|
||||
if (canPlayHls() && hlsVideoAudioCodecs.length && options.enableHls !== false) {
|
||||
if (canPlayHls() && options.enableHls !== false) {
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'ts',
|
||||
Type: 'Video',
|
||||
@@ -754,26 +786,11 @@ define(['browser'], function (browser) {
|
||||
});
|
||||
}
|
||||
|
||||
var maxH264Level = 42;
|
||||
var maxH264Level = browser.chromecast ? 42 : 51;
|
||||
var h264Profiles = 'high|main|baseline|constrained baseline';
|
||||
|
||||
if (browser.tizen || browser.orsay || browser.web0s ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.640833"').replace(/no/, '')) {
|
||||
maxH264Level = 51;
|
||||
}
|
||||
|
||||
// Support H264 Level 52 (Tizen 5.0) - app only
|
||||
if (browser.tizenVersion >= 5 && window.NativeShell) {
|
||||
maxH264Level = 52;
|
||||
}
|
||||
|
||||
if (browser.tizen || browser.orsay ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) {
|
||||
|
||||
// These tests are passing in safari, but playback is failing
|
||||
if (!browser.safari && !browser.iOS && !browser.web0s && !browser.edge && !browser.mobile) {
|
||||
h264Profiles += '|high 10';
|
||||
}
|
||||
if (maxH264Level >= 51 && browser.chrome && !browser.osx) {
|
||||
h264Profiles += '|high 10';
|
||||
}
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
@@ -789,16 +806,13 @@ define(['browser'], function (browser) {
|
||||
{
|
||||
Condition: 'EqualsAny',
|
||||
Property: 'VideoProfile',
|
||||
Value: h264Profiles,
|
||||
IsRequired: false
|
||||
Value: h264Profiles
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: maxH264Level.toString(),
|
||||
IsRequired: false
|
||||
}
|
||||
]
|
||||
Value: maxH264Level.toString()
|
||||
}]
|
||||
});
|
||||
|
||||
if (!browser.edgeUwp && !browser.tizen && !browser.orsay && !browser.web0s) {
|
||||
@@ -882,6 +896,7 @@ define(['browser'], function (browser) {
|
||||
// External vtt or burn in
|
||||
profile.SubtitleProfiles = [];
|
||||
if (supportsTextTracks()) {
|
||||
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: 'vtt',
|
||||
Method: 'External'
|
||||
@@ -889,6 +904,7 @@ define(['browser'], function (browser) {
|
||||
}
|
||||
|
||||
profile.ResponseProfiles = [];
|
||||
|
||||
profile.ResponseProfiles.push({
|
||||
Type: 'Video',
|
||||
Container: 'm4v',
|
||||
@@ -1,24 +1,24 @@
|
||||
button {
|
||||
-webkit-border-fit: border !important;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
-webkit-border-fit: border !important;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 0;
|
||||
font-size: inherit !important;
|
||||
font-family: inherit !important;
|
||||
text-transform: none;
|
||||
background: none !important;
|
||||
background-color: transparent !important;
|
||||
background: none !important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
color: inherit !important;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
outline: none !important;
|
||||
cursor: pointer;
|
||||
contain: layout style;
|
||||
@@ -26,12 +26,24 @@ button::-moz-focus-inner {
|
||||
font-weight: inherit !important;
|
||||
}
|
||||
|
||||
.card:not(.show-animation) {
|
||||
.card-nofocustransform {
|
||||
contain: layout style paint;
|
||||
}
|
||||
|
||||
.itemsContainer {
|
||||
display: flex;
|
||||
margin-left: -0.6em;
|
||||
margin-right: -0.6em;
|
||||
}
|
||||
|
||||
/* TODO replace this with a proper fix */
|
||||
/* doesnt work on mobile devices */
|
||||
/* negative margin fixes annoying misalignment with cards and title */
|
||||
@media all and (max-width:50em) {
|
||||
.itemsContainer {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-list {
|
||||
@@ -55,27 +67,17 @@ button::-moz-focus-inner {
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
.cardPadder-backdrop,
|
||||
.cardPadder-mixedBackdrop,
|
||||
.cardPadder-smallBackdrop,
|
||||
.cardPadder-overflowBackdrop,
|
||||
.cardPadder-overflowSmallBackdrop {
|
||||
.cardPadder-backdrop, .cardPadder-mixedBackdrop, .cardPadder-smallBackdrop, .cardPadder-overflowBackdrop, .cardPadder-overflowSmallBackdrop {
|
||||
padding-bottom: 56.25%;
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.cardPadder-square,
|
||||
.cardPadder-mixedSquare,
|
||||
.cardPadder-overflowSquare,
|
||||
.overflowSquareCard-textCardPadder {
|
||||
.cardPadder-square, .cardPadder-mixedSquare, .cardPadder-overflowSquare, .overflowSquareCard-textCardPadder {
|
||||
padding-bottom: 100%;
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.cardPadder-portrait,
|
||||
.cardPadder-mixedPortrait,
|
||||
.cardPadder-overflowPortrait,
|
||||
.overflowPortraitCard-textCardPadder {
|
||||
.cardPadder-portrait, .cardPadder-mixedPortrait, .cardPadder-overflowPortrait, .overflowPortraitCard-textCardPadder {
|
||||
padding-bottom: 150%;
|
||||
contain: strict;
|
||||
}
|
||||
@@ -90,29 +92,26 @@ button::-moz-focus-inner {
|
||||
margin: 0.6em;
|
||||
transition: none;
|
||||
border: 0 solid transparent;
|
||||
|
||||
/* These both are needed in case cardBox is a button */
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
outline: none !important;
|
||||
contain: layout;
|
||||
contain: style;
|
||||
contain: layout style;
|
||||
}
|
||||
|
||||
.card.show-animation .cardBox {
|
||||
.cardBox-withfocuscontent-large {
|
||||
margin: .4em;
|
||||
}
|
||||
|
||||
.card-focuscontent-large {
|
||||
border: .5em solid transparent;
|
||||
}
|
||||
|
||||
.cardBox-focustransform {
|
||||
will-change: transform;
|
||||
transition: transform 200ms ease-out;
|
||||
}
|
||||
|
||||
.card.show-focus:not(.show-animation) .cardBox {
|
||||
margin: 0.4em;
|
||||
}
|
||||
|
||||
.card.show-focus:not(.show-animation) .cardBox.visualCardBox,
|
||||
.card.show-focus:not(.show-animation) .cardBox:not(.visualCardBox) .cardScalable {
|
||||
border: 0.5em solid transparent;
|
||||
}
|
||||
|
||||
.card.show-animation:focus > .cardBox {
|
||||
.card:focus > .cardBox-focustransform {
|
||||
transform: scale(1.18, 1.18);
|
||||
}
|
||||
|
||||
@@ -134,7 +133,7 @@ button::-moz-focus-inner {
|
||||
|
||||
.btnCardOptions {
|
||||
position: absolute;
|
||||
bottom: 0.25em;
|
||||
bottom: .25em;
|
||||
right: 0;
|
||||
margin: 0 !important;
|
||||
z-index: 1;
|
||||
@@ -145,8 +144,8 @@ button::-moz-focus-inner {
|
||||
position: absolute;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
top: 0.3em;
|
||||
left: 0.3em;
|
||||
top: .3em;
|
||||
left: .3em;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
width: 1.6em;
|
||||
@@ -167,7 +166,6 @@ button::-moz-focus-inner {
|
||||
position: relative;
|
||||
background-clip: content-box !important;
|
||||
color: inherit;
|
||||
|
||||
/* This is only needed for scalable cards */
|
||||
height: 100%;
|
||||
contain: strict;
|
||||
@@ -189,16 +187,13 @@ button::-moz-focus-inner {
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
/* Needed in case this is a button */
|
||||
display: block;
|
||||
|
||||
/* Needed in case this is a button */
|
||||
margin: 0 !important;
|
||||
|
||||
/* Needed in safari */
|
||||
height: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
outline: none !important;
|
||||
contain: strict;
|
||||
}
|
||||
@@ -227,22 +222,24 @@ button::-moz-focus-inner {
|
||||
box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37);
|
||||
}
|
||||
|
||||
.cardImageContainer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.cardImage {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-size: cover;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
border: none;
|
||||
background-position: center bottom;
|
||||
}
|
||||
|
||||
.cardImage-img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
|
||||
/* This is simply for lazy image purposes, to ensure the image is visible sooner when scrolling */
|
||||
min-height: 70%;
|
||||
min-width: 70%;
|
||||
@@ -260,7 +257,7 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.coveredImage {
|
||||
background-size: cover;
|
||||
background-size: 100% 100%;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
@@ -269,17 +266,17 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.cardFooter {
|
||||
padding: 0.3em 0.3em 0.5em 0.3em;
|
||||
padding: .3em .3em .5em .3em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.visualCardBox {
|
||||
box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37);
|
||||
border-radius: 0.145em;
|
||||
border-radius: .145em;
|
||||
}
|
||||
|
||||
.innerCardFooter {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
background: rgba(0,0,0,.7);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -299,7 +296,7 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.cardText {
|
||||
padding: 0.06em 0.5em;
|
||||
padding: .06em .5em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -311,24 +308,7 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.cardText-first {
|
||||
padding-top: 0.24em;
|
||||
}
|
||||
|
||||
.textActionButton {
|
||||
border: 0 !important;
|
||||
background: transparent;
|
||||
padding: 0 !important;
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
outline: none !important;
|
||||
color: inherit;
|
||||
vertical-align: middle;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.textActionButton:hover {
|
||||
text-decoration: underline;
|
||||
padding-top: .24em;
|
||||
}
|
||||
|
||||
.cardText > .textActionButton {
|
||||
@@ -338,7 +318,7 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.innerCardFooter > .cardText {
|
||||
padding: 0.3em 0.5em;
|
||||
padding: .3em .5em;
|
||||
}
|
||||
|
||||
.cardFooter-withlogo {
|
||||
@@ -370,19 +350,40 @@ button::-moz-focus-inner {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cardImageContainer .cardImageIcon {
|
||||
.textActionButton {
|
||||
border: 0 !important;
|
||||
background: transparent;
|
||||
border: 0 !important;
|
||||
padding: 0 !important;
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
outline: none !important;
|
||||
color: inherit;
|
||||
vertical-align: middle;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
/*display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;*/
|
||||
}
|
||||
|
||||
.textActionButton:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.cardImageIcon {
|
||||
font-size: 5em;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.cardImageIcon-small {
|
||||
font-size: 3em !important;
|
||||
margin-bottom: 0.1em;
|
||||
font-size: 3em;
|
||||
margin-bottom: .1em;
|
||||
}
|
||||
|
||||
.cardIndicators {
|
||||
right: 0.225em;
|
||||
top: 0.225em;
|
||||
right: .225em;
|
||||
top: .225em;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -399,16 +400,16 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.programAttributeIndicator {
|
||||
padding: 0.18em 0.5em;
|
||||
padding: .18em .5em;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.cardOverlayButton {
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
color: rgba(255, 255, 255, .76);
|
||||
margin: 0;
|
||||
z-index: 1;
|
||||
padding: 0.75em;
|
||||
padding: .75em;
|
||||
font-size: 88%;
|
||||
}
|
||||
|
||||
@@ -419,7 +420,7 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.cardOverlayButtonIcon {
|
||||
background-color: rgba(0, 0, 0, 0.7) !important;
|
||||
background-color: rgba(0,0,0,.7) !important;
|
||||
border-radius: 100em;
|
||||
width: 1.5em !important;
|
||||
height: 1.5em !important;
|
||||
@@ -429,12 +430,6 @@ button::-moz-focus-inner {
|
||||
font-size: 1.66956521739130434em !important;
|
||||
}
|
||||
|
||||
.cardOverlayButtonIcon.material-icons {
|
||||
/* material-icons override display, so we need to
|
||||
make a better matching selector to set it to flex */
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.cardOverlayButton-centered {
|
||||
bottom: initial;
|
||||
right: initial;
|
||||
@@ -447,10 +442,10 @@ button::-moz-focus-inner {
|
||||
height: 2.6em;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.5) !important;
|
||||
border: 0.06em solid rgba(255, 255, 255, 0.6);
|
||||
padding: 0.38em !important;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
background-color: rgba(0,0,0,.5) !important;
|
||||
border: .06em solid rgba(255,255,255,.6);
|
||||
padding: .38em !important;
|
||||
color: rgba(255, 255, 255, .76);
|
||||
transition: transform 200ms ease-out;
|
||||
}
|
||||
|
||||
@@ -497,15 +492,13 @@ button::-moz-focus-inner {
|
||||
width: 33.333333333333333333333333333333%;
|
||||
}
|
||||
|
||||
.squareCard,
|
||||
.portraitCard {
|
||||
.squareCard, .portraitCard {
|
||||
width: 33.333333333333333333333333333333%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 43.75em) {
|
||||
.squareCard,
|
||||
.portraitCard {
|
||||
.squareCard, .portraitCard {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
@@ -521,8 +514,7 @@ button::-moz-focus-inner {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.squareCard,
|
||||
.portraitCard {
|
||||
.squareCard, .portraitCard {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
@@ -542,8 +534,7 @@ button::-moz-focus-inner {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.squareCard,
|
||||
.portraitCard {
|
||||
.squareCard, .portraitCard {
|
||||
width: 16.666666666666666666666666666667%;
|
||||
}
|
||||
|
||||
@@ -556,9 +547,9 @@ button::-moz-focus-inner {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 87.5em) {
|
||||
.squareCard,
|
||||
.portraitCard {
|
||||
.squareCard, .portraitCard {
|
||||
width: 14.285714285714285714285714285714%;
|
||||
}
|
||||
|
||||
@@ -576,15 +567,13 @@ button::-moz-focus-inner {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.squareCard,
|
||||
.portraitCard {
|
||||
.squareCard, .portraitCard {
|
||||
width: 12.5%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 120em) {
|
||||
.squareCard,
|
||||
.portraitCard {
|
||||
.squareCard, .portraitCard {
|
||||
width: 11.111111111111111111111111111111%;
|
||||
}
|
||||
}
|
||||
@@ -594,8 +583,7 @@ button::-moz-focus-inner {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.squareCard,
|
||||
.portraitCard {
|
||||
.squareCard, .portraitCard {
|
||||
width: 10%;
|
||||
}
|
||||
}
|
||||
@@ -626,8 +614,7 @@ button::-moz-focus-inner {
|
||||
width: 72vw;
|
||||
}
|
||||
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 40vw;
|
||||
}
|
||||
|
||||
@@ -652,35 +639,30 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
@media (min-width: 43.75em) {
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
width: 23.1vw;
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 23.3vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 48.125em) {
|
||||
.overflowBackdropCard,
|
||||
.overflowSmallBackdropCard {
|
||||
.overflowBackdropCard, .overflowSmallBackdropCard {
|
||||
width: 30vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (orientation: landscape) {
|
||||
.overflowBackdropCard,
|
||||
.overflowSmallBackdropCard {
|
||||
.overflowBackdropCard, .overflowSmallBackdropCard {
|
||||
width: 30vw;
|
||||
}
|
||||
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
width: 23.1vw;
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 23.3vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (orientation: landscape) and (min-width: 48.125em) {
|
||||
.overflowBackdropCard,
|
||||
.overflowSmallBackdropCard {
|
||||
width: 23.1vw;
|
||||
.overflowBackdropCard, .overflowSmallBackdropCard {
|
||||
width: 23.3vw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,60 +673,55 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
@media (min-width: 50em) {
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
width: 18.5vw;
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 18.4vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 75em) {
|
||||
.overflowBackdropCard,
|
||||
.overflowSmallBackdropCard {
|
||||
width: 23.1vw;
|
||||
.overflowBackdropCard, .overflowSmallBackdropCard {
|
||||
width: 23.3vw;
|
||||
}
|
||||
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 15.5vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 87.5em) {
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 13.3vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 100em) {
|
||||
.overflowBackdropCard,
|
||||
.overflowSmallBackdropCard {
|
||||
|
||||
.overflowBackdropCard, .overflowSmallBackdropCard {
|
||||
width: 18.7vw;
|
||||
}
|
||||
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 11.6vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 120em) {
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
width: 10.41vw;
|
||||
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 10.3vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 131.25em) {
|
||||
.overflowSquareCard,
|
||||
.overflowPortraitCard {
|
||||
|
||||
.overflowSquareCard, .overflowPortraitCard {
|
||||
width: 9.3vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 156.25em) {
|
||||
.overflowBackdropCard,
|
||||
.overflowSmallBackdropCard {
|
||||
|
||||
.overflowBackdropCard, .overflowSmallBackdropCard {
|
||||
width: 15.6vw;
|
||||
}
|
||||
}
|
||||
@@ -761,8 +738,7 @@ button::-moz-focus-inner {
|
||||
padding-bottom: 87.75%;
|
||||
}
|
||||
|
||||
.itemsContainer-tv > .overflowSquareCard,
|
||||
.itemsContainer-tv > .overflowPortraitCard {
|
||||
.itemsContainer-tv > .overflowSquareCard, .itemsContainer-tv > .overflowPortraitCard {
|
||||
width: 15.6vw;
|
||||
}
|
||||
|
||||
@@ -771,9 +747,9 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.cardOverlayContainer {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(0,0,0,0.5);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
transition: opacity .2s;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@@ -790,7 +766,7 @@ button::-moz-focus-inner {
|
||||
opacity: 0;
|
||||
transition: 0.2s;
|
||||
background: transparent;
|
||||
padding: 0.25em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.cardOverlayButtonIcon-hover {
|
||||
@@ -802,7 +778,7 @@ button::-moz-focus-inner {
|
||||
}
|
||||
|
||||
.cardOverlayFab-primary {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
font-size: 130%;
|
||||
padding: 0;
|
||||
width: 3em;
|
||||
@@ -817,4 +793,4 @@ button::-moz-focus-inner {
|
||||
.cardOverlayFab-primary:hover {
|
||||
transform: scale(1.4, 1.4);
|
||||
transition: 0.2s;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
function (datetime, imageLoader, connectionManager, itemHelper, focusManager, indicators, globalize, layoutManager, appHost, dom, browser, playbackManager, itemShortcuts, imageHelper) {
|
||||
'use strict';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
var devicePixelRatio = window.devicePixelRatio || 1;
|
||||
var enableFocusTransfrom = !browser.slow && !browser.edge;
|
||||
|
||||
function getCardsHtml(items, options) {
|
||||
if (arguments.length === 1) {
|
||||
@@ -139,6 +140,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
}
|
||||
return 100 / 72;
|
||||
}
|
||||
break;
|
||||
case 'overflowPortrait':
|
||||
|
||||
if (layoutManager.tv) {
|
||||
@@ -164,6 +166,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
}
|
||||
return 100 / 42;
|
||||
}
|
||||
break;
|
||||
case 'overflowSquare':
|
||||
if (layoutManager.tv) {
|
||||
return 100 / 15.5;
|
||||
@@ -188,6 +191,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
}
|
||||
return 100 / 42;
|
||||
}
|
||||
break;
|
||||
case 'overflowBackdrop':
|
||||
if (layoutManager.tv) {
|
||||
return 100 / 23.3;
|
||||
@@ -212,6 +216,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
}
|
||||
return 100 / 72;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
@@ -232,9 +237,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
|
||||
function getImageWidth(shape, screenWidth, isOrientationLandscape) {
|
||||
var imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape);
|
||||
var shapeWidth = Math.round(screenWidth / imagesPerRow) * 2;
|
||||
var shapeWidth = screenWidth / imagesPerRow;
|
||||
|
||||
return shapeWidth;
|
||||
return Math.round(shapeWidth);
|
||||
}
|
||||
|
||||
function setCardData(items, options) {
|
||||
@@ -316,8 +321,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
var apiClient;
|
||||
var lastServerId;
|
||||
|
||||
var i;
|
||||
var length;
|
||||
var i, length;
|
||||
|
||||
for (i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
@@ -335,14 +339,19 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
if (options.indexBy === 'PremiereDate') {
|
||||
if (item.PremiereDate) {
|
||||
try {
|
||||
|
||||
newIndexValue = datetime.toLocaleDateString(datetime.parseISO8601Date(item.PremiereDate), { weekday: 'long', month: 'long', day: 'numeric' });
|
||||
|
||||
} catch (err) {
|
||||
console.error('error parsing timestamp for premiere date');
|
||||
}
|
||||
}
|
||||
} else if (options.indexBy === 'ProductionYear') {
|
||||
}
|
||||
|
||||
else if (options.indexBy === 'ProductionYear') {
|
||||
newIndexValue = item.ProductionYear;
|
||||
} else if (options.indexBy === 'CommunityRating') {
|
||||
}
|
||||
|
||||
else if (options.indexBy === 'CommunityRating') {
|
||||
newIndexValue = item.CommunityRating ? (Math.floor(item.CommunityRating) + (item.CommunityRating % 1 >= 0.5 ? 0.5 : 0)) + '+' : null;
|
||||
}
|
||||
|
||||
@@ -575,23 +584,26 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
|
||||
}
|
||||
}
|
||||
} else if (item.ParentPrimaryImageTag) {
|
||||
}
|
||||
else if (item.ParentPrimaryImageTag) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, {
|
||||
type: "Primary",
|
||||
maxWidth: width,
|
||||
tag: item.ParentPrimaryImageTag
|
||||
});
|
||||
} else if (item.SeriesPrimaryImageTag) {
|
||||
}
|
||||
else if (item.SeriesPrimaryImageTag) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, {
|
||||
type: "Primary",
|
||||
maxWidth: width,
|
||||
tag: item.SeriesPrimaryImageTag
|
||||
});
|
||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
}
|
||||
else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
|
||||
width = primaryImageAspectRatio ? Math.round(height * primaryImageAspectRatio) : null;
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.AlbumId, {
|
||||
type: "Primary",
|
||||
@@ -606,7 +618,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
|
||||
}
|
||||
}
|
||||
} else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) {
|
||||
}
|
||||
else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Thumb",
|
||||
@@ -614,7 +627,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
|
||||
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
}
|
||||
else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: "Backdrop",
|
||||
@@ -690,8 +704,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
var html = '';
|
||||
|
||||
var valid = 0;
|
||||
var i;
|
||||
var length;
|
||||
var i, length;
|
||||
|
||||
for (i = 0, length = lines.length; i < length; i++) {
|
||||
|
||||
@@ -755,8 +768,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
date = datetime.parseISO8601Date(item.EndDate);
|
||||
airTimeText += ' - ' + datetime.getDisplayTime(date);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("error parsing date: " + item.StartDate);
|
||||
}
|
||||
catch (e) {
|
||||
console.log("Error parsing date: " + item.StartDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,7 +790,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
if (isOuterFooter && options.cardLayout && layoutManager.mobile) {
|
||||
|
||||
if (options.cardFooterAside !== 'none') {
|
||||
html += '<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu"><i class="material-icons more_horiz"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu"><i class="md-icon"></i></button>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,7 +817,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
} else {
|
||||
lines.push(item.SeriesName);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
|
||||
if (isUsingLiveTvNaming(item)) {
|
||||
|
||||
@@ -888,10 +903,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
|
||||
if (item.PremiereDate) {
|
||||
try {
|
||||
lines.push(datetime.toLocaleDateString(
|
||||
datetime.parseISO8601Date(item.PremiereDate),
|
||||
{ weekday: 'long', month: 'long', day: 'numeric' }
|
||||
));
|
||||
|
||||
lines.push(getPremiereDateText(item));
|
||||
|
||||
} catch (err) {
|
||||
lines.push('');
|
||||
|
||||
@@ -911,8 +925,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
} else {
|
||||
|
||||
if (item.EndDate && item.ProductionYear) {
|
||||
var endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
lines.push(item.ProductionYear + ((endYear === item.ProductionYear) ? '' : (' - ' + endYear)));
|
||||
lines.push(item.ProductionYear + ' - ' + datetime.parseISO8601Date(item.EndDate).getFullYear());
|
||||
} else {
|
||||
lines.push(item.ProductionYear || '');
|
||||
}
|
||||
@@ -986,7 +999,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
if (options.showSeriesTimerChannel) {
|
||||
if (item.RecordAnyChannel) {
|
||||
lines.push(globalize.translate('AllChannels'));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
lines.push(item.ChannelName || globalize.translate('OneChannel'));
|
||||
}
|
||||
}
|
||||
@@ -994,7 +1008,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
if (options.showPersonRoleOrType) {
|
||||
if (item.Role) {
|
||||
lines.push('as ' + item.Role);
|
||||
} else if (item.Type) {
|
||||
}
|
||||
else if (item.Type) {
|
||||
lines.push(globalize.translate('' + item.Type));
|
||||
} else {
|
||||
lines.push('');
|
||||
@@ -1037,7 +1052,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
return text;
|
||||
}
|
||||
|
||||
var html = '<button ' + itemShortcuts.getShortcutAttributesHtml(item, serverId) + ' type="button" class="itemAction textActionButton" title="' + text + '" data-action="link">';
|
||||
var html = '<button ' + itemShortcuts.getShortcutAttributesHtml(item, serverId) + ' type="button" class="itemAction textActionButton" data-action="link">';
|
||||
html += text;
|
||||
html += '</button>';
|
||||
|
||||
@@ -1068,7 +1083,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
|
||||
counts.push(childText);
|
||||
|
||||
} else if (item.Type === 'Genre' || item.Type === 'Studio') {
|
||||
}
|
||||
else if (item.Type === 'Genre' || item.Type === 'Studio') {
|
||||
|
||||
if (item.MovieCount) {
|
||||
|
||||
@@ -1147,7 +1163,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
|
||||
if (item.IsPremiere) {
|
||||
html += '<div class="premiereTvProgram programAttributeIndicator">' + globalize.translate('Premiere') + '</div>';
|
||||
} else if (item.IsSeries && !item.IsRepeat) {
|
||||
}
|
||||
else if (item.IsSeries && !item.IsRepeat) {
|
||||
html += '<div class="newTvProgram programAttributeIndicator">' + globalize.translate('AttributeNew') + '</div>';
|
||||
}
|
||||
//else if (item.IsRepeat) {
|
||||
@@ -1182,7 +1199,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
if (action === 'play' && item.IsFolder) {
|
||||
// If this hard-coding is ever removed make sure to test nested photo albums
|
||||
action = 'link';
|
||||
} else if (item.MediaType === 'Photo') {
|
||||
}
|
||||
else if (item.MediaType === 'Photo') {
|
||||
action = 'play';
|
||||
}
|
||||
|
||||
@@ -1208,8 +1226,6 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
shape = shape || 'mixedSquare';
|
||||
}
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var className = 'card';
|
||||
|
||||
if (shape) {
|
||||
@@ -1228,12 +1244,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
className += ' card-hoverable';
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
className += ' show-focus';
|
||||
|
||||
if (enableFocusTransform) {
|
||||
className += ' show-animation';
|
||||
}
|
||||
if (!enableFocusTransfrom || !layoutManager.tv) {
|
||||
className += ' card-nofocustransform';
|
||||
}
|
||||
|
||||
var imgInfo = getCardImageUrl(item, apiClient, options, shape);
|
||||
@@ -1261,6 +1273,23 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
|
||||
var cardBoxClass = options.cardLayout ? 'cardBox visualCardBox' : 'cardBox';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
||||
if (enableFocusTransfrom) {
|
||||
cardBoxClass += ' cardBox-focustransform cardBox-withfocuscontent';
|
||||
} else {
|
||||
cardBoxClass += ' cardBox-withfocuscontent-large';
|
||||
}
|
||||
|
||||
if (options.cardLayout) {
|
||||
cardBoxClass += ' card-focuscontent';
|
||||
|
||||
if (!enableFocusTransfrom) {
|
||||
cardBoxClass += ' card-focuscontent-large';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var footerCssClass;
|
||||
var progressHtml = indicators.getProgressBarHtml(item);
|
||||
|
||||
@@ -1277,7 +1306,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
height: logoHeight,
|
||||
tag: item.ChannelPrimaryImageTag
|
||||
});
|
||||
} else if (options.showLogo && item.ParentLogoImageTag) {
|
||||
}
|
||||
else if (options.showLogo && item.ParentLogoImageTag) {
|
||||
logoUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, {
|
||||
type: "Logo",
|
||||
height: logoHeight,
|
||||
@@ -1292,7 +1322,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter';
|
||||
innerCardFooter += getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, logoUrl, false);
|
||||
footerOverlayed = true;
|
||||
} else if (progressHtml) {
|
||||
}
|
||||
else if (progressHtml) {
|
||||
innerCardFooter += '<div class="innerCardFooter fullInnerCardFooter innerCardFooterClear">';
|
||||
innerCardFooter += progressHtml;
|
||||
innerCardFooter += '</div>';
|
||||
@@ -1335,15 +1366,15 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
var btnCssClass = 'cardOverlayButton cardOverlayButton-br itemAction';
|
||||
|
||||
if (options.centerPlayButton) {
|
||||
overlayButtons += '<button is="paper-icon-button-light" class="' + btnCssClass + ' cardOverlayButton-centered" data-action="play"><i class="material-icons cardOverlayButtonIcon play_arrow"></i></button>';
|
||||
overlayButtons += '<button is="paper-icon-button-light" class="' + btnCssClass + ' cardOverlayButton-centered" data-action="play"><i class="md-icon cardOverlayButtonIcon"></i></button>';
|
||||
}
|
||||
|
||||
if (overlayPlayButton && !item.IsPlaceHolder && (item.LocationType !== 'Virtual' || !item.MediaType || item.Type === 'Program') && item.Type !== 'Person') {
|
||||
overlayButtons += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="play"><i class="material-icons cardOverlayButtonIcon play_arrow"></i></button>';
|
||||
overlayButtons += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="play"><i class="md-icon cardOverlayButtonIcon"></i></button>';
|
||||
}
|
||||
|
||||
if (options.overlayMoreButton) {
|
||||
overlayButtons += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><i class="material-icons cardOverlayButtonIcon more_horiz"></i></button>';
|
||||
overlayButtons += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><i class="md-icon cardOverlayButtonIcon"></i></button>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1377,6 +1408,15 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
|
||||
var cardScalableClass = 'cardScalable';
|
||||
|
||||
if (layoutManager.tv && !options.cardLayout) {
|
||||
|
||||
cardScalableClass += ' card-focuscontent';
|
||||
|
||||
if (!enableFocusTransfrom) {
|
||||
cardScalableClass += ' card-focuscontent-large';
|
||||
}
|
||||
}
|
||||
|
||||
cardImageContainerOpen = '<div class="' + cardBoxClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainerOpen;
|
||||
cardBoxClose = '</div>';
|
||||
cardScalableClose = '</div>';
|
||||
@@ -1397,12 +1437,13 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, {
|
||||
minCount: 1
|
||||
});
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
|
||||
}
|
||||
|
||||
if (item.Type === 'CollectionFolder' || item.CollectionType) {
|
||||
var refreshClass = item.RefreshProgress ? '' : ' class="hide"';
|
||||
var refreshClass = item.RefreshProgress || (item.RefreshStatus && virtualFolder.item !== 'Idle') ? '' : ' class="hide"';
|
||||
indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>';
|
||||
requireRefreshIndicator();
|
||||
}
|
||||
@@ -1416,7 +1457,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
//}
|
||||
|
||||
if (!imgUrl) {
|
||||
cardImageContainerOpen += getDefaultText(item, options);
|
||||
cardImageContainerOpen += getCardDefaultText(item, options);
|
||||
}
|
||||
|
||||
var tagName = (layoutManager.tv) && !overlayButtons ? 'button' : 'div';
|
||||
@@ -1476,16 +1517,16 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
var btnCssClass = 'cardOverlayButton cardOverlayButton-hover itemAction paper-icon-button-light';
|
||||
|
||||
if (playbackManager.canPlay(item)) {
|
||||
html += '<button is="paper-icon-button-light" class="' + btnCssClass + ' cardOverlayFab-primary" data-action="resume"><i class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover play_arrow"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="' + btnCssClass + ' cardOverlayFab-primary" data-action="resume"><i class="md-icon cardOverlayButtonIcon cardOverlayButtonIcon-hover"></i></button>';
|
||||
}
|
||||
|
||||
html += '<div class="cardOverlayButton-br flex">';
|
||||
html += '<div class="cardOverlayButton-br">';
|
||||
|
||||
var userData = item.UserData || {};
|
||||
|
||||
if (itemHelper.canMarkPlayed(item)) {
|
||||
require(['emby-playstatebutton']);
|
||||
html += '<button is="emby-playstatebutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><i class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover">check</i></button>';
|
||||
html += '<button is="emby-playstatebutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><i class="md-icon cardOverlayButtonIcon cardOverlayButtonIcon-hover"></i></button>';
|
||||
}
|
||||
|
||||
if (itemHelper.canRate(item)) {
|
||||
@@ -1493,10 +1534,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
var likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
require(['emby-ratingbutton']);
|
||||
html += '<button is="emby-ratingbutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><i class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover">favorite</i></button>';
|
||||
html += '<button is="emby-ratingbutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><i class="md-icon cardOverlayButtonIcon cardOverlayButtonIcon-hover"></i></button>';
|
||||
}
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><i class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover more_horiz"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><i class="md-icon cardOverlayButtonIcon cardOverlayButtonIcon-hover"></i></button>';
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
@@ -1504,29 +1545,18 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
return html;
|
||||
}
|
||||
|
||||
function getDefaultText(item, options) {
|
||||
function getCardDefaultText(item, options) {
|
||||
if (item.CollectionType) {
|
||||
return '<i class="cardImageIcon material-icons ' + imageHelper.getLibraryIcon(item.CollectionType) + '"></i>'
|
||||
return '<i class="cardImageIcon md-icon">' + imageHelper.getLibraryIcon(item.CollectionType) + '</i>'
|
||||
}
|
||||
|
||||
switch (item.Type) {
|
||||
case 'MusicAlbum':
|
||||
return '<i class="cardImageIcon material-icons">album</i>';
|
||||
case 'MusicArtist':
|
||||
case 'Person':
|
||||
return '<i class="cardImageIcon material-icons">person</i>';
|
||||
case 'Movie':
|
||||
return '<i class="cardImageIcon material-icons">movie</i>';
|
||||
case 'Series':
|
||||
return '<i class="cardImageIcon material-icons">tv</i>';
|
||||
case 'Book':
|
||||
return '<i class="cardImageIcon material-icons">book</i>';
|
||||
case 'Folder':
|
||||
return '<i class="cardImageIcon material-icons">folder</i>';
|
||||
if (item.Type === 'MusicAlbum') {
|
||||
return '<i class="cardImageIcon md-icon"></i>';
|
||||
}
|
||||
|
||||
if (options && options.defaultCardImageIcon) {
|
||||
return '<i class="cardImageIcon material-icons">' + options.defaultCardImageIcon + '</i>';
|
||||
if (item.Type === 'MusicArtist' || item.Type === 'Person') {
|
||||
return '<i class="cardImageIcon md-icon"></i>';
|
||||
}
|
||||
if (options.defaultCardImageIcon) {
|
||||
return '<i class="cardImageIcon md-icon">' + options.defaultCardImageIcon + '</i>';
|
||||
}
|
||||
|
||||
var defaultName = isUsingLiveTvNaming(item) ? item.Name : itemHelper.getDisplayName(item);
|
||||
@@ -1615,7 +1645,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
indicatorsElem = ensureIndicators(card, indicatorsElem);
|
||||
indicatorsElem.appendChild(playedIndicator);
|
||||
}
|
||||
playedIndicator.innerHTML = '<i class="material-icons indicatorIcon">check</i>';
|
||||
playedIndicator.innerHTML = '<i class="md-icon indicatorIcon"></i>';
|
||||
} else {
|
||||
|
||||
playedIndicator = card.querySelector('.playedIndicator');
|
||||
@@ -1669,7 +1699,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
}
|
||||
|
||||
itemProgressBar.innerHTML = progressHtml;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
|
||||
itemProgressBar = card.querySelector('.itemProgressBar');
|
||||
if (itemProgressBar) {
|
||||
@@ -1696,7 +1727,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
var icon = cell.querySelector('.timerIndicator');
|
||||
if (!icon) {
|
||||
var indicatorsElem = ensureIndicators(cell);
|
||||
indicatorsElem.insertAdjacentHTML('beforeend', '<i class="material-icons timerIndicator indicatorIcon fiber_manual_record"></i>');
|
||||
indicatorsElem.insertAdjacentHTML('beforeend', '<i class="md-icon timerIndicator indicatorIcon"></i>');
|
||||
}
|
||||
cell.setAttribute('data-timerid', newTimerId);
|
||||
}
|
||||
@@ -1732,8 +1763,6 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana
|
||||
|
||||
return {
|
||||
getCardsHtml: getCardsHtml,
|
||||
getDefaultBackgroundClass: getDefaultBackgroundClass,
|
||||
getDefaultText: getDefaultText,
|
||||
buildCards: buildCards,
|
||||
onUserDataChanged: onUserDataChanged,
|
||||
onTimerCreated: onTimerCreated,
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) {
|
||||
'use strict';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
function buildChapterCardsHtml(item, chapters, options) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var className = 'card itemAction chapterCard';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
className += ' show-focus';
|
||||
|
||||
if (enableFocusTransform) {
|
||||
className += ' show-animation';
|
||||
}
|
||||
if (layoutManager.tv && (browser.animate || browser.edge)) {
|
||||
className += ' card-focusscale';
|
||||
}
|
||||
|
||||
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [];
|
||||
@@ -68,7 +60,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
|
||||
|
||||
return apiClient.getScaledImageUrl(item.Id, {
|
||||
|
||||
maxWidth: maxWidth * 2,
|
||||
maxWidth: maxWidth,
|
||||
tag: chapter.ImageTag,
|
||||
type: "Chapter",
|
||||
index: index
|
||||
@@ -90,7 +82,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
|
||||
var cardImageContainer = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
|
||||
|
||||
if (!imgUrl) {
|
||||
cardImageContainer += '<i class="material-icons cardImageIcon local_movies"></i>';
|
||||
cardImageContainer += '<i class="md-icon cardImageIcon">local_movies</i>';
|
||||
}
|
||||
|
||||
var nameHtml = '';
|
||||
@@ -100,6 +92,19 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
|
||||
var cardBoxCssClass = 'cardBox';
|
||||
var cardScalableClass = 'cardScalable';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
var enableFocusTransfrom = !browser.slow && !browser.edge;
|
||||
|
||||
cardScalableClass += ' card-focuscontent';
|
||||
|
||||
if (enableFocusTransfrom) {
|
||||
cardBoxCssClass += ' cardBox-focustransform cardBox-withfocuscontent';
|
||||
} else {
|
||||
cardBoxCssClass += ' cardBox-withfocuscontent-large';
|
||||
cardScalableClass += ' card-focuscontent-large';
|
||||
}
|
||||
}
|
||||
|
||||
var html = '<button type="button" class="' + className + '"' + dataAttributes + '><div class="' + cardBoxCssClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainer + '</div><div class="innerCardFooter">' + nameHtml + '</div></div></div></button>';
|
||||
|
||||
return html;
|
||||
@@ -132,4 +137,4 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
|
||||
buildChapterCards: buildChapterCards
|
||||
};
|
||||
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,7 @@ define(['cardBuilder'], function (cardBuilder) {
|
||||
cardFooterAside: 'none',
|
||||
showPersonRoleOrType: true,
|
||||
cardCssClass: 'personCard',
|
||||
defaultCardImageIcon: 'person'
|
||||
defaultCardImageIcon: ''
|
||||
});
|
||||
cardBuilder.buildCards(items, options);
|
||||
}
|
||||
@@ -19,4 +19,4 @@ define(['cardBuilder'], function (cardBuilder) {
|
||||
buildPeopleCards: buildPeopleCards
|
||||
};
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1,16 +1,10 @@
|
||||
define(["dialogHelper", "loading", "connectionManager", "globalize", "actionsheet", "emby-input", "paper-icon-button-light", "emby-button", "listViewStyle", "material-icons", "formDialogStyle"], function (dialogHelper, loading, connectionManager, globalize, actionsheet) {
|
||||
define(["dialogHelper", "loading", "connectionManager", "globalize", "actionsheet", "emby-input", "paper-icon-button-light", "emby-button", "listViewStyle", "material-icons", "formDialogStyle"], function(dialogHelper, loading, connectionManager, globalize, actionsheet) {
|
||||
"use strict";
|
||||
|
||||
return function (options) {
|
||||
return function(options) {
|
||||
function parentWithClass(elem, className) {
|
||||
while (!elem.classList || !elem.classList.contains(className)) {
|
||||
elem = elem.parentNode;
|
||||
if (!elem) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return elem;
|
||||
for (; !elem.classList || !elem.classList.contains(className);)
|
||||
if (!(elem = elem.parentNode)) return null;
|
||||
return elem
|
||||
}
|
||||
|
||||
function mapChannel(button, channelId, providerChannelId) {
|
||||
@@ -25,35 +19,33 @@ define(["dialogHelper", "loading", "connectionManager", "globalize", "actionshee
|
||||
providerChannelId: providerChannelId
|
||||
},
|
||||
dataType: "json"
|
||||
}).then(function (mapping) {
|
||||
}).then(function(mapping) {
|
||||
var listItem = parentWithClass(button, "listItem");
|
||||
button.setAttribute("data-providerid", mapping.ProviderChannelId);
|
||||
listItem.querySelector(".secondary").innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName);
|
||||
loading.hide();
|
||||
});
|
||||
button.setAttribute("data-providerid", mapping.ProviderChannelId), listItem.querySelector(".secondary").innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName), loading.hide()
|
||||
})
|
||||
}
|
||||
|
||||
function onChannelsElementClick(e) {
|
||||
var btnMap = parentWithClass(e.target, "btnMap");
|
||||
|
||||
if (btnMap) {
|
||||
var channelId = btnMap.getAttribute("data-id");
|
||||
var providerChannelId = btnMap.getAttribute("data-providerid");
|
||||
var menuItems = currentMappingOptions.ProviderChannels.map(function (m) {
|
||||
var menuItems = currentMappingOptions.ProviderChannels.map(function(m) {
|
||||
return {
|
||||
name: m.Name,
|
||||
id: m.Id,
|
||||
selected: m.Id.toLowerCase() === providerChannelId.toLowerCase()
|
||||
};
|
||||
}
|
||||
}).sort(function (a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
actionsheet.show({
|
||||
positionTo: btnMap,
|
||||
items: menuItems
|
||||
}).then(function (newChannelId) {
|
||||
mapChannel(btnMap, channelId, newChannelId);
|
||||
});
|
||||
}).then(function(newChannelId) {
|
||||
mapChannel(btnMap, channelId, newChannelId)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,87 +53,47 @@ define(["dialogHelper", "loading", "connectionManager", "globalize", "actionshee
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
return apiClient.getJSON(apiClient.getUrl("LiveTv/ChannelMappingOptions", {
|
||||
providerId: providerId
|
||||
}));
|
||||
}))
|
||||
}
|
||||
|
||||
function getMappingSecondaryName(mapping, providerName) {
|
||||
return (mapping.ProviderChannelName || "") + " - " + providerName;
|
||||
return (mapping.ProviderChannelName || "") + " - " + providerName
|
||||
}
|
||||
|
||||
function getTunerChannelHtml(channel, providerName) {
|
||||
var html = "";
|
||||
html += '<div class="listItem">';
|
||||
html += '<i class="material-icons listItemIcon">dvr</i>';
|
||||
html += '<div class="listItemBody two-line">';
|
||||
html += '<h3 class="listItemBodyText">';
|
||||
html += channel.Name;
|
||||
html += "</h3>";
|
||||
html += '<div class="secondary listItemBodyText">';
|
||||
|
||||
if (channel.ProviderChannelName) {
|
||||
html += getMappingSecondaryName(channel, providerName);
|
||||
}
|
||||
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
html += '<button class="btnMap autoSize" is="paper-icon-button-light" type="button" data-id="' + channel.Id + '" data-providerid="' + channel.ProviderChannelId + '"><i class="material-icons mode_edit"></i></button>';
|
||||
return html += "</div>";
|
||||
return html += '<div class="listItem">', html += '<i class="md-icon listItemIcon">dvr</i>', html += '<div class="listItemBody two-line">', html += '<h3 class="listItemBodyText">', html += channel.Name, html += "</h3>", html += '<div class="secondary listItemBodyText">', channel.ProviderChannelName && (html += getMappingSecondaryName(channel, providerName)), html += "</div>", html += "</div>", html += '<button class="btnMap autoSize" is="paper-icon-button-light" type="button" data-id="' + channel.Id + '" data-providerid="' + channel.ProviderChannelId + '"><i class="md-icon">mode_edit</i></button>', html += "</div>"
|
||||
}
|
||||
|
||||
function getEditorHtml() {
|
||||
var html = "";
|
||||
html += '<div class="formDialogContent">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
html += '<form style="margin:auto;">';
|
||||
html += "<h1>" + globalize.translate("HeaderChannels") + "</h1>";
|
||||
html += '<div class="channels paperList">';
|
||||
html += "</div>";
|
||||
html += "</form>";
|
||||
html += "</div>";
|
||||
return html += "</div>";
|
||||
return html += '<div class="formDialogContent">', html += '<div class="dialogContentInner dialog-content-centered">', html += '<form style="margin:auto;">', html += "<h1>" + globalize.translate("HeaderChannels") + "</h1>", html += '<div class="channels paperList">', html += "</div>", html += "</form>", html += "</div>", html += "</div>"
|
||||
}
|
||||
|
||||
function initEditor(dlg, options) {
|
||||
getChannelMappingOptions(options.serverId, options.providerId).then(function (result) {
|
||||
getChannelMappingOptions(options.serverId, options.providerId).then(function(result) {
|
||||
currentMappingOptions = result;
|
||||
var channelsElement = dlg.querySelector(".channels");
|
||||
channelsElement.innerHTML = result.TunerChannels.map(function (channel) {
|
||||
return getTunerChannelHtml(channel, result.ProviderName);
|
||||
}).join("");
|
||||
channelsElement.addEventListener("click", onChannelsElementClick);
|
||||
});
|
||||
channelsElement.innerHTML = result.TunerChannels.map(function(channel) {
|
||||
return getTunerChannelHtml(channel, result.ProviderName)
|
||||
}).join(""), channelsElement.addEventListener("click", onChannelsElementClick)
|
||||
})
|
||||
}
|
||||
|
||||
var currentMappingOptions;
|
||||
var self = this;
|
||||
|
||||
self.show = function () {
|
||||
var currentMappingOptions, self = this;
|
||||
self.show = function() {
|
||||
var dialogOptions = {
|
||||
removeOnClose: true
|
||||
removeOnClose: !0
|
||||
};
|
||||
dialogOptions.size = "small";
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add("formDialog");
|
||||
dlg.classList.add("ui-body-a");
|
||||
dlg.classList.add("background-theme-a");
|
||||
var html = "";
|
||||
var title = globalize.translate("MapChannels");
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="material-icons arrow_back"></i></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
html += title;
|
||||
html += "</h3>";
|
||||
html += "</div>";
|
||||
html += getEditorHtml();
|
||||
dlg.innerHTML = html;
|
||||
initEditor(dlg, options);
|
||||
dlg.querySelector(".btnCancel").addEventListener("click", function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
return new Promise(function (resolve, reject) {
|
||||
dlg.addEventListener("close", resolve);
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
};
|
||||
};
|
||||
dlg.classList.add("formDialog"), dlg.classList.add("ui-body-a"), dlg.classList.add("background-theme-a");
|
||||
var html = "",
|
||||
title = globalize.translate("MapChannels");
|
||||
return 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">', html += title, html += "</h3>", html += "</div>", html += getEditorHtml(), dlg.innerHTML = html, initEditor(dlg, options), dlg.querySelector(".btnCancel").addEventListener("click", function() {
|
||||
dialogHelper.close(dlg)
|
||||
}), new Promise(function(resolve, reject) {
|
||||
dlg.addEventListener("close", resolve), dialogHelper.open(dlg)
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ define(['events'], function (events) {
|
||||
//
|
||||
// https://github.com/ravisorg/LinkParser
|
||||
//
|
||||
// Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and
|
||||
// Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and
|
||||
// IPv6, unrecognised TLDs, and more.
|
||||
//
|
||||
// This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
@@ -14,26 +14,26 @@ define(['events'], function (events) {
|
||||
|
||||
// Original URL regex from the Android android.text.util.Linkify function, found here:
|
||||
// http://stackoverflow.com/a/19696443
|
||||
//
|
||||
// However there were problems with it, most probably related to the fact it was
|
||||
//
|
||||
// However there were problems with it, most probably related to the fact it was
|
||||
// written in 2007, and it's been highly modified.
|
||||
//
|
||||
// 1) I didn't like the fact that it was tied to specific TLDs, since new ones
|
||||
//
|
||||
// 1) I didn't like the fact that it was tied to specific TLDs, since new ones
|
||||
// are being added all the time it wouldn't be reasonable to expect developer to
|
||||
// be continually updating their regular expressions.
|
||||
//
|
||||
// 2) It didn't allow unicode characters in the domains which are now allowed in
|
||||
//
|
||||
// 2) It didn't allow unicode characters in the domains which are now allowed in
|
||||
// many languages, (including some IDN TLDs). Again these are constantly being
|
||||
// added to and it doesn't seem reasonable to hard-code them. Note this ended up
|
||||
// not being possible in standard JS due to the way it handles multibyte strings.
|
||||
// It is possible using XRegExp, however a big performance hit results. Disabled
|
||||
// for now.
|
||||
//
|
||||
//
|
||||
// 3) It didn't allow for IPv6 hostnames
|
||||
// IPv6 regex from http://stackoverflow.com/a/17871737
|
||||
//
|
||||
// 4) It was very poorly commented
|
||||
//
|
||||
//
|
||||
// 5) It wasn't as smart as it could have been about what should be part of a
|
||||
// URL and what should be part of human language.
|
||||
|
||||
@@ -102,8 +102,8 @@ define(['events'], function (events) {
|
||||
+ "|(?:\\%[a-f0-9]{2})"
|
||||
// some characters are much more likely to be used AFTER a url and
|
||||
// were not intended to be included in the url itself. Mostly end
|
||||
// of sentence type things. It's also likely that the URL would
|
||||
// still work if any of these characters were missing from the end
|
||||
// of sentence type things. It's also likely that the URL would
|
||||
// still work if any of these characters were missing from the end
|
||||
// because we parsed it incorrectly. For these characters to be accepted
|
||||
// they must be followed by another character that we're reasonably
|
||||
// sure is part of the url
|
||||
@@ -131,9 +131,8 @@ define(['events'], function (events) {
|
||||
var links = [];
|
||||
var match;
|
||||
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (match = linkRegExp.exec(text)) {
|
||||
console.debug(match);
|
||||
// console.log(matches);
|
||||
var txt = match[0];
|
||||
var pos = match.index;
|
||||
var len = txt.length;
|
||||
@@ -190,7 +189,7 @@ define(['events'], function (events) {
|
||||
return apiClient.getPublicSystemInfo().then(function (info) {
|
||||
var localAddress = info.LocalAddress
|
||||
if (!localAddress) {
|
||||
console.debug("No valid local address returned, defaulting to external one")
|
||||
console.log("No valid local address returned, defaulting to external one")
|
||||
localAddress = serverAddress;
|
||||
}
|
||||
addToCache(serverAddress, localAddress);
|
||||
@@ -231,4 +230,4 @@ define(['events'], function (events) {
|
||||
return {
|
||||
getServerAddress: getServerAddress
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
var currentResolve;
|
||||
var currentReject;
|
||||
|
||||
var PlayerName = 'Google Cast';
|
||||
var PlayerName = 'Chromecast';
|
||||
|
||||
function sendConnectionResult(isOk) {
|
||||
|
||||
@@ -105,7 +105,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
this.sessionListener.bind(this),
|
||||
this.receiverListener.bind(this));
|
||||
|
||||
console.debug('chromecast.initialize');
|
||||
console.log('chromecast.initialize');
|
||||
chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.errorHandler);
|
||||
};
|
||||
|
||||
@@ -114,14 +114,14 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
*/
|
||||
CastPlayer.prototype.onInitSuccess = function () {
|
||||
this.isInitialized = true;
|
||||
console.debug("chromecast init success");
|
||||
console.log("chromecast init success");
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic error callback function
|
||||
*/
|
||||
CastPlayer.prototype.onError = function () {
|
||||
console.debug("chromecast error");
|
||||
console.log("chromecast error");
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -177,10 +177,10 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
*/
|
||||
CastPlayer.prototype.receiverListener = function (e) {
|
||||
if (e === 'available') {
|
||||
console.debug("chromecast receiver found");
|
||||
console.log("chromecast receiver found");
|
||||
this.hasReceivers = true;
|
||||
} else {
|
||||
console.debug("chromecast receiver list empty");
|
||||
console.log("chromecast receiver list empty");
|
||||
this.hasReceivers = false;
|
||||
}
|
||||
};
|
||||
@@ -190,7 +190,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
*/
|
||||
CastPlayer.prototype.sessionUpdateListener = function (isAlive) {
|
||||
if (isAlive) {
|
||||
console.debug('sessionUpdateListener: already alive');
|
||||
console.log('sessionUpdateListener: already alive');
|
||||
} else {
|
||||
this.session = null;
|
||||
this.deviceState = DEVICE_STATE.IDLE;
|
||||
@@ -198,7 +198,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||
document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||
|
||||
console.debug('sessionUpdateListener: setting currentMediaSession to null');
|
||||
console.log('sessionUpdateListener: setting currentMediaSession to null');
|
||||
this.currentMediaSession = null;
|
||||
|
||||
sendConnectionResult(false);
|
||||
@@ -211,7 +211,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
* session request in opt_sessionRequest.
|
||||
*/
|
||||
CastPlayer.prototype.launchApp = function () {
|
||||
console.debug("chromecast launching app...");
|
||||
console.log("chromecast launching app...");
|
||||
chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this));
|
||||
};
|
||||
|
||||
@@ -220,7 +220,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
* @param {Object} e A chrome.cast.Session object
|
||||
*/
|
||||
CastPlayer.prototype.onRequestSessionSuccess = function (e) {
|
||||
console.debug("chromecast session success: " + e.sessionId);
|
||||
console.log("chromecast session success: " + e.sessionId);
|
||||
this.onSessionConnected(e);
|
||||
};
|
||||
|
||||
@@ -262,7 +262,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
* Callback function for launch error
|
||||
*/
|
||||
CastPlayer.prototype.onLaunchError = function () {
|
||||
console.debug("chromecast launch error");
|
||||
console.log("chromecast launch error");
|
||||
this.deviceState = DEVICE_STATE.ERROR;
|
||||
sendConnectionResult(false);
|
||||
};
|
||||
@@ -280,7 +280,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
* Callback function for stop app success
|
||||
*/
|
||||
CastPlayer.prototype.onStopAppSuccess = function (message) {
|
||||
console.debug(message);
|
||||
console.log(message);
|
||||
|
||||
this.deviceState = DEVICE_STATE.IDLE;
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
@@ -296,7 +296,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
*/
|
||||
CastPlayer.prototype.loadMedia = function (options, command) {
|
||||
if (!this.session) {
|
||||
console.debug("no session");
|
||||
console.log("no session");
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
};
|
||||
|
||||
CastPlayer.prototype.onPlayCommandSuccess = function () {
|
||||
console.debug('Message was sent to receiver ok.');
|
||||
//console.log('Message was sent to receiver ok.');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -386,7 +386,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
*/
|
||||
CastPlayer.prototype.onMediaDiscovered = function (how, mediaSession) {
|
||||
|
||||
console.debug("chromecast new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')');
|
||||
//console.log("chromecast new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')');
|
||||
this.currentMediaSession = mediaSession;
|
||||
|
||||
if (how === 'loadMedia') {
|
||||
@@ -405,7 +405,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
* @param {!Boolean} e true/false
|
||||
*/
|
||||
CastPlayer.prototype.onMediaStatusUpdate = function (e) {
|
||||
console.debug("chromecast updating media: " + e);
|
||||
//console.log("chromecast updating media: " + e);
|
||||
if (e === false) {
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
}
|
||||
@@ -417,7 +417,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
*/
|
||||
CastPlayer.prototype.setReceiverVolume = function (mute, vol) {
|
||||
if (!this.currentMediaSession) {
|
||||
console.debug('this.currentMediaSession is null');
|
||||
//console.log('this.currentMediaSession is null');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -443,7 +443,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
* Callback function for media command success
|
||||
*/
|
||||
CastPlayer.prototype.mediaCommandSuccessCallback = function (info, e) {
|
||||
console.debug(info);
|
||||
//console.log(info);
|
||||
};
|
||||
|
||||
function normalizeImages(state) {
|
||||
@@ -479,7 +479,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
TotalRecordCount: 1
|
||||
};
|
||||
});
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
|
||||
query.Limit = query.Limit || 100;
|
||||
query.ExcludeLocationTypes = "Virtual";
|
||||
@@ -493,7 +494,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
|
||||
events.on(instance._castPlayer, eventName, function (e, data) {
|
||||
|
||||
console.debug('cc: ' + eventName);
|
||||
//console.log('cc: ' + eventName);
|
||||
var state = instance.getPlayerStateInternal(data);
|
||||
|
||||
events.trigger(instance, eventName, [state]);
|
||||
@@ -520,14 +521,14 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
playbackManager.setActivePlayer(PlayerName, instance.getCurrentTargetInfo());
|
||||
}
|
||||
|
||||
console.debug('cc: connect');
|
||||
console.log('cc: connect');
|
||||
// Reset this so that statechange will fire
|
||||
instance.lastPlayerData = null;
|
||||
});
|
||||
|
||||
events.on(instance._castPlayer, "playbackstart", function (e, data) {
|
||||
|
||||
console.debug('cc: playbackstart');
|
||||
console.log('cc: playbackstart');
|
||||
|
||||
instance._castPlayer.initializeCastPlayer();
|
||||
|
||||
@@ -537,7 +538,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
|
||||
events.on(instance._castPlayer, "playbackstop", function (e, data) {
|
||||
|
||||
console.debug('cc: playbackstop');
|
||||
console.log('cc: playbackstop');
|
||||
var state = instance.getPlayerStateInternal(data);
|
||||
|
||||
events.trigger(instance, "playbackstop", [state]);
|
||||
@@ -555,7 +556,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
|
||||
events.on(instance._castPlayer, "playbackprogress", function (e, data) {
|
||||
|
||||
console.debug('cc: positionchange');
|
||||
//console.log('cc: positionchange');
|
||||
var state = instance.getPlayerStateInternal(data);
|
||||
|
||||
events.trigger(instance, "timeupdate", [state]);
|
||||
@@ -569,7 +570,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
|
||||
events.on(instance._castPlayer, "playstatechange", function (e, data) {
|
||||
|
||||
console.debug('cc: playstatechange');
|
||||
//console.log('cc: playstatechange');
|
||||
var state = instance.getPlayerStateInternal(data);
|
||||
|
||||
events.trigger(instance, "pause", [state]);
|
||||
@@ -664,7 +665,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
|
||||
normalizeImages(data);
|
||||
|
||||
console.debug(JSON.stringify(data));
|
||||
//console.log(JSON.stringify(data));
|
||||
|
||||
if (triggerStateChange) {
|
||||
events.trigger(this, "statechange", [data]);
|
||||
@@ -686,13 +687,6 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
});
|
||||
}
|
||||
|
||||
if (options.items.length > 1 && options && options.ids) {
|
||||
// Use the original request id array for sorting the result in the proper order
|
||||
options.items.sort(function (a, b) {
|
||||
return options.ids.indexOf(a.Id) - options.ids.indexOf(b.Id);
|
||||
});
|
||||
}
|
||||
|
||||
return this._castPlayer.loadMedia(options, command);
|
||||
};
|
||||
|
||||
@@ -758,7 +752,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
|
||||
ChromecastPlayer.prototype.volumeDown = function () {
|
||||
var vol = this._castPlayer.session.receiver.volume.level;
|
||||
if (vol == null) {
|
||||
if (vol == null)
|
||||
{
|
||||
vol = 0.5;
|
||||
}
|
||||
vol -= 0.05;
|
||||
@@ -781,7 +776,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', '
|
||||
|
||||
ChromecastPlayer.prototype.volumeUp = function () {
|
||||
var vol = this._castPlayer.session.receiver.volume.level;
|
||||
if (vol == null) {
|
||||
if (vol == null)
|
||||
{
|
||||
vol = 0.5;
|
||||
}
|
||||
vol += 0.05;
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
vertical-align: middle;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
@@ -243,13 +243,13 @@ define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManage
|
||||
var title = items.length ? globalize.translate('HeaderAddToCollection') : globalize.translate('NewCollection');
|
||||
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="material-icons arrow_back"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
html += title;
|
||||
html += '</h3>';
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += '<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="' + globalize.translate('Help') + '"><i class="material-icons">info</i><span style="margin-left:.25em;">' + globalize.translate('Help') + '</span></a>';
|
||||
html += '<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="' + globalize.translate('Help') + '"><i class="md-icon"></i><span style="margin-left:.25em;">' + globalize.translate('Help') + '</span></a>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
@@ -284,4 +284,4 @@ define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManage
|
||||
};
|
||||
|
||||
return CollectionEditor;
|
||||
});
|
||||
});
|
||||
@@ -24,4 +24,4 @@ define([], function () {
|
||||
return Promise.reject();
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -279,4 +279,4 @@ define(['globalize'], function (globalize) {
|
||||
return toLocaleTimeStringSupportsLocales;
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -51,8 +51,7 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
|
||||
dlg.querySelector('.dialogContentInner').classList.add('hide');
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
var i, length;
|
||||
var html = '';
|
||||
var hasDescriptions = false;
|
||||
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
</div>
|
||||
|
||||
<div class="formDialogFooter formDialogFooter-clear formDialogFooter-flex" style="padding-bottom: 1.5em;">
|
||||
</div>
|
||||
</div>
|
||||
3
src/components/dialog/package.json
Normal file
3
src/components/dialog/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "dialog.js"
|
||||
}
|
||||
@@ -18,7 +18,8 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
if (layoutManager.tv) {
|
||||
if (dlg.classList.contains('scrollX')) {
|
||||
centerFocus(dlg, true, false);
|
||||
} else if (dlg.classList.contains('smoothScrollY')) {
|
||||
}
|
||||
else if (dlg.classList.contains('smoothScrollY')) {
|
||||
centerFocus(dlg, false, false);
|
||||
}
|
||||
}
|
||||
@@ -32,7 +33,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
try {
|
||||
parentNode.removeChild(elem);
|
||||
} catch (err) {
|
||||
console.error('error removing dialog element: ' + err);
|
||||
console.log('Error removing dialog element: ' + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,8 +168,8 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
close(dlg);
|
||||
}
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
function isHistoryEnabled(dlg) {
|
||||
@@ -242,15 +243,9 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
|
||||
var onAnimationFinish = function () {
|
||||
focusManager.pushScope(dlg);
|
||||
|
||||
if (dlg.getAttribute('data-autofocus') === 'true') {
|
||||
focusManager.autoFocus(dlg);
|
||||
}
|
||||
|
||||
if (document.activeElement && !dlg.contains(document.activeElement)) {
|
||||
// Blur foreign element to prevent triggering of an action from the previous scope
|
||||
document.activeElement.blur();
|
||||
}
|
||||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
@@ -438,7 +433,8 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg, true, true);
|
||||
}
|
||||
} else if (options.scrollY !== false) {
|
||||
}
|
||||
else if (options.scrollY !== false) {
|
||||
dlg.classList.add('smoothScrollY');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
@@ -487,4 +483,4 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
globalOnOpenCallback = val;
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -15,12 +15,11 @@
|
||||
|
||||
.dialog {
|
||||
margin: 0;
|
||||
border-radius: 0.2em;
|
||||
border-radius: .2em;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
will-change: transform, opacity;
|
||||
|
||||
/* Strict does not work well with actionsheet */
|
||||
contain: style paint;
|
||||
box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.4);
|
||||
@@ -52,13 +51,13 @@
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
transform: scale(.5);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scaleup {
|
||||
from {
|
||||
transform: scale(0.5);
|
||||
transform: scale(.5);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@@ -79,6 +78,7 @@
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -101,6 +101,7 @@
|
||||
}
|
||||
|
||||
@keyframes slidedown {
|
||||
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
@@ -113,8 +114,8 @@
|
||||
}
|
||||
|
||||
@media all and (max-width: 80em), all and (max-height: 45em) {
|
||||
.dialog-fixedSize,
|
||||
.dialog-fullscreen-lowres {
|
||||
|
||||
.dialog-fixedSize, .dialog-fullscreen-lowres {
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
bottom: 0 !important;
|
||||
@@ -126,6 +127,7 @@
|
||||
}
|
||||
|
||||
@media all and (min-width: 80em) and (min-height: 45em) {
|
||||
|
||||
.dialog-medium {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
@@ -167,5 +169,5 @@
|
||||
}
|
||||
|
||||
.dialogBackdropOpened {
|
||||
opacity: 0.5;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
3
src/components/dialogHelper/package.json
Normal file
3
src/components/dialogHelper/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "dialogHelper.js"
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#ulDirectoryPickerList a {
|
||||
padding-top: 0.4em;
|
||||
padding-bottom: 0.4em;
|
||||
padding-top: .4em;
|
||||
padding-bottom: .4em
|
||||
}
|
||||
|
||||
.lblDirectoryPickerPath {
|
||||
white-space: nowrap;
|
||||
}
|
||||
white-space: nowrap
|
||||
}
|
||||
@@ -76,7 +76,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
|
||||
html += name;
|
||||
html += "</div>";
|
||||
html += "</div>";
|
||||
html += '<i class="material-icons arrow_forward" style="font-size:inherit;"></i>';
|
||||
html += '<i class="md-icon" style="font-size:inherit;">arrow_forward</i>';
|
||||
html += "</div>";
|
||||
return html;
|
||||
}
|
||||
@@ -115,8 +115,8 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
|
||||
var readOnlyAttribute = options.pathReadOnly ? " readonly" : "";
|
||||
html += '<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ' + readOnlyAttribute + ' label="' + Globalize.translate(labelKey) + '"/>';
|
||||
html += "</div>";
|
||||
if (!readOnlyAttribute) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="' + Globalize.translate("ButtonRefresh") + '"><i class="material-icons">search</i></button>';
|
||||
if (!readOnlyAttribute) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="' + Globalize.translate("ButtonRefresh") + '"><i class="md-icon">search</i></button>';
|
||||
}
|
||||
html += "</div>";
|
||||
if (!readOnlyAttribute) {
|
||||
@@ -188,9 +188,9 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
|
||||
var path = lnkPath.getAttribute("data-path");
|
||||
if (lnkPath.classList.contains("lnkFile")) {
|
||||
content.querySelector("#txtDirectoryPickerPath").value = path;
|
||||
} else {
|
||||
} else {
|
||||
refreshDirectoryBrowser(content, path, fileOptions, true)
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -254,10 +254,10 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
|
||||
var systemInfo = responses[0];
|
||||
var initialPath = responses[1];
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: "medium-tall",
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
size: "medium-tall",
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add("ui-body-a");
|
||||
dlg.classList.add("background-theme-a");
|
||||
dlg.classList.add("directoryPicker");
|
||||
@@ -265,7 +265,7 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-
|
||||
|
||||
var html = "";
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseDialog autoSize" tabindex="-1"><i class="material-icons arrow_back"></i></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseDialog autoSize" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
html += options.header || Globalize.translate("HeaderSelectPath");
|
||||
html += "</h3>";
|
||||
|
||||
@@ -180,7 +180,6 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
|
||||
context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs();
|
||||
context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos();
|
||||
context.querySelector('#chkFadein').checked = userSettings.enableFastFadein();
|
||||
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
|
||||
|
||||
context.querySelector('#selectLanguage').value = userSettings.language() || '';
|
||||
@@ -217,7 +216,6 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
|
||||
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
|
||||
|
||||
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);
|
||||
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
||||
|
||||
if (user.Id === apiClient.getCurrentUserId()) {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<h2 class="sectionTitle">
|
||||
${Display}
|
||||
</h2>
|
||||
|
||||
<div class="selectContainer languageSection hide">
|
||||
<select id="selectLanguage" is="emby-select" label="${LabelDisplayLanguage}">
|
||||
<option value="">${Auto}</option>
|
||||
@@ -134,7 +133,6 @@
|
||||
<div class="selectContainer selectDashboardThemeContainer hide">
|
||||
<select id="selectDashboardTheme" is="emby-select" label="${LabelDashboardTheme}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer hide selectScreensaverContainer">
|
||||
<select is="emby-select" class="selectScreensaver" label="${LabelScreensaver}"></select>
|
||||
</div>
|
||||
@@ -143,14 +141,6 @@
|
||||
<select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldFadein">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkFadein" />
|
||||
<span>${EnableFastImageFadeIn}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableFastImageFadeInHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkBackdrops" />
|
||||
@@ -158,7 +148,6 @@
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBackdropsHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldThemeSong hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkThemeSong" />
|
||||
@@ -166,7 +155,6 @@
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableThemeSongsHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldThemeVideo hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkThemeVideo" />
|
||||
|
||||
@@ -63,15 +63,12 @@ define([], function () {
|
||||
var supportsCaptureOption = false;
|
||||
try {
|
||||
var opts = Object.defineProperty({}, 'capture', {
|
||||
// eslint-disable-next-line getter-return
|
||||
get: function () {
|
||||
supportsCaptureOption = true;
|
||||
}
|
||||
});
|
||||
window.addEventListener("test", null, opts);
|
||||
} catch (e) {
|
||||
console.debug('error checking capture support');
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
function addEventListenerWithOptions(target, type, handler, options) {
|
||||
var optionsOrCapture = options;
|
||||
@@ -112,22 +109,6 @@ define([], function () {
|
||||
return windowSize;
|
||||
}
|
||||
|
||||
var standardWidths = [480, 720, 1280, 1440, 1920, 2560, 3840, 5120, 7680];
|
||||
function getScreenWidth() {
|
||||
var width = window.innerWidth;
|
||||
var height = window.innerHeight;
|
||||
|
||||
if (height > width) {
|
||||
width = height * (16.0 / 9.0);
|
||||
}
|
||||
|
||||
var closest = standardWidths.sort(function (a, b) {
|
||||
return Math.abs(width - a) - Math.abs(width - b);
|
||||
})[0];
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
var _animationEvent;
|
||||
function whichAnimationEvent() {
|
||||
|
||||
@@ -135,8 +116,8 @@ define([], function () {
|
||||
return _animationEvent;
|
||||
}
|
||||
|
||||
var t;
|
||||
var el = document.createElement("div");
|
||||
var t,
|
||||
el = document.createElement("div");
|
||||
var animations = {
|
||||
"animation": "animationend",
|
||||
"OAnimation": "oAnimationEnd",
|
||||
@@ -165,8 +146,8 @@ define([], function () {
|
||||
return _transitionEvent;
|
||||
}
|
||||
|
||||
var t;
|
||||
var el = document.createElement("div");
|
||||
var t,
|
||||
el = document.createElement("div");
|
||||
var transitions = {
|
||||
"transition": "transitionend",
|
||||
"OTransition": "oTransitionEnd",
|
||||
@@ -191,9 +172,8 @@ define([], function () {
|
||||
addEventListener: addEventListenerWithOptions,
|
||||
removeEventListener: removeEventListenerWithOptions,
|
||||
getWindowSize: getWindowSize,
|
||||
getScreenWidth: getScreenWidth,
|
||||
whichTransitionEvent: whichTransitionEvent,
|
||||
whichAnimationEvent: whichAnimationEvent,
|
||||
whichAnimationCancelEvent: whichAnimationCancelEvent
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -8,9 +8,6 @@
|
||||
font-size: inherit;
|
||||
font-family: inherit;
|
||||
color: inherit;
|
||||
|
||||
/* These are getting an outline in opera tv browsers, which run chrome 30 */
|
||||
outline: none !important;
|
||||
outline-width: 0;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
@@ -21,13 +18,15 @@
|
||||
padding: 0.9em 1em;
|
||||
vertical-align: middle;
|
||||
border: 0;
|
||||
vertical-align: middle;
|
||||
border-radius: 0.2em;
|
||||
/* These are getting an outline in opera tv browsers, which run chrome 30 */
|
||||
outline: none !important;
|
||||
position: relative;
|
||||
font-weight: 600;
|
||||
|
||||
/* Disable webkit tap highlighting */
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
text-decoration: none;
|
||||
|
||||
/* Not crazy about this but it normalizes heights between anchors and buttons */
|
||||
line-height: 1.35;
|
||||
transform-origin: center;
|
||||
@@ -35,7 +34,7 @@
|
||||
}
|
||||
|
||||
.emby-button.show-focus:focus {
|
||||
transform: scale(1.2);
|
||||
transform: scale(1.4);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -47,6 +46,10 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.button-flat:hover {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.button-link {
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
@@ -81,7 +84,7 @@
|
||||
display: block;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0.25em 0;
|
||||
margin: .25em 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -90,7 +93,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
margin: 0 0.29em;
|
||||
margin: 0 .29em;
|
||||
background: transparent;
|
||||
text-align: center;
|
||||
font-size: inherit;
|
||||
@@ -106,54 +109,54 @@
|
||||
min-height: initial;
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding: 0.556em;
|
||||
padding: .556em;
|
||||
vertical-align: middle;
|
||||
border: 0;
|
||||
|
||||
vertical-align: middle;
|
||||
/* These are getting an outline in opera tv browsers, which run chrome 30 */
|
||||
outline: none !important;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
|
||||
/* Disable webkit tap highlighting */
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
justify-content: center;
|
||||
transform-origin: center;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.paper-icon-button-light.show-focus:focus {
|
||||
transform: scale(1.3);
|
||||
transform: scale(1.6);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.paper-icon-button-light::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
.paper-icon-button-light::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.paper-icon-button-light:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: default;
|
||||
}
|
||||
.paper-icon-button-light:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.paper-icon-button-light > i {
|
||||
font-size: 1.66956521739130434em;
|
||||
.paper-icon-button-light > i {
|
||||
font-size: 1.66956521739130434em;
|
||||
/* Make sure its on top of the ripple */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Make sure its on top of the ripple */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.paper-icon-button-light > div {
|
||||
max-height: 100%;
|
||||
transform: scale(1.8);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
display: inline;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.paper-icon-button-light > img {
|
||||
width: 1.72em;
|
||||
/* Can't use 100% height or it will stretch past the boundaries in safari */
|
||||
/*height: 100%;*/
|
||||
max-height: 100%;
|
||||
/* Make sure its on top of the ripple */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.emby-button-foreground {
|
||||
position: relative;
|
||||
@@ -167,6 +170,7 @@
|
||||
.filterButtonBubble {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
background: #444;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 1.6em;
|
||||
@@ -177,7 +181,7 @@
|
||||
justify-content: center;
|
||||
font-size: 82%;
|
||||
border-radius: 100em;
|
||||
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
|
||||
background: #03a9f4;
|
||||
box-shadow: 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12), 0px 2px 4px -1px rgba(0, 0, 0, 0.2);
|
||||
background: #03A9F4;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
.emby-checkbox {
|
||||
position: absolute;
|
||||
|
||||
/* This is for focusing purposes, so the focusManager doesn't skip over it */
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
@@ -50,13 +49,14 @@
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 0;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
width: 1.83em;
|
||||
height: 1.83em;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
border: 0.14em solid currentcolor;
|
||||
border-radius: 0.14em;
|
||||
border: 2px solid currentcolor;
|
||||
border-radius: .14em;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -68,8 +68,7 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.checkboxIcon-checked,
|
||||
.emby-checkbox-label .checkboxIcon-checked {
|
||||
.checkboxIcon-checked {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -102,28 +101,18 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.checkboxList-verticalwrap > .emby-checkbox-label {
|
||||
display: inline-flex;
|
||||
margin: 0.3em 0 0.3em 0;
|
||||
width: 12em;
|
||||
}
|
||||
.checkboxList-verticalwrap > .emby-checkbox-label {
|
||||
display: inline-flex;
|
||||
margin: .3em 0 .3em 0;
|
||||
width: 12em;
|
||||
}
|
||||
|
||||
.checkboxList-paperList {
|
||||
padding: 1em !important;
|
||||
}
|
||||
|
||||
.checkboxListLabel {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
@keyframes repaintChrome {
|
||||
from {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
padding: 0;
|
||||
}
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
@-webkit-keyframes repaintChrome {
|
||||
@@ -5,8 +5,7 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b
|
||||
|
||||
function onKeyDown(e) {
|
||||
// Don't submit form on enter
|
||||
// Real (non-emulator) Tizen does nothing on Space
|
||||
if (e.keyCode === 13 || e.keyCode === 32) {
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
|
||||
this.checked = !this.checked;
|
||||
@@ -55,10 +54,10 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b
|
||||
outlineClass += ' ' + customClass;
|
||||
}
|
||||
|
||||
var checkedIcon = this.getAttribute('data-checkedicon') || 'check';
|
||||
var checkedIcon = this.getAttribute('data-checkedicon') || '';
|
||||
var uncheckedIcon = this.getAttribute('data-uncheckedicon') || '';
|
||||
var checkHtml = '<i class="material-icons checkboxIcon checkboxIcon-checked">' + checkedIcon + '</i>';
|
||||
var uncheckedHtml = '<i class="material-icons checkboxIcon checkboxIcon-unchecked">' + uncheckedIcon + '</i>';
|
||||
var checkHtml = '<i class="md-icon checkboxIcon checkboxIcon-checked">' + checkedIcon + '</i>';
|
||||
var uncheckedHtml = '<i class="md-icon checkboxIcon checkboxIcon-unchecked">' + uncheckedIcon + '</i>';
|
||||
labelElement.insertAdjacentHTML('beforeend', '<span class="' + outlineClass + '">' + checkHtml + uncheckedHtml + '</span>');
|
||||
|
||||
labelTextElement.classList.add('checkboxLabel');
|
||||
@@ -1,5 +1,5 @@
|
||||
.emby-collapse {
|
||||
margin: 0.5em 0;
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
.collapseContent {
|
||||
@@ -18,9 +18,10 @@
|
||||
text-transform: none;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
border-width: 0 0 0.1em 0;
|
||||
text-transform: none;
|
||||
border-width: 0 0 .1em 0;
|
||||
border-style: solid;
|
||||
padding-left: 0.1em;
|
||||
padding-left: .1em;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -29,7 +30,7 @@
|
||||
transform-origin: 50% 50%;
|
||||
transition: transform 180ms ease-out;
|
||||
position: absolute;
|
||||
right: 0.5em;
|
||||
right: .5em;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], fun
|
||||
|
||||
var title = this.getAttribute('title');
|
||||
|
||||
var html = '<button is="emby-button" type="button" on-click="toggleExpand" id="expandButton" class="emby-collapsible-button iconRight"><h3 class="emby-collapsible-title" title="' + title + '">' + title + '</h3><i class="material-icons emby-collapse-expandIcon expand_more"></i></button>';
|
||||
var html = '<button is="emby-button" type="button" on-click="toggleExpand" id="expandButton" class="emby-collapsible-button iconRight"><h3 class="emby-collapsible-title" title="' + title + '">' + title + '</h3><i class="md-icon emby-collapse-expandIcon">expand_more</i></button>';
|
||||
|
||||
this.insertAdjacentHTML('afterbegin', html);
|
||||
|
||||
@@ -97,4 +97,4 @@ define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], fun
|
||||
prototype: EmbyButtonPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2,28 +2,24 @@
|
||||
display: block;
|
||||
margin: 0;
|
||||
margin-bottom: 0 !important;
|
||||
/* Remove select styling */
|
||||
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
|
||||
font-size: 110%;
|
||||
/* General select styles: change as needed */
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
padding: 0.4em 0.25em;
|
||||
|
||||
/* must the 16px or larger to prevent iOS page zoom on focus */
|
||||
font-size: 110%;
|
||||
|
||||
/* prevent padding from causing width overflow */
|
||||
padding: .4em .25em;
|
||||
/* Prevent padding from causing width overflow */
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
outline: none !important;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.emby-input::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.emby-input:required {
|
||||
box-shadow: none;
|
||||
}
|
||||
.emby-input::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.inputContainer {
|
||||
margin-bottom: 1.8em;
|
||||
@@ -31,11 +27,11 @@
|
||||
|
||||
.inputLabel {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.25em;
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
|
||||
.emby-input + .fieldDescription {
|
||||
margin-top: 0.25em;
|
||||
margin-top: .25em;
|
||||
}
|
||||
|
||||
.emby-input-iconbutton {
|
||||
@@ -28,12 +28,11 @@ define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'registerElement'
|
||||
}
|
||||
|
||||
EmbyInputPrototype.createdCallback = function () {
|
||||
|
||||
if (!this.id) {
|
||||
this.id = 'embyinput' + inputId;
|
||||
inputId++;
|
||||
}
|
||||
|
||||
if (this.classList.contains('emby-input')) {
|
||||
} if (this.classList.contains('emby-input')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -123,4 +122,4 @@ define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'registerElement'
|
||||
prototype: EmbyInputPrototype,
|
||||
extends: 'input'
|
||||
});
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user