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

Merge branch 'master' into scss-config

This commit is contained in:
dkanada 2020-08-04 03:39:08 +09:00 committed by GitHub
commit a32a21a590
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
517 changed files with 32550 additions and 26344 deletions

View file

@ -0,0 +1,63 @@
jobs:
- job: Build
displayName: 'Build'
strategy:
matrix:
Development:
BuildConfiguration: development
Production:
BuildConfiguration: production
Standalone:
BuildConfiguration: standalone
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
displayName: 'Install Node'
inputs:
versionSpec: '12.x'
- task: Cache@2
displayName: 'Check Cache'
inputs:
key: 'yarn | yarn.lock'
path: 'node_modules'
cacheHitVar: CACHE_RESTORED
- script: 'yarn install --frozen-lockfile'
displayName: 'Install Dependencies'
condition: ne(variables.CACHE_RESTORED, 'true')
- script: 'yarn build:development'
displayName: 'Build Development'
condition: eq(variables['BuildConfiguration'], 'development')
- script: 'yarn build:production'
displayName: 'Build Production'
condition: eq(variables['BuildConfiguration'], 'production')
- script: 'yarn build:standalone'
displayName: 'Build Standalone'
condition: eq(variables['BuildConfiguration'], 'standalone')
- script: 'test -d dist'
displayName: 'Check Build'
- script: 'mv dist jellyfin-web'
displayName: 'Rename Directory'
- task: ArchiveFiles@2
displayName: 'Archive Directory'
inputs:
rootFolderOrFile: 'jellyfin-web'
includeRootFolder: true
archiveFile: 'jellyfin-web-$(BuildConfiguration)'
- task: PublishPipelineArtifact@1
displayName: 'Publish Release'
inputs:
targetPath: '$(Build.SourcesDirectory)/jellyfin-web-$(BuildConfiguration).zip'
artifactName: 'jellyfin-web-$(BuildConfiguration)'

View file

@ -0,0 +1,29 @@
jobs:
- job: Lint
displayName: 'Lint'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
displayName: 'Install Node'
inputs:
versionSpec: '12.x'
- task: Cache@2
displayName: 'Check Cache'
inputs:
key: 'yarn | yarn.lock'
path: 'node_modules'
cacheHitVar: CACHE_RESTORED
- script: 'yarn install --frozen-lockfile'
displayName: 'Install Dependencies'
condition: ne(variables.CACHE_RESTORED, 'true')
- script: 'yarn run lint --quiet'
displayName: 'Run ESLint'
- script: 'yarn run stylelint'
displayName: 'Run Stylelint'

View file

@ -0,0 +1,122 @@
jobs:
- job: BuildPackage
displayName: 'Build Packages'
strategy:
matrix:
CentOS:
BuildConfiguration: centos
Debian:
BuildConfiguration: debian
Fedora:
BuildConfiguration: fedora
Portable:
BuildConfiguration: portable
pool:
vmImage: 'ubuntu-latest'
steps:
- script: 'docker build -f deployment/Dockerfile.$(BuildConfiguration) -t jellyfin-web-$(BuildConfiguration) deployment'
displayName: 'Build Dockerfile'
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
- script: 'docker image ls -a && docker run -v $(pwd)/deployment/dist:/dist -v $(pwd):/jellyfin -e IS_UNSTABLE="yes" -e BUILD_ID=$(Build.BuildNumber) jellyfin-web-$(BuildConfiguration)'
displayName: 'Run Dockerfile (unstable)'
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
- script: 'docker image ls -a && docker run -v $(pwd)/deployment/dist:/dist -v $(pwd):/jellyfin -e IS_UNSTABLE="no" -e BUILD_ID=$(Build.BuildNumber) jellyfin-web-$(BuildConfiguration)'
displayName: 'Run Dockerfile (stable)'
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
- task: PublishPipelineArtifact@1
displayName: 'Publish Release'
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
inputs:
targetPath: '$(Build.SourcesDirectory)/deployment/dist'
artifactName: 'jellyfin-web-$(BuildConfiguration)'
- task: SSH@0
displayName: 'Create target directory on repository server'
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
inputs:
sshEndpoint: repository
runOptions: 'inline'
inline: 'mkdir -p /srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
- task: CopyFilesOverSSH@0
displayName: 'Upload artifacts to repository server'
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
inputs:
sshEndpoint: repository
sourceFolder: '$(Build.SourcesDirectory)/deployment/dist'
contents: '**'
targetFolder: '/srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
- job: BuildDocker
displayName: 'Build Docker'
pool:
vmImage: 'ubuntu-latest'
variables:
- name: JellyfinVersion
value: 0.0.0
steps:
- script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
displayName: Set release version (stable)
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
- task: Docker@2
displayName: 'Push Unstable Image'
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
inputs:
repository: 'jellyfin/jellyfin-web'
command: buildAndPush
buildContext: '.'
Dockerfile: 'deployment/Dockerfile.docker'
containerRegistry: Docker Hub
tags: |
unstable-$(Build.BuildNumber)
unstable
- task: Docker@2
displayName: 'Push Stable Image'
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
inputs:
repository: 'jellyfin/jellyfin-web'
command: buildAndPush
buildContext: '.'
Dockerfile: 'deployment/Dockerfile.docker'
containerRegistry: Docker Hub
tags: |
stable-$(Build.BuildNumber)
$(JellyfinVersion)
- job: CollectArtifacts
displayName: 'Collect Artifacts'
dependsOn:
- BuildPackage
- BuildDocker
condition: and(succeeded('BuildPackage'), succeeded('BuildDocker'))
pool:
vmImage: 'ubuntu-latest'
steps:
- task: SSH@0
displayName: 'Update Unstable Repository'
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
inputs:
sshEndpoint: repository
runOptions: 'inline'
inline: 'sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber) unstable'
- task: SSH@0
displayName: 'Update Stable Repository'
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
inputs:
sshEndpoint: repository
runOptions: 'inline'
inline: 'sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber)'

View file

@ -12,94 +12,6 @@ pr:
- '*' - '*'
jobs: jobs:
- job: Build - template: azure-pipelines-build.yml
displayName: 'Build' - template: azure-pipelines-lint.yml
- template: azure-pipelines-package.yml
strategy:
matrix:
Development:
BuildConfiguration: development
Production:
BuildConfiguration: production
Standalone:
BuildConfiguration: standalone
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
displayName: 'Install Node'
inputs:
versionSpec: '12.x'
- task: Cache@2
displayName: 'Check Cache'
inputs:
key: 'yarn | yarn.lock'
path: 'node_modules'
cacheHitVar: CACHE_RESTORED
- script: 'yarn install --frozen-lockfile'
displayName: 'Install Dependencies'
condition: ne(variables.CACHE_RESTORED, 'true')
- script: 'yarn build:development'
displayName: 'Build Development'
condition: eq(variables['BuildConfiguration'], 'development')
- script: 'yarn build:production'
displayName: 'Build Bundle'
condition: eq(variables['BuildConfiguration'], 'production')
- script: 'yarn build:standalone'
displayName: 'Build Standalone'
condition: eq(variables['BuildConfiguration'], 'standalone')
- script: 'test -d dist'
displayName: 'Check Build'
- script: 'mv dist jellyfin-web'
displayName: 'Rename Directory'
- task: ArchiveFiles@2
displayName: 'Archive Directory'
inputs:
rootFolderOrFile: 'jellyfin-web'
includeRootFolder: true
archiveFile: 'jellyfin-web-$(BuildConfiguration)'
- task: PublishPipelineArtifact@1
displayName: 'Publish Release'
inputs:
targetPath: '$(Build.SourcesDirectory)/jellyfin-web-$(BuildConfiguration).zip'
artifactName: 'jellyfin-web-$(BuildConfiguration)'
- job: Lint
displayName: 'Lint'
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
displayName: 'Install Node'
inputs:
versionSpec: '12.x'
- task: Cache@2
displayName: 'Check Cache'
inputs:
key: 'yarn | yarn.lock'
path: 'node_modules'
cacheHitVar: CACHE_RESTORED
- script: 'yarn install --frozen-lockfile'
displayName: 'Install Dependencies'
condition: ne(variables.CACHE_RESTORED, 'true')
- script: 'yarn run lint --quiet'
displayName: 'Run ESLint'
- script: 'yarn run stylelint'
displayName: 'Run Stylelint'

View file

@ -2,4 +2,4 @@ version: 1
update_configs: update_configs:
- package_manager: "javascript" - package_manager: "javascript"
directory: "/" directory: "/"
update_schedule: "weekly" update_schedule: "live"

View file

@ -8,5 +8,5 @@ trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
end_of_line = lf end_of_line = lf
[json] [*.json]
indent_size = 2 indent_size = 2

View file

@ -1,6 +1,7 @@
module.exports = { module.exports = {
root: true, root: true,
plugins: [ plugins: [
'@babel',
'promise', 'promise',
'import', 'import',
'eslint-comments' 'eslint-comments'
@ -27,28 +28,34 @@ module.exports = {
'plugin:compat/recommended' 'plugin:compat/recommended'
], ],
rules: { rules: {
'block-spacing': ["error"], 'block-spacing': ['error'],
'brace-style': ["error"], 'brace-style': ['error', '1tbs', { 'allowSingleLine': true }],
'comma-dangle': ["error", "never"], 'comma-dangle': ['error', 'never'],
'comma-spacing': ["error"], 'comma-spacing': ['error'],
'eol-last': ["error"], 'eol-last': ['error'],
'indent': ["error", 4, { "SwitchCase": 1 }], 'indent': ['error', 4, { 'SwitchCase': 1 }],
'keyword-spacing': ["error"], 'keyword-spacing': ['error'],
'max-statements-per-line': ["error"], 'max-statements-per-line': ['error'],
'no-floating-decimal': ["error"], 'no-floating-decimal': ['error'],
'no-multi-spaces': ["error"], 'no-multi-spaces': ['error'],
'no-multiple-empty-lines': ["error", { "max": 1 }], 'no-multiple-empty-lines': ['error', { 'max': 1 }],
'no-trailing-spaces': ["error"], 'no-trailing-spaces': ['error'],
'one-var': ["error", "never"], 'no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }],
'quotes': ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": false }], 'no-unused-vars': ['error', { 'vars': 'all', 'args': 'none', 'ignoreRestSiblings': true }],
'semi': ["error"], 'one-var': ['error', 'never'],
'space-before-blocks': ["error"] 'padded-blocks': ['error', 'never'],
'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }],
'semi': ['error'],
'space-before-blocks': ['error'],
'space-infix-ops': 'error',
'yoda': 'error'
}, },
overrides: [ overrides: [
{ {
files: [ files: [
'./src/**/*.js' './src/**/*.js'
], ],
parser: '@babel/eslint-parser',
env: { env: {
node: false, node: false,
amd: true, amd: true,
@ -96,11 +103,10 @@ module.exports = {
}, },
rules: { rules: {
// TODO: Fix warnings and remove these rules // TODO: Fix warnings and remove these rules
'no-redeclare': ["warn"], 'no-redeclare': ['off'],
'no-unused-vars': ["warn"], 'no-useless-escape': ['off'],
'no-useless-escape': ["warn"],
// TODO: Remove after ES6 migration is complete // TODO: Remove after ES6 migration is complete
'import/no-unresolved': ["off"] 'import/no-unresolved': ['off']
}, },
settings: { settings: {
polyfills: [ polyfills: [
@ -130,6 +136,7 @@ module.exports = {
'Object.getOwnPropertyDescriptor', 'Object.getOwnPropertyDescriptor',
'Object.getPrototypeOf', 'Object.getPrototypeOf',
'Object.keys', 'Object.keys',
'Object.entries',
'Object.getOwnPropertyNames', 'Object.getOwnPropertyNames',
'Function.name', 'Function.name',
'Function.hasInstance', 'Function.hasInstance',
@ -190,4 +197,4 @@ module.exports = {
} }
} }
] ]
} };

4
.github/CODEOWNERS vendored
View file

@ -1,4 +1,6 @@
.ci @dkanada @EraYaN .ci @dkanada @EraYaN
.github @jellyfin/core .github @jellyfin/core
build.sh @joshuaboniface fedora @joshuaboniface
debian @joshuaboniface
.copr @joshuaboniface
deployment @joshuaboniface deployment @joshuaboniface

View file

@ -1,23 +1,20 @@
--- ---
name: Bug report name: Bug Report
about: Create a bug report about: You have noticed a general issue or regression, and would like to report it
title: ''
labels: bug labels: bug
assignees: ''
--- ---
**Describe the bug** **Describe The Bug**
<!-- A clear and concise description of what the bug is. --> <!-- A clear and concise description of what the bug is. -->
**To Reproduce** **Steps To Reproduce**
<!-- Steps to reproduce the behavior: --> <!-- Steps to reproduce the behavior: -->
1. Go to '...' 1. Go to '...'
2. Click on '....' 2. Click on '....'
3. Scroll down to '....' 3. Scroll down to '....'
4. See error 4. See error
**Expected behavior** **Expected Behavior**
<!-- A clear and concise description of what you expected to happen. --> <!-- A clear and concise description of what you expected to happen. -->
**Logs** **Logs**
@ -27,9 +24,9 @@ assignees: ''
<!-- If applicable, add screenshots to help explain your problem. --> <!-- If applicable, add screenshots to help explain your problem. -->
**System (please complete the following information):** **System (please complete the following information):**
- OS: [e.g. Docker, Debian, Windows] - Platform: [e.g. Linux, Windows, iPhone, Tizen]
- Browser: [e.g. Firefox, Chrome, Safari] - Browser: [e.g. Firefox, Chrome, Safari]
- Jellyfin Version: [e.g. 10.0.1] - Jellyfin Version: [e.g. 10.6.0]
**Additional context** **Additional Context**
<!-- Add any other context about the problem here. --> <!-- Add any other context about the problem here. -->

View file

@ -0,0 +1,22 @@
---
name: Playback Issue
about: You have playback issues with some files
labels: playback
---
**Describe The Bug**
<!-- A clear and concise description of what the bug is. -->
**Media Information**
<!-- Please paste any ffprobe or MediaInfo logs. -->
**Screenshots**
<!-- Add screenshots from the Playback Data and Media Info. -->
**System (please complete the following information):**
- Platform: [e.g. Linux, Windows, iPhone, Tizen]
- Browser: [e.g. Firefox, Chrome, Safari]
- Jellyfin Version: [e.g. 10.6.0]
**Additional Context**
<!-- Add any other context about the problem here. -->

View file

@ -0,0 +1,13 @@
---
name: Technical Discussion
about: You want to discuss technical aspects of changes you intend to make
labels: enhancement
---
<!-- Explain the change and the motivations behind it.
For example, if you plan to rely on a new dependency, explain why and what
it brings to the project.
If you plan to make significant changes, go roughly over the steps you intend
to take and how you would divide the change in PRs of a manageable size. -->

View file

@ -0,0 +1,9 @@
---
name: Meta Issue
about: You want to track a number of other issues as part of a larger project
labels: meta
---
* [ ] Issue 1 [#123]
* [ ] Issue 2 [#456]
* [ ] ...

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Feature Request
url: https://features.jellyfin.org/
about: Please head over to our feature request hub to vote on or submit a feature.
- name: Help Or Question
url: https://matrix.to/#/#jellyfin-troubleshooting:matrix.org
about: Please join the troubleshooting Matrix channel to get some help.

24
.github/SUPPORT.md vendored Normal file
View file

@ -0,0 +1,24 @@
# Support
Jellyfin contributors have limited availability to address general support
questions. Please make sure you are using the latest version of Jellyfin.
When looking for support or information, please first search for your
question in these venues:
* [Jellyfin Forum](https://forum.jellyfin.org)
* [Jellyfin Documentation](https://docs.jellyfin.org)
* [Open or **closed** issues in the organization](https://github.com/issues?q=sort%3Aupdated-desc+org%3Ajellyfin+is%3Aissue+)
If you didn't find an answer in the resources above, contributors and other
users are reachable through the following channels:
* #jellyfin on [Matrix](https://matrix.to/#/#jellyfin:matrix.org%22) or [IRC](https://webchat.freenode.net/#jellyfin)
* #jellyfin-troubleshooting on [Matrix](https://matrix.to/#/#jellyfin-troubleshooting:matrix.org) or [IRC](https://webchat.freenode.net/#jellyfin-troubleshooting)
* [/r/jellyfin on Reddit](https://www.reddit.com/r/jellyfin)
GitHub issues are for tracking enhancements and bugs, not general support.
The open source license grants you the freedom to use Jellyfin.
It does not guarantee commitments of other people's time.
Please be respectful and manage your expectations.

8
.gitignore vendored
View file

@ -1,6 +1,3 @@
# config
config.json
# npm # npm
dist dist
web web
@ -8,4 +5,7 @@ node_modules
# ide # ide
.idea .idea
.vscode .vscode
# log
yarn-error.log

View file

@ -36,6 +36,8 @@
- [MrTimscampi](https://github.com/MrTimscampi) - [MrTimscampi](https://github.com/MrTimscampi)
- [Sarab Singh](https://github.com/sarab97) - [Sarab Singh](https://github.com/sarab97)
- [GuilhermeHideki](https://github.com/GuilhermeHideki) - [GuilhermeHideki](https://github.com/GuilhermeHideki)
- [Andrei Oanca](https://github.com/OancaAndrei)
- [Cromefire_](https://github.com/cromefire)
# Emby Contributors # Emby Contributors

View file

@ -44,7 +44,8 @@ Jellyfin Web is the frontend used for most of the clients available for end user
### Dependencies ### Dependencies
- Yarn - [Node.js](https://nodejs.org/en/download/)
- [Yarn 1.22.4](https://classic.yarnpkg.com/en/docs/install)
- Gulp-cli - Gulp-cli
### Getting Started ### Getting Started
@ -78,4 +79,4 @@ Jellyfin Web is the frontend used for most of the clients available for end user
```sh ```sh
yarn build:standalone yarn build:standalone
``` ```

View file

@ -1,7 +1,7 @@
--- ---
# We just wrap `build` so this is really it # We just wrap `build` so this is really it
name: "jellyfin-web" name: "jellyfin-web"
version: "10.6.0" version: "10.7.0"
packages: packages:
- debian.all - debian.all
- fedora.all - fedora.all

View file

@ -4,6 +4,7 @@
set -o errexit set -o errexit
set -o pipefail set -o pipefail
set -o xtrace
usage() { usage() {
echo -e "bump_version - increase the shared version and generate changelogs" echo -e "bump_version - increase the shared version and generate changelogs"
@ -23,10 +24,7 @@ build_file="./build.yaml"
new_version="$1" new_version="$1"
# Parse the version from shared version file # Parse the version from shared version file
old_version="$( old_version="$( grep "appVersion" ${shared_version_file} | head -1 | sed -E "s/var appVersion = '([0-9\.]+)';/\1/" | tr -d '[:space:]' )"
grep "appVersion" ${shared_version_file} | head -1 \
| sed -E 's/var appVersion = "([0-9\.]+)";/\1/'
)"
echo "Old version in appHost is: $old_version" echo "Old version in appHost is: $old_version"
# Set the shared version to the specified new_version # Set the shared version to the specified new_version
@ -34,11 +32,8 @@ old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' cha
new_version_sed="$( cut -f1 -d'-' <<<"${new_version}" )" new_version_sed="$( cut -f1 -d'-' <<<"${new_version}" )"
sed -i "s/${old_version_sed}/${new_version_sed}/g" ${shared_version_file} sed -i "s/${old_version_sed}/${new_version_sed}/g" ${shared_version_file}
old_version="$( old_version="$( grep "version:" ${build_file} | sed -E 's/version: "([0-9\.]+[-a-z0-9]*)"/\1/' )"
grep "version:" ${build_file} \ echo "Old version in ${build_file}: ${old_version}"
| sed -E 's/version: "([0-9\.]+[-a-z0-9]*)"/\1/'
)"
echo "Old version in ${build_file}: $old_version`"
# Set the build.yaml version to the specified new_version # Set the build.yaml version to the specified new_version
old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars
@ -54,7 +49,7 @@ fi
debian_changelog_file="debian/changelog" debian_changelog_file="debian/changelog"
debian_changelog_temp="$( mktemp )" debian_changelog_temp="$( mktemp )"
# Create new temp file with our changelog # Create new temp file with our changelog
echo -e "jellyfin (${new_version_deb}) unstable; urgency=medium echo -e "jellyfin-web (${new_version_deb}) unstable; urgency=medium
* New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v${new_version} * New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v${new_version}
@ -65,15 +60,15 @@ cat ${debian_changelog_file} >> ${debian_changelog_temp}
mv ${debian_changelog_temp} ${debian_changelog_file} mv ${debian_changelog_temp} ${debian_changelog_file}
# Write out a temporary Yum changelog with our new stuff prepended and some templated formatting # Write out a temporary Yum changelog with our new stuff prepended and some templated formatting
fedora_spec_file="fedora/jellyfin.spec" fedora_spec_file="fedora/jellyfin-web.spec"
fedora_changelog_temp="$( mktemp )" fedora_changelog_temp="$( mktemp )"
fedora_spec_temp_dir="$( mktemp -d )" fedora_spec_temp_dir="$( mktemp -d )"
fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin.spec.tmp" fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin-web.spec.tmp"
# Make a copy of our spec file for hacking # Make a copy of our spec file for hacking
cp ${fedora_spec_file} ${fedora_spec_temp_dir}/ cp ${fedora_spec_file} ${fedora_spec_temp_dir}/
pushd ${fedora_spec_temp_dir} pushd ${fedora_spec_temp_dir}
# Split out the stuff before and after changelog # Split out the stuff before and after changelog
csplit jellyfin.spec "/^%changelog/" # produces xx00 xx01 csplit jellyfin-web.spec "/^%changelog/" # produces xx00 xx01
# Update the version in xx00 # Update the version in xx00
sed -i "s/${old_version_sed}/${new_version_sed}/g" xx00 sed -i "s/${old_version_sed}/${new_version_sed}/g" xx00
# Remove the header from xx01 # Remove the header from xx01
@ -92,5 +87,5 @@ mv ${fedora_spec_temp} ${fedora_spec_file}
rm -rf ${fedora_changelog_temp} ${fedora_spec_temp_dir} rm -rf ${fedora_changelog_temp} ${fedora_spec_temp_dir}
# Stage the changed files for commit # Stage the changed files for commit
git add ${shared_version_file} ${build_file} ${debian_changelog_file} ${fedora_spec_file} Dockerfile* git add ${shared_version_file} ${build_file} ${debian_changelog_file} ${fedora_spec_file}
git status git status

6
debian/changelog vendored
View file

@ -1,3 +1,9 @@
jellyfin-web (10.7.0-1) unstable; urgency=medium
* Forthcoming stable release
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 27 Jul 2020 19:13:31 -0400
jellyfin-web (10.6.0-1) unstable; urgency=medium jellyfin-web (10.6.0-1) unstable; urgency=medium
* New upstream version 10.6.0; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.0 * New upstream version 10.6.0; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.0

View file

@ -1,7 +1,9 @@
FROM centos:7 FROM centos:7
# Docker build arguments # Docker build arguments
ARG SOURCE_DIR=/jellyfin ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist ARG ARTIFACT_DIR=/dist
# Docker run environment # Docker run environment
ENV SOURCE_DIR=/jellyfin ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist ENV ARTIFACT_DIR=/dist
@ -9,19 +11,19 @@ ENV IS_DOCKER=YES
# Prepare CentOS environment # Prepare CentOS environment
RUN yum update -y \ RUN yum update -y \
&& yum install -y epel-release \ && yum install -y epel-release \
&& yum install -y @buildsys-build rpmdevtools git yum-plugins-core nodejs-yarn autoconf automake glibc-devel && yum install -y @buildsys-build rpmdevtools git yum-plugins-core nodejs-yarn autoconf automake glibc-devel
# Install recent NodeJS and Yarn # Install recent NodeJS and Yarn
RUN curl -fSsLo /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \ RUN curl -fSsLo /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \
&& rpm -i https://rpm.nodesource.com/pub_10.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm \ && rpm -i https://rpm.nodesource.com/pub_10.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm \
&& yum install -y yarn && yum install -y yarn
# Link to build script # Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.centos.all /build.sh RUN ln -sf ${SOURCE_DIR}/deployment/build.centos /build.sh
VOLUME ${SOURCE_DIR}/ VOLUME ${SOURCE_DIR}
VOLUME ${ARTIFACT_DIR}/ VOLUME ${ARTIFACT_DIR}
ENTRYPOINT ["/build.sh"] ENTRYPOINT ["/build.sh"]

View file

@ -1,7 +1,9 @@
FROM debian:10 FROM debian:10
# Docker build arguments # Docker build arguments
ARG SOURCE_DIR=/jellyfin ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist ARG ARTIFACT_DIR=/dist
# Docker run environment # Docker run environment
ENV SOURCE_DIR=/jellyfin ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist ENV ARTIFACT_DIR=/dist
@ -10,16 +12,16 @@ ENV IS_DOCKER=YES
# Prepare Debian build environment # Prepare Debian build environment
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y debhelper mmv npm git && apt-get install -y debhelper mmv npm git
# Prepare Yarn # Prepare Yarn
RUN npm install -g yarn RUN npm install -g yarn
# Link to build script # Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.all /build.sh RUN ln -sf ${SOURCE_DIR}/deployment/build.debian /build.sh
VOLUME ${SOURCE_DIR}/ VOLUME ${SOURCE_DIR}
VOLUME ${ARTIFACT_DIR}/ VOLUME ${ARTIFACT_DIR}
ENTRYPOINT ["/build.sh"] ENTRYPOINT ["/build.sh"]

View file

@ -0,0 +1,11 @@
FROM node:alpine
ARG SOURCE_DIR=/src
ARG ARTIFACT_DIR=/jellyfin-web
RUN apk add autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python
WORKDIR ${SOURCE_DIR}
COPY . .
RUN yarn install && mv dist ${ARTIFACT_DIR}

View file

@ -1,7 +1,9 @@
FROM fedora:31 FROM fedora:31
# Docker build arguments # Docker build arguments
ARG SOURCE_DIR=/jellyfin ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist ARG ARTIFACT_DIR=/dist
# Docker run environment # Docker run environment
ENV SOURCE_DIR=/jellyfin ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist ENV ARTIFACT_DIR=/dist
@ -9,13 +11,13 @@ ENV IS_DOCKER=YES
# Prepare Fedora environment # Prepare Fedora environment
RUN dnf update -y \ RUN dnf update -y \
&& dnf install -y @buildsys-build rpmdevtools git dnf-plugins-core nodejs-yarn autoconf automake glibc-devel && dnf install -y @buildsys-build rpmdevtools git dnf-plugins-core nodejs-yarn autoconf automake glibc-devel
# Link to build script # Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.fedora.all /build.sh RUN ln -sf ${SOURCE_DIR}/deployment/build.fedora /build.sh
VOLUME ${SOURCE_DIR}/ VOLUME ${SOURCE_DIR}
VOLUME ${ARTIFACT_DIR}/ VOLUME ${ARTIFACT_DIR}
ENTRYPOINT ["/build.sh"] ENTRYPOINT ["/build.sh"]

View file

@ -1,16 +1,17 @@
FROM debian:10 FROM debian:10
# Docker build arguments # Docker build arguments
ARG SOURCE_DIR=/jellyfin ARG SOURCE_DIR=/jellyfin
ARG ARTIFACT_DIR=/dist ARG ARTIFACT_DIR=/dist
# Docker run environment # Docker run environment
ENV SOURCE_DIR=/jellyfin ENV SOURCE_DIR=/jellyfin
ENV ARTIFACT_DIR=/dist ENV ARTIFACT_DIR=/dist
ENV DEB_BUILD_OPTIONS=noddebs
ENV IS_DOCKER=YES ENV IS_DOCKER=YES
# Prepare Debian build environment # Prepare Debian build environment
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y mmv npm git && apt-get install -y mmv npm git
# Prepare Yarn # Prepare Yarn
RUN npm install -g yarn RUN npm install -g yarn
@ -18,8 +19,8 @@ RUN npm install -g yarn
# Link to build script # Link to build script
RUN ln -sf ${SOURCE_DIR}/deployment/build.portable /build.sh RUN ln -sf ${SOURCE_DIR}/deployment/build.portable /build.sh
VOLUME ${SOURCE_DIR}/ VOLUME ${SOURCE_DIR}
VOLUME ${ARTIFACT_DIR}/ VOLUME ${ARTIFACT_DIR}
ENTRYPOINT ["/build.sh"] ENTRYPOINT ["/build.sh"]

41
deployment/build.centos Executable file
View file

@ -0,0 +1,41 @@
#!/bin/bash
set -o errexit
set -o xtrace
# move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# modify changelog to unstable configuration if IS_UNSTABLE
if [[ ${IS_UNSTABLE} == 'yes' ]]; then
pushd fedora
PR_ID=$( git log --grep 'Merge pull request' --oneline --single-worktree --first-parent | head -1 | grep --color=none -Eo '#[0-9]+' | tr -d '#' )
sed -i "s/Version:.*/Version: ${BUILD_ID}/" jellyfin-web.spec
sed -i "/%changelog/q" jellyfin-web.spec
cat <<EOF >>jellyfin-web.spec
* $( LANG=C date '+%a %b %d %Y' ) Jellyfin Packaging Team <packaging@jellyfin.org>
- Jellyfin Web unstable build ${BUILD_ID} for merged PR #${PR_ID}
EOF
popd
fi
# build rpm
make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS
rpmbuild --rebuild -bb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm
# move the artifacts
mv /root/rpmbuild/RPMS/noarch/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
rm -f fedora/jellyfin*.tar.gz
cp -a /tmp/yarn.lock yarn.lock
popd

View file

@ -1,27 +0,0 @@
#!/bin/bash
#= CentOS 7 all .rpm
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# Build RPM
make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS
rpmbuild --rebuild -bb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm
# Move the artifacts out
mv /root/rpmbuild/RPMS/noarch/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
rm -f fedora/jellyfin*.tar.gz
cp -a /tmp/yarn.lock yarn.lock
popd

39
deployment/build.debian Executable file
View file

@ -0,0 +1,39 @@
#!/bin/bash
set -o errexit
set -o xtrace
# move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# modify changelog to unstable configuration if IS_UNSTABLE
if [[ ${IS_UNSTABLE} == 'yes' ]]; then
pushd debian
PR_ID=$( git log --grep 'Merge pull request' --oneline --single-worktree --first-parent | head -1 | grep --color=none -Eo '#[0-9]+' | tr -d '#' )
cat <<EOF >changelog
jellyfin-web (${BUILD_ID}-unstable) unstable; urgency=medium
* Jellyfin Web unstable build ${BUILD_ID} for merged PR #${PR_ID}
-- Jellyfin Packaging Team <packaging@jellyfin.org> $( date --rfc-2822 )
EOF
popd
fi
# build deb
dpkg-buildpackage -us -uc --pre-clean --post-clean
mkdir -p ${ARTIFACT_DIR}
mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}
cp -a /tmp/yarn.lock yarn.lock
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
popd

View file

@ -1,25 +0,0 @@
#!/bin/bash
#= Debian/Ubuntu all .deb
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# Build DEB
dpkg-buildpackage -us -uc --pre-clean --post-clean
mkdir -p ${ARTIFACT_DIR}/
mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/
cp -a /tmp/yarn.lock yarn.lock
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
popd

41
deployment/build.fedora Executable file
View file

@ -0,0 +1,41 @@
#!/bin/bash
set -o errexit
set -o xtrace
# move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# modify changelog to unstable configuration if IS_UNSTABLE
if [[ ${IS_UNSTABLE} == 'yes' ]]; then
pushd fedora
PR_ID=$( git log --grep 'Merge pull request' --oneline --single-worktree --first-parent | head -1 | grep --color=none -Eo '#[0-9]+' | tr -d '#' )
sed -i "s/Version:.*/Version: ${BUILD_ID}/" jellyfin-web.spec
sed -i "/%changelog/q" jellyfin-web.spec
cat <<EOF >>jellyfin-web.spec
* $( LANG=C date '+%a %b %d %Y' ) Jellyfin Packaging Team <packaging@jellyfin.org>
- Jellyfin Web unstable build ${BUILD_ID} for merged PR #${PR_ID}
EOF
popd
fi
# build rpm
make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS
rpmbuild -rb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm
# move the artifacts
mv /root/rpmbuild/RPMS/noarch/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
rm -f fedora/jellyfin*.tar.gz
cp -a /tmp/yarn.lock yarn.lock
popd

View file

@ -1,27 +0,0 @@
#!/bin/bash
#= Fedora 29+ all .rpm
set -o errexit
set -o xtrace
# Move to source directory
pushd ${SOURCE_DIR}
cp -a yarn.lock /tmp/yarn.lock
# Build RPM
make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS
rpmbuild -rb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm
# Move the artifacts out
mv /root/rpmbuild/RPMS/noarch/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/
if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}
fi
rm -f fedora/jellyfin*.tar.gz
cp -a /tmp/yarn.lock yarn.lock
popd

View file

@ -1,25 +1,27 @@
#!/bin/bash #!/bin/bash
#= Portable .NET DLL .tar.gz
set -o errexit set -o errexit
set -o xtrace set -o xtrace
# Move to source directory # move to source directory
pushd ${SOURCE_DIR} pushd ${SOURCE_DIR}
# Get version # get version
version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )" if [[ ${IS_UNSTABLE} == 'yes' ]]; then
version="${BUILD_ID}"
else
version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )"
fi
# Build archives # build archives
npx yarn install npx yarn install
mv dist/ jellyfin-web_${version} mv dist jellyfin-web_${version}
tar -czf jellyfin-web_${version}_portable.tar.gz jellyfin-web_${version} tar -czf jellyfin-web_${version}_portable.tar.gz jellyfin-web_${version}
rm -rf dist/ rm -rf dist
# Move the artifacts out # move the artifacts
mkdir -p ${ARTIFACT_DIR}/ mkdir -p ${ARTIFACT_DIR}
mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}
if [[ ${IS_DOCKER} == YES ]]; then if [[ ${IS_DOCKER} == YES ]]; then
chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR}

View file

@ -1,7 +1,7 @@
%global debug_package %{nil} %global debug_package %{nil}
Name: jellyfin-web Name: jellyfin-web
Version: 10.6.0 Version: 10.7.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: The Free Software Media System web client Summary: The Free Software Media System web client
License: GPLv3 License: GPLv3
@ -12,7 +12,7 @@ Source0: jellyfin-web-%{version}.tar.gz
%if 0%{?centos} %if 0%{?centos}
BuildRequires: yarn BuildRequires: yarn
%else %else
BuildRequires nodejs-yarn BuildRequires: nodejs-yarn
%endif %endif
BuildArch: noarch BuildArch: noarch
@ -39,5 +39,7 @@ mv dist %{buildroot}%{_datadir}/jellyfin-web
%{_datadir}/licenses/jellyfin/LICENSE %{_datadir}/licenses/jellyfin/LICENSE
%changelog %changelog
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org> * Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
- Forthcoming stable release - Forthcoming stable release

View file

@ -45,7 +45,7 @@ const options = {
query: ['src/**/*.png', 'src/**/*.jpg', 'src/**/*.gif', 'src/**/*.svg'] query: ['src/**/*.png', 'src/**/*.jpg', 'src/**/*.gif', 'src/**/*.svg']
}, },
copy: { copy: {
query: ['src/**/*.json', 'src/**/*.ico'] query: ['src/**/*.json', 'src/**/*.ico', 'src/**/*.mp3']
}, },
injectBundle: { injectBundle: {
query: 'src/index.html' query: 'src/index.html'
@ -181,16 +181,15 @@ function copy(query) {
.pipe(browserSync.stream()); .pipe(browserSync.stream());
} }
function copyIndex() {
return src(options.injectBundle.query, { base: './src/' })
.pipe(dest('dist/'))
.pipe(browserSync.stream());
}
function injectBundle() { function injectBundle() {
return src(options.injectBundle.query, { base: './src/' }) return src(options.injectBundle.query, { base: './src/' })
.pipe(inject( .pipe(inject(
src(['src/scripts/apploader.js'], { read: false }, { base: './src/' }), { relative: true } src(['src/scripts/apploader.js'], { read: false }, { base: './src/' }), {
relative: true,
transform: function (filepath) {
return `<script src="${filepath}" defer></script>`;
}
}
)) ))
.pipe(dest('dist/')) .pipe(dest('dist/'))
.pipe(browserSync.stream()); .pipe(browserSync.stream());
@ -200,6 +199,6 @@ function build(standalone) {
return series(clean, parallel(javascript, apploader(standalone), webpack, css, html, images, copy)); return series(clean, parallel(javascript, apploader(standalone), webpack, css, html, images, copy));
} }
exports.default = series(build(false), copyIndex); exports.default = series(build(false), injectBundle);
exports.standalone = series(build(true), injectBundle); exports.standalone = series(build(true), injectBundle);
exports.serve = series(exports.standalone, serve); exports.serve = series(exports.standalone, serve);

View file

@ -5,27 +5,30 @@
"repository": "https://github.com/jellyfin/jellyfin-web", "repository": "https://github.com/jellyfin/jellyfin-web",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.9.6", "@babel/core": "^7.11.0",
"@babel/plugin-transform-modules-amd": "^7.9.6", "@babel/eslint-parser": "^7.11.0",
"@babel/eslint-plugin": "^7.11.0",
"@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/plugin-proposal-private-methods": "^7.10.1",
"@babel/plugin-transform-modules-amd": "^7.10.5",
"@babel/polyfill": "^7.8.7", "@babel/polyfill": "^7.8.7",
"@babel/preset-env": "^7.8.6", "@babel/preset-env": "^7.11.0",
"autoprefixer": "^9.7.6", "autoprefixer": "^9.8.6",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"browser-sync": "^2.26.7", "browser-sync": "^2.26.12",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^5.1.1", "copy-webpack-plugin": "^5.1.1",
"css-loader": "^3.4.2", "css-loader": "^4.2.0",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
"del": "^5.1.0", "del": "^5.1.0",
"eslint": "^6.8.0", "eslint": "^7.6.0",
"eslint-plugin-compat": "^3.5.1", "eslint-plugin-compat": "^3.5.1",
"eslint-plugin-eslint-comments": "^3.1.2", "eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.20.2", "eslint-plugin-import": "^2.21.2",
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^4.2.1",
"file-loader": "^6.0.0", "file-loader": "^6.0.0",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"gulp-babel": "^8.0.0", "gulp-babel": "^8.0.0",
"gulp-cli": "^2.2.0", "gulp-cli": "^2.3.0",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-htmlmin": "^5.0.1", "gulp-htmlmin": "^5.0.1",
"gulp-if": "^3.0.0", "gulp-if": "^3.0.0",
@ -35,52 +38,49 @@
"gulp-postcss": "^8.0.0", "gulp-postcss": "^8.0.0",
"gulp-sass": "^4.0.2", "gulp-sass": "^4.0.2",
"gulp-sourcemaps": "^2.6.5", "gulp-sourcemaps": "^2.6.5",
"gulp-terser": "^1.2.0", "gulp-terser": "^1.3.0",
"html-webpack-plugin": "^4.3.0", "html-webpack-plugin": "^4.3.0",
"lazypipe": "^1.0.2", "lazypipe": "^1.0.2",
"node-sass": "^4.13.1", "node-sass": "^4.13.1",
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0", "postcss-preset-env": "^6.7.0",
"style-loader": "^1.1.3", "style-loader": "^1.1.3",
"stylelint": "^13.3.3", "stylelint": "^13.6.1",
"stylelint-config-rational-order": "^0.1.2", "stylelint-config-rational-order": "^0.1.2",
"stylelint-no-browser-hacks": "^1.2.1", "stylelint-no-browser-hacks": "^1.2.1",
"stylelint-order": "^4.0.0", "stylelint-order": "^4.1.0",
"webpack": "^4.41.5", "webpack": "^4.44.1",
"webpack-cli": "^3.3.10",
"webpack-concat-plugin": "^3.0.0",
"webpack-dev-server": "^3.10.3",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"webpack-stream": "^5.2.1" "webpack-stream": "^5.2.1"
}, },
"dependencies": { "dependencies": {
"alameda": "^1.4.0", "alameda": "^1.4.0",
"blurhash": "^1.1.3",
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz", "classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"date-fns": "^2.12.0", "date-fns": "^2.15.0",
"document-register-element": "^1.14.3", "epubjs": "^0.3.85",
"fast-text-encoding": "^1.0.1", "fast-text-encoding": "^1.0.3",
"flv.js": "^1.5.0", "flv.js": "^1.5.0",
"headroom.js": "^0.11.0", "headroom.js": "^0.11.0",
"hls.js": "^0.13.1", "hls.js": "^0.14.7",
"howler": "^2.1.3", "howler": "^2.2.0",
"intersection-observer": "^0.10.0", "intersection-observer": "^0.11.0",
"jellyfin-apiclient": "^1.1.1", "jellyfin-apiclient": "^1.4.1",
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto", "jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
"jquery": "^3.5.0", "jquery": "^3.5.1",
"jstree": "^3.3.7", "jstree": "^3.3.10",
"libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-smarttv", "libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-smarttv",
"material-design-icons-iconfont": "^5.0.1", "material-design-icons-iconfont": "^5.0.1",
"native-promise-only": "^0.8.0-a", "native-promise-only": "^0.8.0-a",
"page": "^1.11.6", "page": "^1.11.6",
"query-string": "^6.11.1", "query-string": "^6.13.1",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"screenfull": "^5.0.2", "screenfull": "^5.0.2",
"shaka-player": "^2.5.10",
"sortablejs": "^1.10.2", "sortablejs": "^1.10.2",
"swiper": "^5.3.7", "swiper": "^5.4.5",
"webcomponents.js": "^0.7.24", "webcomponents.js": "^0.7.24",
"whatwg-fetch": "^3.0.0" "whatwg-fetch": "^3.2.0"
}, },
"babel": { "babel": {
"presets": [ "presets": [
@ -89,26 +89,214 @@
"overrides": [ "overrides": [
{ {
"test": [ "test": [
"src/components/accessSchedule/accessSchedule.js",
"src/components/actionSheet/actionSheet.js",
"src/components/activitylog.js",
"src/components/alert.js",
"src/components/alphaPicker/alphaPicker.js",
"src/components/appFooter/appFooter.js",
"src/components/autoFocuser.js", "src/components/autoFocuser.js",
"src/components/backdrop/backdrop.js",
"src/components/cardbuilder/cardBuilder.js", "src/components/cardbuilder/cardBuilder.js",
"src/components/filedownloader.js", "src/components/cardbuilder/chaptercardbuilder.js",
"src/components/cardbuilder/peoplecardbuilder.js",
"src/components/channelMapper/channelMapper.js",
"src/components/collectionEditor/collectionEditor.js",
"src/components/confirm/confirm.js",
"src/components/dialog/dialog.js",
"src/components/dialogHelper/dialogHelper.js",
"src/components/directorybrowser/directorybrowser.js",
"src/components/displaySettings/displaySettings.js",
"src/components/favoriteitems.js",
"src/components/fetchhelper.js",
"src/components/filterdialog/filterdialog.js",
"src/components/groupedcards.js",
"src/components/homeScreenSettings/homeScreenSettings.js",
"src/components/homesections/homesections.js",
"src/components/htmlMediaHelper.js",
"src/components/imageOptionsEditor/imageOptionsEditor.js",
"src/components/images/imageLoader.js", "src/components/images/imageLoader.js",
"src/components/lazyloader/lazyloader-intersectionobserver.js", "src/components/imageDownloader/imageDownloader.js",
"src/components/imageeditor/imageeditor.js",
"src/components/imageUploader/imageUploader.js",
"src/components/indicators/indicators.js",
"src/components/itemContextMenu.js",
"src/components/itemHelper.js",
"src/components/itemidentifier/itemidentifier.js",
"src/components/itemMediaInfo/itemMediaInfo.js",
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
"src/components/libraryoptionseditor/libraryoptionseditor.js",
"src/components/listview/listview.js",
"src/components/loading/loading.js",
"src/components/maintabsmanager.js",
"src/components/mediainfo/mediainfo.js",
"src/components/mediaLibraryCreator/mediaLibraryCreator.js",
"src/components/mediaLibraryEditor/mediaLibraryEditor.js",
"src/components/metadataEditor/metadataEditor.js",
"src/components/metadataEditor/personEditor.js",
"src/components/multiSelect/multiSelect.js",
"src/components/nowPlayingBar/nowPlayingBar.js",
"src/components/playback/brightnessosd.js",
"src/components/playback/mediasession.js", "src/components/playback/mediasession.js",
"src/components/playback/nowplayinghelper.js",
"src/components/playback/playbackorientation.js",
"src/components/playback/playbackmanager.js",
"src/components/playback/playerSelectionMenu.js",
"src/components/playback/playersettingsmenu.js",
"src/components/playback/playmethodhelper.js",
"src/components/playback/playqueuemanager.js",
"src/components/playback/remotecontrolautoplay.js",
"src/components/playback/volumeosd.js",
"src/components/playbackSettings/playbackSettings.js",
"src/components/playerstats/playerstats.js",
"src/components/playlisteditor/playlisteditor.js",
"src/components/playmenu.js",
"src/components/prompt/prompt.js",
"src/components/refreshdialog/refreshdialog.js",
"src/components/sanatizefilename.js", "src/components/sanatizefilename.js",
"src/components/scrollManager.js", "src/components/scrollManager.js",
"src/plugins/htmlVideoPlayer/plugin.js",
"src/components/search/searchfields.js",
"src/components/search/searchresults.js",
"src/components/settingshelper.js",
"src/components/shortcuts.js",
"src/components/subtitlesettings/subtitleappearancehelper.js",
"src/components/subtitlesettings/subtitlesettings.js",
"src/components/syncPlay/groupSelectionMenu.js",
"src/components/syncPlay/playbackPermissionManager.js",
"src/components/syncPlay/syncPlayManager.js",
"src/components/syncPlay/timeSyncManager.js",
"src/components/toast/toast.js",
"src/components/upnextdialog/upnextdialog.js",
"src/components/viewContainer.js",
"src/controllers/session/addServer/index.js",
"src/controllers/session/forgotPassword/index.js",
"src/controllers/session/redeemPassword/index.js",
"src/controllers/session/login/index.js",
"src/controllers/session/selectServer/index.js",
"src/controllers/dashboard/apikeys.js",
"src/controllers/dashboard/dashboard.js",
"src/controllers/dashboard/devices/device.js",
"src/controllers/dashboard/devices/devices.js",
"src/controllers/dashboard/dlna/profile.js",
"src/controllers/dashboard/dlna/profiles.js",
"src/controllers/dashboard/dlna/settings.js",
"src/controllers/dashboard/encodingsettings.js",
"src/controllers/dashboard/general.js",
"src/controllers/dashboard/librarydisplay.js",
"src/controllers/dashboard/logs.js",
"src/controllers/music/musicalbums.js",
"src/controllers/music/musicartists.js",
"src/controllers/music/musicgenres.js",
"src/controllers/music/musicplaylists.js",
"src/controllers/music/musicrecommended.js",
"src/controllers/music/songs.js",
"src/controllers/dashboard/mediaLibrary.js",
"src/controllers/dashboard/metadataImages.js",
"src/controllers/dashboard/metadatanfo.js",
"src/controllers/dashboard/networking.js",
"src/controllers/dashboard/notifications/notification.js",
"src/controllers/dashboard/notifications/notifications.js",
"src/controllers/dashboard/playback.js",
"src/controllers/dashboard/plugins/repositories/index.js",
"src/controllers/dashboard/scheduledtasks/scheduledtask.js",
"src/controllers/dashboard/scheduledtasks/scheduledtasks.js",
"src/controllers/dashboard/serveractivity.js",
"src/controllers/dashboard/streaming.js",
"src/controllers/dashboard/users/useredit.js",
"src/controllers/dashboard/users/userlibraryaccess.js",
"src/controllers/dashboard/users/usernew.js",
"src/controllers/dashboard/users/userparentalcontrol.js",
"src/controllers/dashboard/users/userpasswordpage.js",
"src/controllers/dashboard/users/userprofilespage.js",
"src/controllers/edititemmetadata.js",
"src/controllers/favorites.js",
"src/controllers/hometab.js",
"src/controllers/playback/nowplaying.js",
"src/controllers/playback/videoosd.js",
"src/controllers/itemDetails/index.js",
"src/controllers/playback/queue/index.js",
"src/controllers/playback/video/index.js",
"src/controllers/searchpage.js",
"src/controllers/livetvtuner.js",
"src/controllers/livetvstatus.js",
"src/controllers/livetvguideprovider.js",
"src/controllers/livetvsettings.js",
"src/controllers/shows/episodes.js",
"src/controllers/shows/tvgenres.js",
"src/controllers/shows/tvlatest.js",
"src/controllers/shows/tvrecommended.js",
"src/controllers/shows/tvshows.js",
"src/controllers/shows/tvstudios.js",
"src/controllers/shows/tvupcoming.js",
"src/controllers/user/display/index.js",
"src/controllers/user/home/index.js",
"src/controllers/user/menu/index.js",
"src/controllers/user/playback/index.js",
"src/controllers/user/profile/index.js",
"src/controllers/user/subtitles/index.js",
"src/controllers/wizard/finish/index.js",
"src/controllers/wizard/remote/index.js",
"src/controllers/wizard/settings/index.js",
"src/controllers/wizard/start/index.js",
"src/controllers/wizard/user/index.js",
"src/elements/emby-button/emby-button.js",
"src/elements/emby-button/paper-icon-button-light.js",
"src/elements/emby-checkbox/emby-checkbox.js",
"src/elements/emby-collapse/emby-collapse.js",
"src/elements/emby-input/emby-input.js",
"src/elements/emby-itemrefreshindicator/emby-itemrefreshindicator.js",
"src/elements/emby-itemscontainer/emby-itemscontainer.js",
"src/elements/emby-playstatebutton/emby-playstatebutton.js",
"src/elements/emby-programcell/emby-programcell.js",
"src/elements/emby-progressbar/emby-progressbar.js",
"src/elements/emby-progressring/emby-progressring.js",
"src/elements/emby-radio/emby-radio.js",
"src/elements/emby-ratingbutton/emby-ratingbutton.js",
"src/elements/emby-scrollbuttons/emby-scrollbuttons.js",
"src/elements/emby-scroller/emby-scroller.js",
"src/elements/emby-select/emby-select.js",
"src/elements/emby-slider/emby-slider.js",
"src/elements/emby-tabs/emby-tabs.js",
"src/elements/emby-textarea/emby-textarea.js",
"src/elements/emby-toggle/emby-toggle.js",
"src/plugins/backdropScreensaver/plugin.js",
"src/plugins/bookPlayer/plugin.js",
"src/plugins/bookPlayer/tableOfContents.js",
"src/plugins/photoPlayer/plugin.js",
"src/plugins/youtubePlayer/plugin.js",
"src/scripts/alphanumericshortcuts.js",
"src/scripts/autoBackdrops.js",
"src/scripts/browser.js",
"src/scripts/datetime.js",
"src/scripts/deleteHelper.js",
"src/scripts/dfnshelper.js", "src/scripts/dfnshelper.js",
"src/scripts/dom.js", "src/scripts/dom.js",
"src/scripts/editorsidebar.js",
"src/scripts/fileDownloader.js",
"src/scripts/filesystem.js", "src/scripts/filesystem.js",
"src/scripts/globalize.js",
"src/scripts/imagehelper.js", "src/scripts/imagehelper.js",
"src/scripts/inputManager.js", "src/scripts/inputManager.js",
"src/scripts/keyboardnavigation.js", "src/scripts/autoThemes.js",
"src/scripts/themeManager.js",
"src/scripts/keyboardNavigation.js",
"src/scripts/libraryBrowser.js",
"src/scripts/mouseManager.js",
"src/scripts/multiDownload.js",
"src/scripts/playlists.js",
"src/scripts/routes.js",
"src/scripts/settings/appSettings.js", "src/scripts/settings/appSettings.js",
"src/scripts/settings/userSettings.js", "src/scripts/settings/userSettings.js",
"src/scripts/settings/webSettings.js" "src/scripts/settings/webSettings.js",
"src/scripts/taskbutton.js",
"src/scripts/themeLoader.js",
"src/scripts/touchHelper.js"
], ],
"plugins": [ "plugins": [
"@babel/plugin-transform-modules-amd" "@babel/plugin-transform-modules-amd",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-private-methods"
] ]
} }
] ]
@ -118,7 +306,7 @@
"last 2 Chrome versions", "last 2 Chrome versions",
"last 2 ChromeAndroid versions", "last 2 ChromeAndroid versions",
"last 2 Safari versions", "last 2 Safari versions",
"last 2 iOS versions", "iOS > 10",
"last 2 Edge versions", "last 2 Edge versions",
"Chrome 27", "Chrome 27",
"Chrome 38", "Chrome 38",
@ -126,6 +314,7 @@
"Chrome 53", "Chrome 53",
"Chrome 56", "Chrome 56",
"Chrome 63", "Chrome 63",
"Edge 18",
"Firefox ESR" "Firefox ESR"
], ],
"scripts": { "scripts": {

View file

@ -5,8 +5,10 @@ const cssnano = require('cssnano');
const config = () => ({ const config = () => ({
plugins: [ plugins: [
// Explicitly specify browserslist to override ones from node_modules
// For example, Swiper has it in its package.json
postcssPresetEnv({browsers: packageConfig.browserslist}), postcssPresetEnv({browsers: packageConfig.browserslist}),
autoprefixer(), autoprefixer({overrideBrowserslist: packageConfig.browserslist}),
cssnano() cssnano()
] ]
}); });

View file

@ -15,6 +15,8 @@ print(langlst)
input('press enter to continue') input('press enter to continue')
keysus = [] keysus = []
missing = []
with open(langdir + '/' + 'en-us.json') as en: with open(langdir + '/' + 'en-us.json') as en:
langus = json.load(en) langus = json.load(en)
for key in langus: for key in langus:
@ -32,10 +34,19 @@ for lang in langlst:
for key in langjson: for key in langjson:
if key in keysus: if key in keysus:
langjnew[key] = langjson[key] langjnew[key] = langjson[key]
elif key not in missing:
missing.append(key)
f.seek(0) f.seek(0)
f.write(json.dumps(langjnew, indent=inde, sort_keys=False, ensure_ascii=False)) f.write(json.dumps(langjnew, indent=inde, sort_keys=False, ensure_ascii=False))
f.write('\n') f.write('\n')
f.truncate() f.truncate()
f.close() f.close()
print(missing)
print('LENGTH: ' + str(len(missing)))
with open('missing.txt', 'w') as out:
for item in missing:
out.write(item + '\n')
out.close()
print('DONE') print('DONE')

View file

@ -34,7 +34,7 @@ for lang in langlst:
print(dep) print(dep)
print('LENGTH: ' + str(len(dep))) print('LENGTH: ' + str(len(dep)))
with open('scout.txt', 'w') as out: with open('unused.txt', 'w') as out:
for item in dep: for item in dep:
out.write(item + '\n') out.write(item + '\n')
out.close() out.close()

View file

@ -4,18 +4,19 @@
<div class="detailSectionHeader"> <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}"> <button is="emby-button" type="button" class="fab btnNewKey submit" style="margin-left:1em;" title="${ButtonAdd}">
<span class="material-icons add"></span> <span class="material-icons add" aria-hidden="true"></span>
</button> </button>
</div> </div>
<p>${HeaderApiKeysHelp}</p> <p>${HeaderApiKeysHelp}</p>
<br /> <br />
<table class="tblApiKeys detailTable"> <table class="tblApiKeys detailTable">
<caption class="clipForScreenReader">${ApiKeysCaption}</caption>
<thead> <thead>
<tr> <tr>
<th class="detailTableHeaderCell"></th> <th scope="col" class="detailTableHeaderCell"></th>
<th class="detailTableHeaderCell">${HeaderApiKey}</th> <th scope="col" class="detailTableHeaderCell">${HeaderApiKey}</th>
<th class="detailTableHeaderCell">${HeaderApp}</th> <th scope="col" class="detailTableHeaderCell">${HeaderApp}</th>
<th class="detailTableHeaderCell">${HeaderDateIssued}</th> <th scope="col" class="detailTableHeaderCell">${HeaderDateIssued}</th>
</tr> </tr>
</thead> </thead>
<tbody class="resultBody"></tbody> <tbody class="resultBody"></tbody>

Binary file not shown.

View file

@ -235,6 +235,15 @@ div[data-role=controlgroup] a.ui-btn-active {
width: 50%; width: 50%;
} }
.localUsers .cardText-secondary {
white-space: pre-wrap;
height: 3em;
}
.customCssContainer textarea {
resize: none;
}
@media all and (min-width: 70em) { @media all and (min-width: 70em) {
.dashboardSections { .dashboardSections {
-webkit-flex-wrap: wrap; -webkit-flex-wrap: wrap;

View file

@ -30,6 +30,10 @@
align-items: flex-start; align-items: flex-start;
} }
.align-items-flex-end {
align-items: flex-end;
}
.justify-content-center { .justify-content-center {
justify-content: center; justify-content: center;
} }
@ -38,6 +42,10 @@
justify-content: flex-end; justify-content: flex-end;
} }
.justify-content-space-between {
justify-content: space-between;
}
.flex-wrap-wrap { .flex-wrap-wrap {
flex-wrap: wrap; flex-wrap: wrap;
} }

View file

@ -1,8 +1,3 @@
html { html {
font-size: 82% !important; font-size: 82% !important;
} }
.formDialogFooter {
position: static !important;
margin: 0 -1em !important;
}

View file

@ -24,10 +24,6 @@
padding-top: 7em !important; padding-top: 7em !important;
} }
.layout-mobile .libraryPage {
padding-top: 4em !important;
}
.itemDetailPage { .itemDetailPage {
padding-top: 0 !important; padding-top: 0 !important;
} }
@ -164,6 +160,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
contain: layout style paint; contain: layout style paint;
transition: background ease-in-out 0.5s;
} }
.hiddenViewMenuBar .skinHeader { .hiddenViewMenuBar .skinHeader {
@ -178,6 +175,10 @@
width: 100%; width: 100%;
} }
.layout-tv .sectionTabs {
width: 55%;
}
.selectedMediaFolder { .selectedMediaFolder {
background-color: #f2f2f2 !important; background-color: #f2f2f2 !important;
} }
@ -272,7 +273,7 @@
} }
} }
@media all and (max-width: 84em) { @media all and (max-width: 100em) {
.withSectionTabs .headerTop { .withSectionTabs .headerTop {
padding-bottom: 0.55em; padding-bottom: 0.55em;
} }
@ -280,9 +281,13 @@
.sectionTabs { .sectionTabs {
font-size: 83.5%; font-size: 83.5%;
} }
.layout-tv .sectionTabs {
width: 100%;
}
} }
@media all and (min-width: 84em) { @media all and (min-width: 100em) {
.headerTop { .headerTop {
padding: 0.8em 0.8em; padding: 0.8em 0.8em;
} }
@ -438,12 +443,14 @@
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-attachment: fixed; background-attachment: fixed;
height: 50vh; height: 40vh;
position: relative; position: relative;
animation: backdrop-fadein 800ms ease-in normal both;
} }
.layout-mobile .itemBackdrop { .layout-mobile .itemBackdrop {
background-attachment: scroll; background-attachment: scroll;
height: 26.5vh;
} }
.layout-desktop .itemBackdrop::after, .layout-desktop .itemBackdrop::after,
@ -463,10 +470,20 @@
.detailPageContent { .detailPageContent {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding-left: 2%; padding-left: 32.45vw;
padding-right: 2%; padding-right: 2%;
} }
.layout-mobile .detailPageContent {
padding-left: 5%;
padding-right: 5%;
}
.layout-desktop .detailPageContent .emby-scroller,
.layout-tv .detailPageContent .emby-scroller {
margin-left: 0;
}
.layout-desktop .noBackdrop .detailPageContent, .layout-desktop .noBackdrop .detailPageContent,
.layout-tv .noBackdrop .detailPageContent { .layout-tv .noBackdrop .detailPageContent {
margin-top: 2.5em; margin-top: 2.5em;
@ -477,6 +494,10 @@
margin-top: 0; margin-top: 0;
} }
.detailSectionContent a {
color: inherit;
}
.personBackdrop { .personBackdrop {
background-size: contain; background-size: contain;
} }
@ -495,7 +516,23 @@
.parentName { .parentName {
display: block; display: block;
margin-bottom: 0.5em; margin: 0 0 0;
}
.layout-mobile .parentName {
margin: 0.6em 0 0;
}
.musicParentName {
margin: 0.15em 0 0.2em;
}
.layout-mobile .musicParentName {
margin: -0.25em 0 0.25em;
}
.layout-mobile .itemExternalLinks {
display: none;
} }
.mainDetailButtons { .mainDetailButtons {
@ -503,8 +540,6 @@
-webkit-box-align: center; -webkit-box-align: center;
-webkit-align-items: center; -webkit-align-items: center;
align-items: center; align-items: center;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
margin: 1em 0; margin: 1em 0;
} }
@ -520,6 +555,35 @@
font-weight: 600; font-weight: 600;
} }
.itemName.originalTitle {
margin: 0.2em 0 0.2em;
}
.itemName.parentNameLast {
margin: 0 0 0;
}
.layout-mobile .itemName.parentNameLast {
margin: 0.4em 0 0.4em;
}
.layout-mobile h1.itemName,
.layout-mobile h1.parentName {
font-size: 1.6em;
}
.itemName.parentNameLast.withOriginalTitle {
margin: 0 0 0;
}
.layout-mobile .itemName.parentNameLast.withOriginalTitle {
margin: 0.6em 0 0;
}
.layout-mobile .itemName.originalTitle {
margin: 0.5em 0 0.5em;
}
.nameContainer { .nameContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -546,6 +610,19 @@
text-align: center; text-align: center;
} }
.layout-mobile .mainDetailButtons {
margin-top: 1em;
margin-bottom: 0.5em;
}
.subtitle {
margin: 0.15em 0 0.2em;
}
.layout-mobile .subtitle {
margin: 0.2em 0 0.2em;
}
.detailPagePrimaryContainer { .detailPagePrimaryContainer {
display: flex; display: flex;
align-items: center; align-items: center;
@ -556,7 +633,7 @@
.layout-mobile .detailPagePrimaryContainer { .layout-mobile .detailPagePrimaryContainer {
display: block; display: block;
position: relative; position: relative;
top: 0; padding: 0.5em 3.3% 0.5em;
} }
.layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer, .layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer,
@ -566,13 +643,14 @@
padding-left: 32.45vw; padding-left: 32.45vw;
} }
.layout-desktop .detailSticky, .layout-desktop .detailRibbon,
.layout-tv .detailSticky { .layout-tv .detailRibbon {
margin-top: -7.2em; margin-top: -7.2em;
height: 7.2em;
} }
.layout-desktop .noBackdrop .detailSticky, .layout-desktop .noBackdrop .detailRibbon,
.layout-tv .noBackdrop .detailSticky { .layout-tv .noBackdrop .detailRibbon {
margin-top: 0; margin-top: 0;
} }
@ -584,6 +662,9 @@
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
text-align: left; text-align: left;
min-width: 0;
max-width: 100%;
overflow: hidden;
} }
.layout-mobile .infoText { .layout-mobile .infoText {
@ -594,12 +675,29 @@
margin: 1.25em 0; margin: 1.25em 0;
} }
.detailImageContainer { .layout-mobile .detailPageSecondaryContainer {
position: relative; margin: 1em 0;
margin-top: -25vh; }
.layout-mobile .detailImageContainer {
display: none;
}
.detailImageContainer .card {
position: absolute;
top: 50%;
float: left; float: left;
width: 25vw; width: 25vw;
z-index: 3; z-index: 3;
transform: translateY(-50%);
}
.detailImageContainer .card.backdropCard {
top: 35%;
}
.detailImageContainer .card.squareCard {
top: 40%;
} }
.layout-desktop .noBackdrop .detailImageContainer, .layout-desktop .noBackdrop .detailImageContainer,
@ -612,11 +710,11 @@
} }
.detailLogo { .detailLogo {
width: 30vw; width: 25vw;
height: 25vh; height: 16vh;
position: absolute; position: absolute;
top: 10vh; top: 10vh;
right: 20vw; right: 25vw;
background-size: contain; background-size: contain;
} }
@ -641,7 +739,8 @@ div.itemDetailGalleryLink.defaultCardBackground {
} }
.itemDetailGalleryLink.defaultCardBackground { .itemDetailGalleryLink.defaultCardBackground {
height: 23vw; /* Dirty hack to get it to look somewhat square. Less than ideal. */ /* Dirty hack to get it to look somewhat square. Less than ideal. */
height: 23vw;
} }
.itemDetailGalleryLink.defaultCardBackground > .material-icons { .itemDetailGalleryLink.defaultCardBackground > .material-icons {
@ -655,14 +754,19 @@ div.itemDetailGalleryLink.defaultCardBackground {
position: relative; position: relative;
} }
.layout-desktop .detailPageWrapperContainer, .layout-desktop .itemBackdrop,
.layout-tv .detailPageWrapperContainer { .layout-tv .itemBackdrop {
margin-top: 7.2em; height: 40vh;
} }
.layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer, .layout-desktop .detailPageWrapperContainer,
.layout-desktop #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer { .layout-tv .detailPageWrapperContainer {
padding-left: 3.3%; margin-top: 0.1em;
}
.layout-desktop .detailImageContainer .card,
.layout-tv .detailImageContainer .card {
top: 10%;
} }
.btnPlaySimple { .btnPlaySimple {
@ -678,12 +782,12 @@ div.itemDetailGalleryLink.defaultCardBackground {
.emby-button.detailFloatingButton { .emby-button.detailFloatingButton {
position: absolute; position: absolute;
background-color: rgba(0, 0, 0, 0.5) !important; background-color: rgba(0, 0, 0, 0.5);
z-index: 1; z-index: 3;
top: 50%; top: 100%;
left: 50%; left: 90%;
margin: -2.2em 0 0 -2.2em; margin: -2.2em 0 0 -2.2em;
padding: 0.4em !important; padding: 0.4em;
color: rgba(255, 255, 255, 0.76); color: rgba(255, 255, 255, 0.76);
} }
@ -693,16 +797,12 @@ div.itemDetailGalleryLink.defaultCardBackground {
@media all and (max-width: 62.5em) { @media all and (max-width: 62.5em) {
.parentName { .parentName {
margin-bottom: 1em; margin-bottom: 0;
} }
.itemDetailPage { .itemDetailPage {
padding-top: 0 !important; padding-top: 0 !important;
} }
.detailimg-hidemobile {
display: none;
}
} }
@media all and (min-width: 31.25em) { @media all and (min-width: 31.25em) {
@ -797,9 +897,9 @@ div.itemDetailGalleryLink.defaultCardBackground {
} }
.detailImageProgressContainer { .detailImageProgressContainer {
position: absolute;
bottom: 0; bottom: 0;
width: 22.786458333333332vw; margin-top: -0.4vw;
width: 100%;
} }
.detailButton-text { .detailButton-text {
@ -818,21 +918,7 @@ div.itemDetailGalleryLink.defaultCardBackground {
} }
} }
@media all and (min-width: 62.5em) { @media all and (min-width: 100em) {
.headerTop {
padding-left: 0.8em;
padding-right: 0.8em;
}
.headerTabs {
align-self: center;
width: auto;
align-items: center;
justify-content: center;
margin-top: -4.2em;
position: relative;
}
.detailFloatingButton { .detailFloatingButton {
display: none !important; display: none !important;
} }
@ -866,6 +952,10 @@ div.itemDetailGalleryLink.defaultCardBackground {
} }
} }
.detailVerticalSection .emby-scrollbuttons {
padding-top: 0.4em;
}
.layout-tv .detailVerticalSection { .layout-tv .detailVerticalSection {
margin-bottom: 3.4em !important; margin-bottom: 3.4em !important;
} }
@ -954,6 +1044,10 @@ div.itemDetailGalleryLink.defaultCardBackground {
margin-bottom: 2.7em; margin-bottom: 2.7em;
} }
.layout-mobile .verticalSection-extrabottompadding {
margin-bottom: 1em;
}
.sectionTitleButton, .sectionTitleButton,
.sectionTitleIconButton { .sectionTitleIconButton {
margin-right: 0 !important; margin-right: 0 !important;
@ -979,7 +1073,13 @@ div.itemDetailGalleryLink.defaultCardBackground {
div:not(.sectionTitleContainer-cards) > .sectionTitle-cards { div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
margin: 0; margin: 0;
padding-top: 1.25em; padding-top: 0.5em;
padding-bottom: 0.2em;
}
.layout-mobile :not(.sectionTitleContainer-cards) > .sectionTitle-cards {
margin: 0;
padding-top: 0.5em;
} }
.sectionTitleButton { .sectionTitleButton {
@ -1132,6 +1232,12 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
.trackSelections .selectContainer .selectLabel { .trackSelections .selectContainer .selectLabel {
margin: 0 0.2em 0 0; margin: 0 0.2em 0 0;
line-height: 1.75;
}
.layout-mobile .detailsGroupItem .label,
.layout-mobile .trackSelections .selectContainer .selectLabel {
flex-basis: 4.5em;
} }
.trackSelections .selectContainer .detailTrackSelect { .trackSelections .selectContainer .detailTrackSelect {
@ -1144,3 +1250,21 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
margin-top: 0; margin-top: 0;
font-size: 1.4em; font-size: 1.4em;
} }
.overview-controls {
display: flex;
justify-content: flex-end;
}
.detail-clamp-text {
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 12;
-webkit-box-orient: vertical;
}
@media all and (min-width: 40em) {
.detail-clamp-text {
-webkit-line-clamp: 6;
}
}

View file

@ -12,6 +12,7 @@
.hiddenScrollX, .hiddenScrollX,
.layout-tv .scrollX { .layout-tv .scrollX {
-ms-overflow-style: none; -ms-overflow-style: none;
scrollbar-width: none;
} }
.hiddenScrollX-forced { .hiddenScrollX-forced {
@ -40,6 +41,7 @@
.hiddenScrollY, .hiddenScrollY,
.layout-tv .smoothScrollY { .layout-tv .smoothScrollY {
-ms-overflow-style: none; -ms-overflow-style: none;
scrollbar-width: none;
/* Can't do this because it not only hides the scrollbar, but also prevents scrolling */ /* Can't do this because it not only hides the scrollbar, but also prevents scrolling */

View file

@ -5,9 +5,26 @@ html {
height: 100%; height: 100%;
} }
.layout-mobile,
.layout-tv {
-webkit-touch-callout: none;
user-select: none;
}
.clipForScreenReader {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
.material-icons { .material-icons {
/* Fix font ligatures on older WebOS versions */ /* Fix font ligatures on older WebOS versions */
-webkit-font-feature-settings: "liga"; font-feature-settings: "liga";
} }
.backgroundContainer { .backgroundContainer {
@ -23,16 +40,6 @@ html {
line-height: 1.35; line-height: 1.35;
} }
.layout-mobile,
.layout-tv {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
body { body {
overflow-x: hidden; overflow-x: hidden;
background-color: transparent !important; background-color: transparent !important;
@ -109,3 +116,30 @@ div[data-role=page] {
.headroom--unpinned { .headroom--unpinned {
transform: translateY(-100%); transform: translateY(-100%);
} }
.drawerContent {
/* make sure the bottom of the drawer is visible when music is playing */
padding-bottom: 4em;
}
.force-scroll {
overflow-y: scroll;
}
.hide-scroll {
overflow-y: hidden;
}
.w-100 {
width: 100%;
}
.margin-auto-x {
margin-left: auto;
margin-right: auto;
}
.margin-auto-y {
margin-top: auto;
margin-bottom: auto;
}

View file

@ -30,7 +30,7 @@
opacity: 0; opacity: 0;
} }
.osdHeader .headerButton:not(.headerBackButton):not(.headerCastButton) { .osdHeader .headerButton:not(.headerBackButton):not(.headerCastButton):not(.headerSyncButton) {
display: none; display: none;
} }

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24"><title>Microsoft Edge icon</title><path d="M21.86 17.86q.14 0 .25.12.1.13.1.25t-.11.33l-.32.46-.43.53-.44.5q-.21.25-.38.42l-.22.23q-.58.53-1.34 1.04-.76.51-1.6.91-.86.4-1.74.64t-1.67.24q-.9 0-1.69-.28-.8-.28-1.48-.78-.68-.5-1.22-1.17-.53-.66-.92-1.44-.38-.77-.58-1.6-.2-.83-.2-1.67 0-1 .32-1.96.33-.97.87-1.8.14.95.55 1.77.41.82 1.02 1.5.6.68 1.38 1.21.78.54 1.64.9.86.36 1.77.56.92.2 1.8.2 1.12 0 2.18-.24 1.06-.23 2.06-.72l.2-.1.2-.05zm-15.5-1.27q0 1.1.27 2.15.27 1.06.78 2.03.51.96 1.24 1.77.74.82 1.66 1.4-1.47-.2-2.8-.74-1.33-.55-2.48-1.37-1.15-.83-2.08-1.9-.92-1.07-1.58-2.33T.36 14.94Q0 13.54 0 12.06q0-.81.32-1.49.31-.68.83-1.23.53-.55 1.2-.96.66-.4 1.35-.66.74-.27 1.5-.39.78-.12 1.55-.12.7 0 1.42.1.72.12 1.4.35.68.23 1.32.57.63.35 1.16.83-.35 0-.7.07-.33.07-.65.23v-.02q-.63.28-1.2.74-.57.46-1.05 1.04-.48.58-.87 1.26-.38.67-.65 1.39-.27.71-.42 1.44-.15.72-.15 1.38zM11.96.06q1.7 0 3.33.39 1.63.38 3.07 1.15 1.43.77 2.62 1.93 1.18 1.16 1.98 2.7.49.94.76 1.96.28 1 .28 2.08 0 .89-.23 1.7-.24.8-.69 1.48-.45.68-1.1 1.22-.64.53-1.45.88-.54.24-1.11.36-.58.13-1.16.13-.42 0-.97-.03-.54-.03-1.1-.12-.55-.1-1.05-.28-.5-.19-.84-.5-.12-.09-.23-.24-.1-.16-.1-.33 0-.15.16-.35.16-.2.35-.5.2-.28.36-.68.16-.4.16-.95 0-1.06-.4-1.96-.4-.91-1.06-1.64-.66-.74-1.52-1.28-.86-.55-1.79-.89-.84-.3-1.72-.44-.87-.14-1.76-.14-1.55 0-3.06.45T.94 7.55q.71-1.74 1.81-3.13 1.1-1.38 2.52-2.35Q6.68 1.1 8.37.58q1.7-.52 3.58-.52Z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -4,18 +4,18 @@
// Use define from require.js not webpack's define // Use define from require.js not webpack's define
var _define = window.define; var _define = window.define;
// document-register-element
var docRegister = require('document-register-element');
_define('document-register-element', function() {
return docRegister;
});
// fetch // fetch
var fetch = require('whatwg-fetch'); var fetch = require('whatwg-fetch');
_define('fetch', function() { _define('fetch', function() {
return fetch; return fetch;
}); });
// Blurhash
var blurhash = require('blurhash');
_define('blurhash', function() {
return blurhash;
});
// query-string // query-string
var query = require('query-string'); var query = require('query-string');
_define('queryString', function() { _define('queryString', function() {
@ -59,12 +59,6 @@ _define('resize-observer-polyfill', function() {
return resize; return resize;
}); });
// shaka
var shaka = require('shaka-player');
_define('shaka', function() {
return shaka;
});
// swiper // swiper
var swiper = require('swiper/js/swiper'); var swiper = require('swiper/js/swiper');
require('swiper/css/swiper.min.css'); require('swiper/css/swiper.min.css');
@ -102,6 +96,11 @@ _define('jellyfin-noto', function () {
return noto; return noto;
}); });
var epubjs = require('epubjs');
_define('epubjs', function () {
return epubjs;
});
// page.js // page.js
var page = require('page'); var page = require('page');
_define('page', function() { _define('page', function() {

View file

@ -0,0 +1,97 @@
/* eslint-disable indent */
/**
* Module for controlling user parental control from.
* @module components/accessSchedule/accessSchedule
*/
import dialogHelper from 'dialogHelper';
import datetime from 'datetime';
import globalize from 'globalize';
import 'emby-select';
import 'paper-icon-button-light';
import 'formDialogStyle';
function getDisplayTime(hours) {
let minutes = 0;
const pct = hours % 1;
if (pct) {
minutes = parseInt(60 * pct);
}
return datetime.getDisplayTime(new Date(2000, 1, 1, hours, minutes, 0, 0));
}
function populateHours(context) {
let html = '';
for (let 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, {DayOfWeek, StartHour, EndHour}) {
context.querySelector('#selectDay').value = DayOfWeek || 'Sunday';
context.querySelector('#selectStart').value = StartHour || 0;
context.querySelector('#selectEnd').value = EndHour || 0;
}
function submitSchedule(context, options) {
const updatedSchedule = {
DayOfWeek: context.querySelector('#selectDay').value,
StartHour: context.querySelector('#selectStart').value,
EndHour: context.querySelector('#selectEnd').value
};
if (parseFloat(updatedSchedule.StartHour) >= parseFloat(updatedSchedule.EndHour)) {
return void alert(globalize.translate('ErrorStartHourGreaterThanEnd'));
}
context.submitted = true;
options.schedule = Object.assign(options.schedule, updatedSchedule);
dialogHelper.close(context);
}
export function show(options) {
return new Promise((resolve, reject) => {
import('text!./accessSchedule.template.html').then(({default: template}) => {
const dlg = dialogHelper.createDialog({
removeOnClose: true,
size: 'small'
});
dlg.classList.add('formDialog');
let html = '';
html += globalize.translateHtml(template);
dlg.innerHTML = html;
populateHours(dlg);
loadSchedule(dlg, options.schedule);
dialogHelper.open(dlg);
dlg.addEventListener('close', () => {
if (dlg.submitted) {
resolve(options.schedule);
} else {
reject();
}
});
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
dlg.querySelector('form').addEventListener('submit', event => {
submitSchedule(dlg, options);
event.preventDefault();
return false;
});
});
});
}
/* eslint-enable indent */
export default {
show: show
};

View file

@ -1,6 +1,6 @@
<div class="formDialogHeader"> <div class="formDialogHeader">
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"> <button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
<span class="material-icons arrow_back"></span> <span class="material-icons arrow_back" aria-hidden="true"></span>
</button> </button>
<h3 class="formDialogHeaderTitle"> <h3 class="formDialogHeaderTitle">
${HeaderAccessSchedule} ${HeaderAccessSchedule}

View file

@ -1,89 +0,0 @@
define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-button-light', 'formDialogStyle'], function (dialogHelper, datetime, globalize) {
'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));
}
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;
}
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;
}
function submitSchedule(context, options) {
var updatedSchedule = {
DayOfWeek: context.querySelector('#selectDay').value,
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);
}
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'
});
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();
});
}
};
});

View file

@ -0,0 +1,323 @@
import dialogHelper from 'dialogHelper';
import layoutManager from 'layoutManager';
import globalize from 'globalize';
import dom from 'dom';
import 'emby-button';
import 'css!./actionSheet';
import 'material-icons';
import 'scrollStyles';
import 'listViewStyle';
function getOffsets(elems) {
let results = [];
if (!document) {
return results;
}
for (const elem of elems) {
let box = elem.getBoundingClientRect();
results.push({
top: box.top,
left: box.left,
width: box.width,
height: box.height
});
}
return results;
}
function getPosition(options, dlg) {
const windowSize = dom.getWindowSize();
const windowHeight = windowSize.innerHeight;
const windowWidth = windowSize.innerWidth;
let pos = getOffsets([options.positionTo])[0];
if (options.positionY !== 'top') {
pos.top += (pos.height || 0) / 2;
}
pos.left += (pos.width || 0) / 2;
const height = dlg.offsetHeight || 300;
const width = dlg.offsetWidth || 160;
// Account for popup size
pos.top -= height / 2;
pos.left -= width / 2;
// Avoid showing too close to the bottom
const overflowX = pos.left + width - windowWidth;
const overflowY = pos.top + height - windowHeight;
if (overflowX > 0) {
pos.left -= (overflowX + 20);
}
if (overflowY > 0) {
pos.top -= (overflowY + 20);
}
pos.top += (options.offsetTop || 0);
pos.left += (options.offsetLeft || 0);
// Do some boundary checking
pos.top = Math.max(pos.top, 10);
pos.left = Math.max(pos.left, 10);
return pos;
}
function centerFocus(elem, horiz, on) {
import('scrollHelper').then(({default: scrollHelper}) => {
const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
export function show(options) {
// items
// positionTo
// showCancel
// title
let dialogOptions = {
removeOnClose: true,
enableHistory: options.enableHistory,
scrollY: false
};
let isFullscreen;
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
isFullscreen = true;
dialogOptions.autoFocus = true;
} else {
dialogOptions.modal = false;
dialogOptions.entryAnimation = options.entryAnimation;
dialogOptions.exitAnimation = options.exitAnimation;
dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140;
dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100;
dialogOptions.autoFocus = false;
}
let dlg = dialogHelper.createDialog(dialogOptions);
if (isFullscreen) {
dlg.classList.add('actionsheet-fullscreen');
} else {
dlg.classList.add('actionsheet-not-fullscreen');
}
dlg.classList.add('actionSheet');
if (options.dialogClass) {
dlg.classList.add(options.dialogClass);
}
let html = '';
const scrollClassName = layoutManager.tv ? 'scrollY smoothScrollY hiddenScrollY' : 'scrollY';
let style = '';
// Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation
if (options.items.length > 20) {
const minWidth = dom.getWindowSize().innerWidth >= 300 ? 240 : 200;
style += 'min-width:' + minWidth + 'px;';
}
let renderIcon = false;
let icons = [];
let itemIcon;
for (const item of options.items) {
itemIcon = item.icon || (item.selected ? 'check' : null);
if (itemIcon) {
renderIcon = true;
}
icons.push(itemIcon || '');
}
if (layoutManager.tv) {
html += `<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1">
<span class="material-icons arrow_back"></span>
</button>`;
}
// If any items have an icon, give them all an icon just to make sure they're all lined up evenly
const center = options.title && (!renderIcon /*|| itemsWithIcons.length != options.items.length*/);
if (center || layoutManager.tv) {
html += '<div class="actionSheetContent actionSheetContent-centered">';
} else {
html += '<div class="actionSheetContent">';
}
if (options.title) {
html += '<h1 class="actionSheetTitle">' + options.title + '</h1>';
}
if (options.text) {
html += '<p class="actionSheetText">' + options.text + '</p>';
}
let scrollerClassName = 'actionSheetScroller';
if (layoutManager.tv) {
scrollerClassName += ' actionSheetScroller-tv focuscontainer-x focuscontainer-y';
}
html += '<div class="' + scrollerClassName + ' ' + scrollClassName + '" style="' + style + '">';
let menuItemClass = 'listItem listItem-button actionSheetMenuItem';
if (options.border || options.shaded) {
menuItemClass += ' listItem-border';
}
if (options.menuItemClass) {
menuItemClass += ' ' + options.menuItemClass;
}
if (layoutManager.tv) {
menuItemClass += ' listItem-focusscale';
}
if (layoutManager.mobile) {
menuItemClass += ' actionsheet-xlargeFont';
}
// 'options.items' is HTMLOptionsCollection, so no fancy loops
for (let i = 0; i < options.items.length; i++) {
const item = options.items[i];
if (item.divider) {
html += '<div class="actionsheetDivider"></div>';
continue;
}
const autoFocus = item.selected && layoutManager.tv ? ' autoFocus' : '';
// Check for null in case int 0 was passed in
const optionId = item.id == null || item.id === '' ? item.value : item.id;
html += '<button' + autoFocus + ' is="emby-button" type="button" class="' + menuItemClass + '" data-id="' + optionId + '">';
itemIcon = icons[i];
if (itemIcon) {
html += `<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons ${itemIcon}"></span>`;
} else if (renderIcon && !center) {
html += '<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons check" style="visibility:hidden;"></span>';
}
html += '<div class="listItemBody actionsheetListItemBody">';
html += '<div class="listItemBodyText actionSheetItemText">';
html += (item.name || item.textContent || item.innerText);
html += '</div>';
if (item.secondaryText) {
html += `<div class="listItemBodyText secondary">${item.secondaryText}</div>`;
}
html += '</div>';
if (item.asideText) {
html += `<div class="listItemAside actionSheetItemAsideText">${item.asideText}</div>`;
}
html += '</button>';
}
if (options.showCancel) {
html += '<div class="buttons">';
html += `<button is="emby-button" type="button" class="btnCloseActionSheet">${globalize.translate('ButtonCancel')}</button>`;
html += '</div>';
}
html += '</div>';
dlg.innerHTML = html;
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
}
let btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
if (btnCloseActionSheet) {
btnCloseActionSheet.addEventListener('click', function () {
dialogHelper.close(dlg);
});
}
let selectedId;
let timeout;
if (options.timeout) {
timeout = setTimeout(function () {
dialogHelper.close(dlg);
}, options.timeout);
}
return new Promise(function (resolve, reject) {
let isResolved;
dlg.addEventListener('click', function (e) {
const actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
if (actionSheetMenuItem) {
selectedId = actionSheetMenuItem.getAttribute('data-id');
if (options.resolveOnClick) {
if (options.resolveOnClick.indexOf) {
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
resolve(selectedId);
isResolved = true;
}
} else {
resolve(selectedId);
isResolved = true;
}
}
dialogHelper.close(dlg);
}
});
dlg.addEventListener('close', function () {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
}
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
if (!isResolved) {
if (selectedId != null) {
if (options.callback) {
options.callback(selectedId);
}
resolve(selectedId);
} else {
reject();
}
}
});
dialogHelper.open(dlg);
const pos = options.positionTo && dialogOptions.size !== 'fullscreen' ? getPosition(options, dlg) : null;
if (pos) {
dlg.style.position = 'fixed';
dlg.style.margin = 0;
dlg.style.left = pos.left + 'px';
dlg.style.top = pos.top + 'px';
}
});
}
export default {
show: show
};

View file

@ -1,360 +0,0 @@
define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-button', 'css!./actionsheet', 'material-icons', 'scrollStyles', 'listViewStyle'], function (dialogHelper, layoutManager, globalize, browser, dom) {
'use strict';
function getOffsets(elems) {
var doc = document;
var results = [];
if (!doc) {
return results;
}
var box;
var elem;
for (var i = 0, length = elems.length; i < length; i++) {
elem = elems[i];
// Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error
if (elem.getBoundingClientRect) {
box = elem.getBoundingClientRect();
} else {
box = { top: 0, left: 0 };
}
results[i] = {
top: box.top,
left: box.left,
width: box.width,
height: box.height
};
}
return results;
}
function getPosition(options, dlg) {
var windowSize = dom.getWindowSize();
var windowHeight = windowSize.innerHeight;
var windowWidth = windowSize.innerWidth;
var pos = getOffsets([options.positionTo])[0];
if (options.positionY !== 'top') {
pos.top += (pos.height || 0) / 2;
}
pos.left += (pos.width || 0) / 2;
var height = dlg.offsetHeight || 300;
var width = dlg.offsetWidth || 160;
// Account for popup size
pos.top -= height / 2;
pos.left -= width / 2;
// Avoid showing too close to the bottom
var overflowX = pos.left + width - windowWidth;
var overflowY = pos.top + height - windowHeight;
if (overflowX > 0) {
pos.left -= (overflowX + 20);
}
if (overflowY > 0) {
pos.top -= (overflowY + 20);
}
pos.top += (options.offsetTop || 0);
pos.left += (options.offsetLeft || 0);
// Do some boundary checking
pos.top = Math.max(pos.top, 10);
pos.left = Math.max(pos.left, 10);
return pos;
}
function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function show(options) {
// items
// positionTo
// showCancel
// title
var dialogOptions = {
removeOnClose: true,
enableHistory: options.enableHistory,
scrollY: false
};
var backButton = false;
var isFullscreen;
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
isFullscreen = true;
backButton = true;
dialogOptions.autoFocus = true;
} else {
dialogOptions.modal = false;
dialogOptions.entryAnimation = options.entryAnimation;
dialogOptions.exitAnimation = options.exitAnimation;
dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140;
dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100;
dialogOptions.autoFocus = false;
}
var dlg = dialogHelper.createDialog(dialogOptions);
if (isFullscreen) {
dlg.classList.add('actionsheet-fullscreen');
} else {
dlg.classList.add('actionsheet-not-fullscreen');
}
dlg.classList.add('actionSheet');
if (options.dialogClass) {
dlg.classList.add(options.dialogClass);
}
var html = '';
var scrollClassName = layoutManager.tv ? 'scrollY smoothScrollY hiddenScrollY' : 'scrollY';
var style = '';
// Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation
if (options.items.length > 20) {
var minWidth = dom.getWindowSize().innerWidth >= 300 ? 240 : 200;
style += 'min-width:' + minWidth + 'px;';
}
var i;
var length;
var option;
var renderIcon = false;
var icons = [];
var itemIcon;
for (i = 0, length = options.items.length; i < length; i++) {
option = options.items[i];
itemIcon = option.icon || (option.selected ? 'check' : null);
if (itemIcon) {
renderIcon = true;
}
icons.push(itemIcon || '');
}
if (layoutManager.tv) {
html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
}
// If any items have an icon, give them all an icon just to make sure they're all lined up evenly
var center = options.title && (!renderIcon /*|| itemsWithIcons.length != options.items.length*/);
if (center || layoutManager.tv) {
html += '<div class="actionSheetContent actionSheetContent-centered">';
} else {
html += '<div class="actionSheetContent">';
}
if (options.title) {
html += '<h1 class="actionSheetTitle">';
html += options.title;
html += '</h1>';
}
if (options.text) {
html += '<p class="actionSheetText">';
html += options.text;
html += '</p>';
}
var scrollerClassName = 'actionSheetScroller';
if (layoutManager.tv) {
scrollerClassName += ' actionSheetScroller-tv focuscontainer-x focuscontainer-y';
}
html += '<div class="' + scrollerClassName + ' ' + scrollClassName + '" style="' + style + '">';
var menuItemClass = 'listItem listItem-button actionSheetMenuItem';
if (options.border || options.shaded) {
menuItemClass += ' listItem-border';
}
if (options.menuItemClass) {
menuItemClass += ' ' + options.menuItemClass;
}
if (layoutManager.tv) {
menuItemClass += ' listItem-focusscale';
}
if (layoutManager.mobile) {
menuItemClass += ' actionsheet-xlargeFont';
}
for (i = 0, length = options.items.length; i < length; i++) {
option = options.items[i];
if (option.divider) {
html += '<div class="actionsheetDivider"></div>';
continue;
}
var autoFocus = option.selected && layoutManager.tv ? ' autoFocus' : '';
// Check for null in case int 0 was passed in
var optionId = option.id == null || option.id === '' ? option.value : option.id;
html += '<button' + autoFocus + ' is="emby-button" type="button" class="' + menuItemClass + '" data-id="' + optionId + '">';
itemIcon = icons[i];
if (itemIcon) {
html += '<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons ' + itemIcon + '"></span>';
} else if (renderIcon && !center) {
html += '<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons check" style="visibility:hidden;"></span>';
}
html += '<div class="listItemBody actionsheetListItemBody">';
html += '<div class="listItemBodyText actionSheetItemText">';
html += (option.name || option.textContent || option.innerText);
html += '</div>';
if (option.secondaryText) {
html += '<div class="listItemBodyText secondary">';
html += option.secondaryText;
html += '</div>';
}
html += '</div>';
if (option.asideText) {
html += '<div class="listItemAside actionSheetItemAsideText">';
html += option.asideText;
html += '</div>';
}
html += '</button>';
}
if (options.showCancel) {
html += '<div class="buttons">';
html += '<button is="emby-button" type="button" class="btnCloseActionSheet">' + globalize.translate('ButtonCancel') + '</button>';
html += '</div>';
}
html += '</div>';
dlg.innerHTML = html;
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
}
var btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
if (btnCloseActionSheet) {
dlg.querySelector('.btnCloseActionSheet').addEventListener('click', function () {
dialogHelper.close(dlg);
});
}
// Seeing an issue in some non-chrome browsers where this is requiring a double click
//var eventName = browser.firefox ? 'mousedown' : 'click';
var selectedId;
var timeout;
if (options.timeout) {
timeout = setTimeout(function () {
dialogHelper.close(dlg);
}, options.timeout);
}
return new Promise(function (resolve, reject) {
var isResolved;
dlg.addEventListener('click', function (e) {
var actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
if (actionSheetMenuItem) {
selectedId = actionSheetMenuItem.getAttribute('data-id');
if (options.resolveOnClick) {
if (options.resolveOnClick.indexOf) {
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
resolve(selectedId);
isResolved = true;
}
} else {
resolve(selectedId);
isResolved = true;
}
}
dialogHelper.close(dlg);
}
});
dlg.addEventListener('close', function () {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
}
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
if (!isResolved) {
if (selectedId != null) {
if (options.callback) {
options.callback(selectedId);
}
resolve(selectedId);
} else {
reject();
}
}
});
dialogHelper.open(dlg);
var pos = options.positionTo && dialogOptions.size !== 'fullscreen' ? getPosition(options, dlg) : null;
if (pos) {
dlg.style.position = 'fixed';
dlg.style.margin = 0;
dlg.style.left = pos.left + 'px';
dlg.style.top = pos.top + 'px';
}
});
}
return {
show: show
};
});

View file

@ -1,13 +1,22 @@
define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings', 'serverNotifications', 'connectionManager', 'emby-button', 'listViewStyle'], function (events, globalize, dom, datefns, dfnshelper, userSettings, serverNotifications, connectionManager) { import events from 'events';
'use strict'; import globalize from 'globalize';
import dom from 'dom';
import * as datefns from 'date-fns';
import dfnshelper from 'dfnshelper';
import serverNotifications from 'serverNotifications';
import connectionManager from 'connectionManager';
import 'emby-button';
import 'listViewStyle';
/* eslint-disable indent */
function getEntryHtml(entry, apiClient) { function getEntryHtml(entry, apiClient) {
var html = ''; let html = '';
html += '<div class="listItem listItem-border">'; html += '<div class="listItem listItem-border">';
var color = '#00a4dc'; let color = '#00a4dc';
var icon = 'notifications'; let icon = 'notifications';
if ('Error' == entry.Severity || 'Fatal' == entry.Severity || 'Warn' == entry.Severity) { if (entry.Severity == 'Error' || entry.Severity == 'Fatal' || entry.Severity == 'Warn') {
color = '#cc0000'; color = '#cc0000';
icon = 'notification_important'; icon = 'notification_important';
} }
@ -34,10 +43,14 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
html += '</div>'; html += '</div>';
if (entry.Overview) { if (entry.Overview) {
html += '<button type="button" is="paper-icon-button-light" class="btnEntryInfo" data-id="' + entry.Id + '" title="' + globalize.translate('Info') + '"><span class="material-icons info"></span></button>'; html += `<button type="button" is="paper-icon-button-light" class="btnEntryInfo" data-id="${entry.Id}" title="${globalize.translate('Info')}">
<span class="material-icons info"></span>
</button>`;
} }
return html += '</div>'; html += '</div>';
return html;
} }
function renderList(elem, apiClient, result, startIndex, limit) { function renderList(elem, apiClient, result, startIndex, limit) {
@ -47,14 +60,15 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
} }
function reloadData(instance, elem, apiClient, startIndex, limit) { function reloadData(instance, elem, apiClient, startIndex, limit) {
if (null == startIndex) { if (startIndex == null) {
startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0'); startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0');
} }
limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7'); limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7');
var minDate = new Date(); const minDate = new Date();
var hasUserId = 'false' !== elem.getAttribute('data-useractivity'); const hasUserId = elem.getAttribute('data-useractivity') !== 'false';
// TODO: Use date-fns
if (hasUserId) { if (hasUserId) {
minDate.setTime(minDate.getTime() - 24 * 60 * 60 * 1000); // one day back minDate.setTime(minDate.getTime() - 24 * 60 * 60 * 1000); // one day back
} else { } else {
@ -70,7 +84,7 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
elem.setAttribute('data-activitystartindex', startIndex); elem.setAttribute('data-activitystartindex', startIndex);
elem.setAttribute('data-activitylimit', limit); elem.setAttribute('data-activitylimit', limit);
if (!startIndex) { if (!startIndex) {
var activityContainer = dom.parentWithClass(elem, 'activityContainer'); const activityContainer = dom.parentWithClass(elem, 'activityContainer');
if (activityContainer) { if (activityContainer) {
if (result.Items.length) { if (result.Items.length) {
@ -87,7 +101,7 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
} }
function onActivityLogUpdate(e, apiClient, data) { function onActivityLogUpdate(e, apiClient, data) {
var options = this.options; const options = this.options;
if (options && options.serverId === apiClient.serverId()) { if (options && options.serverId === apiClient.serverId()) {
reloadData(this, options.element, apiClient); reloadData(this, options.element, apiClient);
@ -95,14 +109,14 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
} }
function onListClick(e) { function onListClick(e) {
var btnEntryInfo = dom.parentWithClass(e.target, 'btnEntryInfo'); const btnEntryInfo = dom.parentWithClass(e.target, 'btnEntryInfo');
if (btnEntryInfo) { if (btnEntryInfo) {
var id = btnEntryInfo.getAttribute('data-id'); const id = btnEntryInfo.getAttribute('data-id');
var items = this.items; const items = this.items;
if (items) { if (items) {
var item = items.filter(function (i) { const item = items.filter(function (i) {
return i.Id.toString() === id; return i.Id.toString() === id;
})[0]; })[0];
@ -114,35 +128,35 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
} }
function showItemOverview(item) { function showItemOverview(item) {
require(['alert'], function (alert) { import('alert').then(({default: alert}) => {
alert({ alert({
text: item.Overview text: item.Overview
}); });
}); });
} }
function ActivityLog(options) { class ActivityLog {
constructor(options) {
this.options = options; this.options = options;
var element = options.element; const element = options.element;
element.classList.add('activityLogListWidget'); element.classList.add('activityLogListWidget');
element.addEventListener('click', onListClick.bind(this)); element.addEventListener('click', onListClick.bind(this));
var apiClient = connectionManager.getApiClient(options.serverId); const apiClient = connectionManager.getApiClient(options.serverId);
reloadData(this, element, apiClient); reloadData(this, element, apiClient);
var onUpdate = onActivityLogUpdate.bind(this); const onUpdate = onActivityLogUpdate.bind(this);
this.updateFn = onUpdate; this.updateFn = onUpdate;
events.on(serverNotifications, 'ActivityLogEntry', onUpdate); events.on(serverNotifications, 'ActivityLogEntry', onUpdate);
apiClient.sendMessage('ActivityLogEntryStart', '0,1500'); apiClient.sendMessage('ActivityLogEntryStart', '0,1500');
} }
destroy() {
ActivityLog.prototype.destroy = function () { const options = this.options;
var options = this.options;
if (options) { if (options) {
options.element.classList.remove('activityLogListWidget'); 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; const onUpdate = this.updateFn;
if (onUpdate) { if (onUpdate) {
events.off(serverNotifications, 'ActivityLogEntry', onUpdate); events.off(serverNotifications, 'ActivityLogEntry', onUpdate);
@ -150,7 +164,9 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
this.items = null; this.items = null;
this.options = null; this.options = null;
}; }
}
return ActivityLog; export default ActivityLog;
});
/* eslint-enable indent */

View file

@ -1,14 +1,16 @@
define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize) { import browser from 'browser';
'use strict'; import dialog from 'dialog';
import globalize from 'globalize';
/* eslint-disable indent */
function replaceAll(originalString, strReplace, strWith) { function replaceAll(originalString, strReplace, strWith) {
var reg = new RegExp(strReplace, 'ig'); const reg = new RegExp(strReplace, 'ig');
return originalString.replace(reg, strWith); return originalString.replace(reg, strWith);
} }
return function (text, title) { export default function (text, title) {
let options;
var options;
if (typeof text === 'string') { if (typeof text === 'string') {
options = { options = {
title: title, title: title,
@ -21,7 +23,7 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
if (browser.tv && window.alert) { if (browser.tv && window.alert) {
alert(replaceAll(options.text || '', '<br/>', '\n')); alert(replaceAll(options.text || '', '<br/>', '\n'));
} else { } else {
var items = []; const items = [];
items.push({ items.push({
name: globalize.translate('ButtonGotIt'), name: globalize.translate('ButtonGotIt'),
@ -31,7 +33,7 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
options.buttons = items; options.buttons = items;
return dialog(options).then(function (result) { return dialog.show(options).then(function (result) {
if (result === 'ok') { if (result === 'ok') {
return Promise.resolve(); return Promise.resolve();
} }
@ -41,5 +43,6 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
} }
return Promise.resolve(); return Promise.resolve();
}; }
});
/* eslint-enable indent */

View file

@ -0,0 +1,313 @@
/* eslint-disable indent */
/**
* Module alphaPicker.
* @module components/alphaPicker/alphaPicker
*/
import focusManager from 'focusManager';
import layoutManager from 'layoutManager';
import dom from 'dom';
import 'css!./style.css';
import 'paper-icon-button-light';
import 'material-icons';
const selectedButtonClass = 'alphaPickerButton-selected';
function focus() {
const scope = this;
const selected = scope.querySelector(`.${selectedButtonClass}`);
if (selected) {
focusManager.focus(selected);
} else {
focusManager.autoFocus(scope, true);
}
}
function getAlphaPickerButtonClassName(vertical) {
let alphaPickerButtonClassName = 'alphaPickerButton';
if (layoutManager.tv) {
alphaPickerButtonClassName += ' alphaPickerButton-tv';
}
if (vertical) {
alphaPickerButtonClassName += ' alphaPickerButton-vertical';
}
return alphaPickerButtonClassName;
}
function getLetterButton(l, vertical) {
return `<button data-value="${l}" class="${getAlphaPickerButtonClassName(vertical)}">${l}</button>`;
}
function mapLetters(letters, vertical) {
return letters.map(l => {
return getLetterButton(l, vertical);
});
}
function render(element, options) {
element.classList.add('alphaPicker');
if (layoutManager.tv) {
element.classList.add('alphaPicker-tv');
}
const vertical = element.classList.contains('alphaPicker-vertical');
if (!vertical) {
element.classList.add('focuscontainer-x');
}
let html = '';
let letters;
const alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical);
let rowClassName = 'alphaPickerRow';
if (vertical) {
rowClassName += ' alphaPickerRow-vertical';
}
html += `<div class="${rowClassName}">`;
if (options.mode === 'keyboard') {
html += `<button data-value=" " is="paper-icon-button-light" class="${alphaPickerButtonClassName}"><span class="material-icons alphaPickerButtonIcon space_bar"></span></button>`;
} else {
letters = ['#'];
html += mapLetters(letters, vertical).join('');
}
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
html += mapLetters(letters, vertical).join('');
if (options.mode === 'keyboard') {
html += `<button data-value="backspace" is="paper-icon-button-light" class="${alphaPickerButtonClassName}"><span class="material-icons alphaPickerButtonIcon backspace"></span></button>`;
html += '</div>';
letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
html += `<div class="${rowClassName}">`;
html += '<br/>';
html += mapLetters(letters, vertical).join('');
html += '</div>';
} else {
html += '</div>';
}
element.innerHTML = html;
element.classList.add('focusable');
element.focus = focus;
}
export class AlphaPicker {
constructor(options) {
const self = this;
this.options = options;
const element = options.element;
const itemsContainer = options.itemsContainer;
const itemClass = options.itemClass;
let itemFocusValue;
let itemFocusTimeout;
function onItemFocusTimeout() {
itemFocusTimeout = null;
self.value(itemFocusValue);
}
let alphaFocusedElement;
let alphaFocusTimeout;
function onAlphaFocusTimeout() {
alphaFocusTimeout = null;
if (document.activeElement === alphaFocusedElement) {
const value = alphaFocusedElement.getAttribute('data-value');
self.value(value, true);
}
}
function onAlphaPickerInKeyboardModeClick(e) {
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
const value = alphaPickerButton.getAttribute('data-value');
element.dispatchEvent(new CustomEvent('alphavalueclicked', {
cancelable: false,
detail: {
value
}
}));
}
}
function onAlphaPickerClick(e) {
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
const value = alphaPickerButton.getAttribute('data-value');
if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
this.value(null, true);
} else {
this.value(value, true);
}
}
}
function onAlphaPickerFocusIn(e) {
if (alphaFocusTimeout) {
clearTimeout(alphaFocusTimeout);
alphaFocusTimeout = null;
}
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
alphaFocusedElement = alphaPickerButton;
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
}
}
function onItemsFocusIn(e) {
const item = dom.parentWithClass(e.target, itemClass);
if (item) {
const prefix = item.getAttribute('data-prefix');
if (prefix && prefix.length) {
itemFocusValue = prefix[0];
if (itemFocusTimeout) {
clearTimeout(itemFocusTimeout);
}
itemFocusTimeout = setTimeout(onItemFocusTimeout, 100);
}
}
}
this.enabled = function (enabled) {
if (enabled) {
if (itemsContainer) {
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
}
if (options.mode === 'keyboard') {
element.addEventListener('click', onAlphaPickerInKeyboardModeClick);
}
if (options.valueChangeEvent !== 'click') {
element.addEventListener('focus', onAlphaPickerFocusIn, true);
} else {
element.addEventListener('click', onAlphaPickerClick.bind(this));
}
} else {
if (itemsContainer) {
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
}
element.removeEventListener('click', onAlphaPickerInKeyboardModeClick);
element.removeEventListener('focus', onAlphaPickerFocusIn, true);
element.removeEventListener('click', onAlphaPickerClick.bind(this));
}
};
render(element, options);
this.enabled(true);
this.visible(true);
}
value(value, applyValue) {
const element = this.options.element;
let btn;
let selected;
if (value !== undefined) {
if (value != null) {
value = value.toUpperCase();
this._currentValue = value;
if (this.options.mode !== 'keyboard') {
selected = element.querySelector(`.${selectedButtonClass}`);
try {
btn = element.querySelector(`.alphaPickerButton[data-value='${value}']`);
} catch (err) {
console.error('error in querySelector:', err);
}
if (btn && btn !== selected) {
btn.classList.add(selectedButtonClass);
}
if (selected && selected !== btn) {
selected.classList.remove(selectedButtonClass);
}
}
} else {
this._currentValue = value;
selected = element.querySelector(`.${selectedButtonClass}`);
if (selected) {
selected.classList.remove(selectedButtonClass);
}
}
}
if (applyValue) {
element.dispatchEvent(new CustomEvent('alphavaluechanged', {
cancelable: false,
detail: {
value
}
}));
}
return this._currentValue;
}
on(name, fn) {
const element = this.options.element;
element.addEventListener(name, fn);
}
off(name, fn) {
const element = this.options.element;
element.removeEventListener(name, fn);
}
visible(visible) {
const element = this.options.element;
element.style.visibility = visible ? 'visible' : 'hidden';
}
values() {
const element = this.options.element;
const elems = element.querySelectorAll('.alphaPickerButton');
const values = [];
for (let i = 0, length = elems.length; i < length; i++) {
values.push(elems[i].getAttribute('data-value'));
}
return values;
}
focus() {
const element = this.options.element;
focusManager.autoFocus(element, true);
}
destroy() {
const element = this.options.element;
this.enabled(false);
element.classList.remove('focuscontainer-x');
this.options = null;
}
}
/* eslint-enable indent */
export default AlphaPicker;

View file

@ -1,321 +0,0 @@
define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-button-light', 'material-icons'], function (focusManager, layoutManager, dom) {
'use strict';
var selectedButtonClass = 'alphaPickerButton-selected';
function focus() {
var scope = this;
var selected = scope.querySelector('.' + selectedButtonClass);
if (selected) {
focusManager.focus(selected);
} else {
focusManager.autoFocus(scope, true);
}
}
function getAlphaPickerButtonClassName(vertical) {
var alphaPickerButtonClassName = 'alphaPickerButton';
if (layoutManager.tv) {
alphaPickerButtonClassName += ' alphaPickerButton-tv';
}
if (vertical) {
alphaPickerButtonClassName += ' alphaPickerButton-vertical';
}
return alphaPickerButtonClassName;
}
function getLetterButton(l, vertical) {
return '<button data-value="' + l + '" class="' + getAlphaPickerButtonClassName(vertical) + '">' + l + '</button>';
}
function mapLetters(letters, vertical) {
return letters.map(function (l) {
return getLetterButton(l, vertical);
});
}
function render(element, options) {
element.classList.add('alphaPicker');
if (layoutManager.tv) {
element.classList.add('alphaPicker-tv');
}
var vertical = element.classList.contains('alphaPicker-vertical');
if (!vertical) {
element.classList.add('focuscontainer-x');
}
var html = '';
var letters;
var alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical);
var rowClassName = 'alphaPickerRow';
if (vertical) {
rowClassName += ' alphaPickerRow-vertical';
}
html += '<div class="' + rowClassName + '">';
if (options.mode === 'keyboard') {
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><span class="material-icons alphaPickerButtonIcon space_bar"></span></button>';
} else {
letters = ['#'];
html += mapLetters(letters, vertical).join('');
}
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
html += mapLetters(letters, vertical).join('');
if (options.mode === 'keyboard') {
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><span class="material-icons alphaPickerButtonIcon backspace"></span></button>';
html += '</div>';
letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
html += '<div class="' + rowClassName + '">';
html += '<br/>';
html += mapLetters(letters, vertical).join('');
html += '</div>';
} else {
html += '</div>';
}
element.innerHTML = html;
element.classList.add('focusable');
element.focus = focus;
}
function AlphaPicker(options) {
var self = this;
this.options = options;
var element = options.element;
var itemsContainer = options.itemsContainer;
var itemClass = options.itemClass;
var itemFocusValue;
var itemFocusTimeout;
function onItemFocusTimeout() {
itemFocusTimeout = null;
self.value(itemFocusValue);
}
var alphaFocusedElement;
var alphaFocusTimeout;
function onAlphaFocusTimeout() {
alphaFocusTimeout = null;
if (document.activeElement === alphaFocusedElement) {
var value = alphaFocusedElement.getAttribute('data-value');
self.value(value, true);
}
}
function onAlphaPickerInKeyboardModeClick(e) {
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
var value = alphaPickerButton.getAttribute('data-value');
element.dispatchEvent(new CustomEvent('alphavalueclicked', {
cancelable: false,
detail: {
value: value
}
}));
}
}
function onAlphaPickerClick(e) {
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
var value = alphaPickerButton.getAttribute('data-value');
if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
self.value(null, true);
} else {
self.value(value, true);
}
}
}
function onAlphaPickerFocusIn(e) {
if (alphaFocusTimeout) {
clearTimeout(alphaFocusTimeout);
alphaFocusTimeout = null;
}
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
alphaFocusedElement = alphaPickerButton;
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
}
}
function onItemsFocusIn(e) {
var item = dom.parentWithClass(e.target, itemClass);
if (item) {
var prefix = item.getAttribute('data-prefix');
if (prefix && prefix.length) {
itemFocusValue = prefix[0];
if (itemFocusTimeout) {
clearTimeout(itemFocusTimeout);
}
itemFocusTimeout = setTimeout(onItemFocusTimeout, 100);
}
}
}
self.enabled = function (enabled) {
if (enabled) {
if (itemsContainer) {
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
}
if (options.mode === 'keyboard') {
element.addEventListener('click', onAlphaPickerInKeyboardModeClick);
}
if (options.valueChangeEvent !== 'click') {
element.addEventListener('focus', onAlphaPickerFocusIn, true);
} else {
element.addEventListener('click', onAlphaPickerClick.bind(this));
}
} else {
if (itemsContainer) {
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
}
element.removeEventListener('click', onAlphaPickerInKeyboardModeClick);
element.removeEventListener('focus', onAlphaPickerFocusIn, true);
element.removeEventListener('click', onAlphaPickerClick.bind(this));
}
};
render(element, options);
this.enabled(true);
this.visible(true);
}
AlphaPicker.prototype.value = function (value, applyValue) {
var element = this.options.element;
var btn;
var selected;
if (value !== undefined) {
if (value != null) {
value = value.toUpperCase();
this._currentValue = value;
if (this.options.mode !== 'keyboard') {
selected = element.querySelector('.' + selectedButtonClass);
try {
btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']');
} catch (err) {
console.error('error in querySelector: ' + err);
}
if (btn && btn !== selected) {
btn.classList.add(selectedButtonClass);
}
if (selected && selected !== btn) {
selected.classList.remove(selectedButtonClass);
}
}
} else {
this._currentValue = value;
selected = element.querySelector('.' + selectedButtonClass);
if (selected) {
selected.classList.remove(selectedButtonClass);
}
}
}
if (applyValue) {
element.dispatchEvent(new CustomEvent('alphavaluechanged', {
cancelable: false,
detail: {
value: value
}
}));
}
return this._currentValue;
};
AlphaPicker.prototype.on = function (name, fn) {
var element = this.options.element;
element.addEventListener(name, fn);
};
AlphaPicker.prototype.off = function (name, fn) {
var element = this.options.element;
element.removeEventListener(name, fn);
};
AlphaPicker.prototype.visible = function (visible) {
var element = this.options.element;
element.style.visibility = visible ? 'visible' : 'hidden';
};
AlphaPicker.prototype.values = function () {
var element = this.options.element;
var elems = element.querySelectorAll('.alphaPickerButton');
var values = [];
for (var i = 0, length = elems.length; i < length; i++) {
values.push(elems[i].getAttribute('data-value'));
}
return values;
};
AlphaPicker.prototype.focus = function () {
var element = this.options.element;
focusManager.autoFocus(element, true);
};
AlphaPicker.prototype.destroy = function () {
var element = this.options.element;
this.enabled(false);
element.classList.remove('focuscontainer-x');
this.options = null;
};
return AlphaPicker;
});

View file

@ -1,17 +1,17 @@
define(['browser', 'css!./appfooter'], function (browser) { import 'css!./appFooter';
'use strict';
function render(options) { function render(options) {
var elem = document.createElement('div'); const elem = document.createElement('div');
elem.classList.add('appfooter'); elem.classList.add('appfooter');
document.body.appendChild(elem); document.body.appendChild(elem);
return elem; return elem;
} }
function appFooter(options) { class appFooter {
var self = this; constructor(options) {
const self = this;
self.element = render(options); self.element = render(options);
self.add = function (elem) { self.add = function (elem) {
@ -26,12 +26,11 @@ define(['browser', 'css!./appfooter'], function (browser) {
} }
}; };
} }
destroy() {
appFooter.prototype.destroy = function () {
var self = this; var self = this;
self.element = null; self.element = null;
}; }
}
return appFooter; export default appFooter;
});

View file

@ -1,6 +1,9 @@
define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'page', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, layoutManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost, connectionManager) { define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdrop', 'browser', 'page', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, skinManager, backdrop, browser, page, appSettings, appHost, connectionManager) {
'use strict'; 'use strict';
browser = browser.default || browser;
loading = loading.default || loading;
var appRouter = { var appRouter = {
showLocalLogin: function (serverId, manualLogin) { showLocalLogin: function (serverId, manualLogin) {
var pageName = manualLogin ? 'manuallogin' : 'login'; var pageName = manualLogin ? 'manuallogin' : 'login';
@ -16,25 +19,25 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
show('/settings/settings.html'); show('/settings/settings.html');
}, },
showNowPlaying: function () { showNowPlaying: function () {
show('/nowplaying.html'); show('queue');
} }
}; };
function beginConnectionWizard() { function beginConnectionWizard() {
backdrop.clear(); backdrop.clearBackdrop();
loading.show(); loading.show();
connectionManager.connect({ connectionManager.connect({
enableAutoLogin: appSettings.enableAutoLogin() enableAutoLogin: appSettings.enableAutoLogin()
}).then(function (result) { }).then(function (result) {
handleConnectionResult(result, loading); handleConnectionResult(result);
}); });
} }
function handleConnectionResult(result, loading) { function handleConnectionResult(result) {
switch (result.State) { switch (result.State) {
case 'SignedIn': case 'SignedIn':
loading.hide(); loading.hide();
skinManager.loadUserSkin(); Emby.Page.goHome();
break; break;
case 'ServerSignIn': case 'ServerSignIn':
result.ApiClient.getPublicUsers().then(function (users) { result.ApiClient.getPublicUsers().then(function (users) {
@ -53,7 +56,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
break; break;
case 'ServerUpdateNeeded': case 'ServerUpdateNeeded':
require(['alert'], function (alert) { require(['alert'], function (alert) {
alert({ alert.default({
text: globalize.translate('ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin'), text: globalize.translate('ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin'),
html: globalize.translate('ServerUpdateNeeded', '<a href="https://github.com/jellyfin/jellyfin">https://github.com/jellyfin/jellyfin</a>') html: globalize.translate('ServerUpdateNeeded', '<a href="https://github.com/jellyfin/jellyfin">https://github.com/jellyfin/jellyfin</a>')
}).then(function () { }).then(function () {
@ -147,26 +150,19 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
if (typeof route.path === 'string') { if (typeof route.path === 'string') {
loadContentUrl(ctx, next, route, currentRequest); loadContentUrl(ctx, next, route, currentRequest);
} else { } else {
// ? TODO
next(); next();
} }
}; };
if (!isBackNav) { if (!isBackNav) {
// Don't force a new view for home due to the back menu
//if (route.type !== 'home') {
onNewViewNeeded(); onNewViewNeeded();
return; return;
//}
} }
viewManager.tryRestoreView(currentRequest, function () { viewManager.tryRestoreView(currentRequest, function () {
// done
currentRouteInfo = { currentRouteInfo = {
route: route, route: route,
path: ctx.path path: ctx.path
}; };
}).catch(function (result) { }).catch(function (result) {
if (!result || !result.cancelled) { if (!result || !result.cancelled) {
onNewViewNeeded(); onNewViewNeeded();
@ -197,12 +193,10 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
} }
function onRequestFail(e, data) { function onRequestFail(e, data) {
var apiClient = this; var apiClient = this;
if (data.status === 403) { if (data.status === 403) {
if (data.errorCode === 'ParentalControl') { if (data.errorCode === 'ParentalControl') {
var isCurrentAllowed = currentRouteInfo ? (currentRouteInfo.route.anonymous || currentRouteInfo.route.startup) : true; var isCurrentAllowed = currentRouteInfo ? (currentRouteInfo.route.anonymous || currentRouteInfo.route.startup) : true;
// Bounce to the login screen, but not if a password entry fails, obviously // Bounce to the login screen, but not if a password entry fails, obviously
@ -210,7 +204,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
showForcedLogoutMessage(globalize.translate('AccessRestrictedTryAgainLater')); showForcedLogoutMessage(globalize.translate('AccessRestrictedTryAgainLater'));
appRouter.showLocalLogin(apiClient.serverId()); appRouter.showLocalLogin(apiClient.serverId());
} }
} }
} }
} }
@ -222,48 +215,13 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
} }
function normalizeImageOptions(options) { function normalizeImageOptions(options) {
var scaleFactor = browser.tv ? 0.8 : 1;
var setQuality; var setQuality;
if (options.maxWidth) { if (options.maxWidth || options.width || options.maxHeight || options.height) {
options.maxWidth = Math.round(options.maxWidth * scaleFactor);
setQuality = true; setQuality = true;
} }
if (options.width) { if (setQuality && !options.quality) {
options.width = Math.round(options.width * scaleFactor); options.quality = 90;
setQuality = true;
}
if (options.maxHeight) {
options.maxHeight = Math.round(options.maxHeight * scaleFactor);
setQuality = true;
}
if (options.height) {
options.height = Math.round(options.height * scaleFactor);
setQuality = true;
}
if (setQuality) {
var quality = 100;
var type = options.type || 'Primary';
if (browser.tv || browser.slow) {
if (browser.chrome) {
// webp support
quality = type === 'Primary' ? 40 : 50;
} else {
quality = type === 'Backdrop' ? 60 : 50;
}
} else {
quality = type === 'Backdrop' ? 70 : 90;
}
options.quality = quality;
} }
} }
@ -272,12 +230,10 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
if (navigator.connection) { if (navigator.connection) {
var max = navigator.connection.downlinkMax; var max = navigator.connection.downlinkMax;
if (max && max > 0 && max < Number.POSITIVE_INFINITY) { if (max && max > 0 && max < Number.POSITIVE_INFINITY) {
max /= 8; max /= 8;
max *= 1000000; max *= 1000000;
max *= 0.7; max *= 0.7;
max = parseInt(max); return parseInt(max, 10);
return max;
} }
} }
/* eslint-enable compat/compat */ /* eslint-enable compat/compat */
@ -290,7 +246,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
} }
function onApiClientCreated(e, newApiClient) { function onApiClientCreated(e, newApiClient) {
newApiClient.normalizeImageOptions = normalizeImageOptions; newApiClient.normalizeImageOptions = normalizeImageOptions;
if (browser.iOS) { if (browser.iOS) {
@ -304,12 +259,10 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
} }
function initApiClient(apiClient) { function initApiClient(apiClient) {
onApiClientCreated({}, apiClient); onApiClientCreated({}, apiClient);
} }
function initApiClients() { function initApiClients() {
connectionManager.getApiClients().forEach(initApiClient); connectionManager.getApiClients().forEach(initApiClient);
events.on(connectionManager, 'apiclientcreated', onApiClientCreated); events.on(connectionManager, 'apiclientcreated', onApiClientCreated);
@ -325,7 +278,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
var firstConnectionResult; var firstConnectionResult;
function start(options) { function start(options) {
loading.show(); loading.show();
initApiClients(); initApiClients();
@ -335,56 +287,29 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
connectionManager.connect({ connectionManager.connect({
enableAutoLogin: appSettings.enableAutoLogin() enableAutoLogin: appSettings.enableAutoLogin()
}).then(function (result) { }).then(function (result) {
firstConnectionResult = result; firstConnectionResult = result;
options = options || {}; options = options || {};
page({ page({
click: options.click !== false, click: options.click !== false,
hashbang: options.hashbang !== false, hashbang: options.hashbang !== false
enableHistory: enableHistory()
}); });
}).catch().then(function() { }).catch().then(function() {
loading.hide(); loading.hide();
}); });
} }
function enableHistory() {
//if (browser.edgeUwp) {
// return false;
//}
// shows status bar on navigation
if (browser.xboxOne) {
return false;
}
// Does not support history
if (browser.orsay) {
return false;
}
return true;
}
function enableNativeHistory() { function enableNativeHistory() {
return false; return false;
} }
function authenticate(ctx, route, callback) { function authenticate(ctx, route, callback) {
var firstResult = firstConnectionResult; var firstResult = firstConnectionResult;
if (firstResult) { if (firstResult) {
firstConnectionResult = null; firstConnectionResult = null;
if (firstResult.State !== 'SignedIn' && !route.anonymous) { if (firstResult.State !== 'SignedIn' && !route.anonymous) {
handleConnectionResult(firstResult);
handleConnectionResult(firstResult, loading);
return; return;
} }
} }
@ -412,19 +337,15 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
} }
if (apiClient && apiClient.isLoggedIn()) { if (apiClient && apiClient.isLoggedIn()) {
console.debug('appRouter - user is authenticated'); console.debug('appRouter - user is authenticated');
if (route.isDefaultRoute) { if (route.isDefaultRoute) {
console.debug('appRouter - loading skin home page'); console.debug('appRouter - loading skin home page');
loadUserSkinWithOptions(ctx); Emby.Page.goHome();
return; return;
} else if (route.roles) { } else if (route.roles) {
validateRoles(apiClient, route.roles).then(function () { validateRoles(apiClient, route.roles).then(function () {
callback(); callback();
}, beginConnectionWizard); }, beginConnectionWizard);
return; return;
} }
@ -434,15 +355,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
callback(); callback();
} }
function loadUserSkinWithOptions(ctx) {
require(['queryString'], function (queryString) {
var params = queryString.parse(ctx.querystring);
skinManager.loadUserSkin({
start: params.start
});
});
}
function validateRoles(apiClient, roles) { function validateRoles(apiClient, roles) {
return Promise.all(roles.split(',').map(function (role) { return Promise.all(roles.split(',').map(function (role) {
return validateRole(apiClient, role); return validateRole(apiClient, role);
@ -463,12 +375,10 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
return Promise.resolve(); return Promise.resolve();
} }
var isHandlingBackToDefault;
var isDummyBackToHome; var isDummyBackToHome;
function loadContent(ctx, route, html, request) { function loadContent(ctx, route, html, request) {
html = globalize.translateHtml(html, route.dictionary);
html = globalize.translateDocument(html, route.dictionary);
request.view = html; request.view = html;
viewManager.loadView(request); viewManager.loadView(request);
@ -527,7 +437,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
} }
function getWindowLocationSearch(win) { function getWindowLocationSearch(win) {
var currentPath = currentRouteInfo ? (currentRouteInfo.path || '') : ''; var currentPath = currentRouteInfo ? (currentRouteInfo.path || '') : '';
var index = currentPath.indexOf('?'); var index = currentPath.indexOf('?');
@ -571,9 +480,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
if (!document.querySelector('.dialogContainer') && startPages.indexOf(curr.type) !== -1) { if (!document.querySelector('.dialogContainer') && startPages.indexOf(curr.type) !== -1) {
return false; return false;
} }
if (enableHistory()) {
return history.length > 1;
}
return (page.len || 0) > 0; return (page.len || 0) > 0;
} }
@ -589,8 +496,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
path = '/' + path; path = '/' + path;
} }
var baseRoute = baseUrl(); path = path.replace(baseUrl(), '');
path = path.replace(baseRoute, '');
if (currentRouteInfo && currentRouteInfo.path === path) { if (currentRouteInfo && currentRouteInfo.path === path) {
// can't use this with home right now due to the back menu // can't use this with home right now due to the back menu
@ -621,10 +527,11 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
} }
function showItem(item, serverId, options) { function showItem(item, serverId, options) {
// TODO: Refactor this so it only gets items, not strings.
if (typeof (item) === 'string') { if (typeof (item) === 'string') {
var apiClient = serverId ? connectionManager.getApiClient(serverId) : connectionManager.currentApiClient(); var apiClient = serverId ? connectionManager.getApiClient(serverId) : connectionManager.currentApiClient();
apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (item) { apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (itemObject) {
appRouter.showItem(item, options); appRouter.showItem(itemObject, options);
}); });
} else { } else {
if (arguments.length === 2) { if (arguments.length === 2) {
@ -660,7 +567,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
} }
if (level === 'full' || level === 2) { if (level === 'full' || level === 2) {
backdrop.clear(true); backdrop.clearBackdrop(true);
document.documentElement.classList.add('transparentDocument'); document.documentElement.classList.add('transparentDocument');
backgroundContainer.classList.add('backgroundContainer-transparent'); backgroundContainer.classList.add('backgroundContainer-transparent');
backdropContainer.classList.add('hide'); backdropContainer.classList.add('hide');
@ -680,7 +587,6 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM
function pushState(state, title, url) { function pushState(state, title, url) {
state.navigate = false; state.navigate = false;
history.pushState(state, title, url); history.pushState(state, title, url);
} }
function setBaseRoute() { function setBaseRoute() {

View file

@ -1,11 +1,13 @@
define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'globalize'], function (appSettings, browser, events, htmlMediaHelper, webSettings, globalize) { define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'globalize'], function (appSettings, browser, events, htmlMediaHelper, webSettings, globalize) {
'use strict'; 'use strict';
browser = browser.default || browser;
function getBaseProfileOptions(item) { function getBaseProfileOptions(item) {
var disableHlsVideoAudioCodecs = []; var disableHlsVideoAudioCodecs = [];
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) { if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
if (browser.edge || browser.msie) { if (browser.edge) {
disableHlsVideoAudioCodecs.push('mp3'); disableHlsVideoAudioCodecs.push('mp3');
} }
@ -47,7 +49,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder); profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
} else { } else {
var builderOpts = getBaseProfileOptions(item); var builderOpts = getBaseProfileOptions(item);
builderOpts.enableSsaRender = (item && !options.isRetry && 'allcomplexformats' !== appSettings.get('subtitleburnin')); builderOpts.enableSsaRender = (item && !options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats');
profile = profileBuilder(builderOpts); profile = profileBuilder(builderOpts);
} }
@ -93,18 +95,38 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
function getDeviceName() { function getDeviceName() {
var deviceName; 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'; if (browser.tizen) {
deviceName = 'Samsung Smart TV';
} else if (browser.web0s) {
deviceName = 'LG Smart TV';
} else if (browser.operaTv) {
deviceName = 'Opera TV';
} else if (browser.xboxOne) {
deviceName = 'Xbox One';
} else if (browser.ps4) {
deviceName = 'Sony PS4';
} else if (browser.chrome) {
deviceName = 'Chrome';
} else if (browser.edgeChromium) {
deviceName = 'Edge Chromium';
} else if (browser.edge) {
deviceName = 'Edge';
} else if (browser.firefox) {
deviceName = 'Firefox';
} else if (browser.opera) {
deviceName = 'Opera';
} else if (browser.safari) {
deviceName = 'Safari';
} else {
deviceName = 'Web Browser';
}
if (browser.ipad) { if (browser.ipad) {
deviceName += ' iPad'; deviceName += ' iPad';
} else { } else if (browser.iphone) {
if (browser.iphone) { deviceName += ' iPhone';
deviceName += ' iPhone'; } else if (browser.android) {
} else { deviceName += ' Android';
if (browser.android) {
deviceName += ' Android';
}
}
} }
return deviceName; return deviceName;
@ -239,12 +261,6 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
features.push('fullscreenchange'); features.push('fullscreenchange');
} }
if (browser.chrome || browser.edge && !browser.slow) {
if (!browser.noAnimation && !browser.edgeUwp && !browser.xboxOne) {
features.push('imageanalysis');
}
}
if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) { if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
features.push('physicalvolumecontrol'); features.push('physicalvolumecontrol');
} }
@ -263,11 +279,11 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
features.push('targetblank'); features.push('targetblank');
features.push('screensaver'); features.push('screensaver');
webSettings.enableMultiServer().then(enabled => { webSettings.getMultiServer().then(enabled => {
if (enabled) features.push('multiserver'); if (enabled) features.push('multiserver');
}); });
if (!browser.orsay && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) { if (!browser.orsay && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
features.push('subtitleappearancesettings'); features.push('subtitleappearancesettings');
} }
@ -279,7 +295,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
features.push('fileinput'); features.push('fileinput');
} }
if (browser.chrome) { if (browser.chrome || browser.edgeChromium) {
features.push('chromecast'); features.push('chromecast');
} }
@ -335,7 +351,7 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
var deviceId; var deviceId;
var deviceName; var deviceName;
var appName = 'Jellyfin Web'; var appName = 'Jellyfin Web';
var appVersion = '10.6.0'; var appVersion = '10.7.0';
var appHost = { var appHost = {
getWindowState: function () { getWindowState: function () {
@ -356,10 +372,9 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
return window.NativeShell.AppHost.supports(command); return window.NativeShell.AppHost.supports(command);
} }
return -1 !== supportedFeatures.indexOf(command.toLowerCase()); return supportedFeatures.indexOf(command.toLowerCase()) !== -1;
}, },
preferVisualCards: browser.android || browser.chrome, preferVisualCards: browser.android || browser.chrome,
moreIcon: browser.android ? 'more_vert' : 'more_horiz',
getSyncProfile: getSyncProfile, getSyncProfile: getSyncProfile,
getDefaultLayout: function () { getDefaultLayout: function () {
if (window.NativeShell) { if (window.NativeShell) {
@ -394,13 +409,6 @@ define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'g
getPushTokenInfo: function () { getPushTokenInfo: function () {
return {}; return {};
}, },
setThemeColor: function (color) {
var metaThemeColor = document.querySelector('meta[name=theme-color]');
if (metaThemeColor) {
metaThemeColor.setAttribute('content', color);
}
},
setUserScalable: function (scalable) { setUserScalable: function (scalable) {
if (!browser.tv) { if (!browser.tv) {
var att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no'; var att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no';

View file

@ -1,5 +1,11 @@
define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings', 'css!./backdrop'], function (browser, connectionManager, playbackManager, dom, userSettings) { import browser from 'browser';
'use strict'; import connectionManager from 'connectionManager';
import playbackManager from 'playbackManager';
import dom from 'dom';
import * as userSettings from 'userSettings';
import 'css!./backdrop';
/* eslint-disable indent */
function enableAnimation(elem) { function enableAnimation(elem) {
if (browser.slow) { if (browser.slow) {
@ -22,71 +28,70 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
return true; return true;
} }
function Backdrop() { class Backdrop {
} load(url, parent, existingBackdropImage) {
const img = new Image();
const self = this;
Backdrop.prototype.load = function (url, parent, existingBackdropImage) { img.onload = () => {
var img = new Image(); if (self.isDestroyed) {
var self = this; return;
img.onload = function () {
if (self.isDestroyed) {
return;
}
var backdropImage = document.createElement('div');
backdropImage.classList.add('backdropImage');
backdropImage.classList.add('displayingBackdropImage');
backdropImage.style.backgroundImage = "url('" + url + "')";
backdropImage.setAttribute('data-url', url);
backdropImage.classList.add('backdropImageFadeIn');
parent.appendChild(backdropImage);
if (!enableAnimation(backdropImage)) {
if (existingBackdropImage && existingBackdropImage.parentNode) {
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
} }
internalBackdrop(true);
return;
}
var onAnimationComplete = function () { const backdropImage = document.createElement('div');
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, { backdropImage.classList.add('backdropImage');
backdropImage.classList.add('displayingBackdropImage');
backdropImage.style.backgroundImage = `url('${url}')`;
backdropImage.setAttribute('data-url', url);
backdropImage.classList.add('backdropImageFadeIn');
parent.appendChild(backdropImage);
if (!enableAnimation(backdropImage)) {
if (existingBackdropImage && existingBackdropImage.parentNode) {
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
}
internalBackdrop(true);
return;
}
const onAnimationComplete = () => {
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
once: true
});
if (backdropImage === self.currentAnimatingElement) {
self.currentAnimatingElement = null;
}
if (existingBackdropImage && existingBackdropImage.parentNode) {
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
}
};
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
once: true once: true
}); });
if (backdropImage === self.currentAnimatingElement) {
self.currentAnimatingElement = null; internalBackdrop(true);
}
if (existingBackdropImage && existingBackdropImage.parentNode) {
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
}
}; };
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, { img.src = url;
once: true
});
internalBackdrop(true);
};
img.src = url;
};
Backdrop.prototype.cancelAnimation = function () {
var elem = this.currentAnimatingElement;
if (elem) {
elem.classList.remove('backdropImageFadeIn');
this.currentAnimatingElement = null;
} }
};
Backdrop.prototype.destroy = function () { cancelAnimation() {
this.isDestroyed = true; const elem = this.currentAnimatingElement;
this.cancelAnimation(); if (elem) {
}; elem.classList.remove('backdropImageFadeIn');
this.currentAnimatingElement = null;
}
}
var backdropContainer; destroy() {
this.isDestroyed = true;
this.cancelAnimation();
}
}
let backdropContainer;
function getBackdropContainer() { function getBackdropContainer() {
if (!backdropContainer) { if (!backdropContainer) {
backdropContainer = document.querySelector('.backdropContainer'); backdropContainer = document.querySelector('.backdropContainer');
@ -101,7 +106,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
return backdropContainer; return backdropContainer;
} }
function clearBackdrop(clearAll) { export function clearBackdrop(clearAll) {
clearRotation(); clearRotation();
if (currentLoadingBackdrop) { if (currentLoadingBackdrop) {
@ -109,7 +114,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
currentLoadingBackdrop = null; currentLoadingBackdrop = null;
} }
var elem = getBackdropContainer(); const elem = getBackdropContainer();
elem.innerHTML = ''; elem.innerHTML = '';
if (clearAll) { if (clearAll) {
@ -119,7 +124,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
internalBackdrop(false); internalBackdrop(false);
} }
var backgroundContainer; let backgroundContainer;
function getBackgroundContainer() { function getBackgroundContainer() {
if (!backgroundContainer) { if (!backgroundContainer) {
backgroundContainer = document.querySelector('.backgroundContainer'); backgroundContainer = document.querySelector('.backgroundContainer');
@ -135,31 +140,27 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
} }
} }
var hasInternalBackdrop; let hasInternalBackdrop;
function internalBackdrop(enabled) { function internalBackdrop(enabled) {
hasInternalBackdrop = enabled; hasInternalBackdrop = enabled;
setBackgroundContainerBackgroundEnabled(); setBackgroundContainerBackgroundEnabled();
} }
var hasExternalBackdrop; let hasExternalBackdrop;
function externalBackdrop(enabled) { export function externalBackdrop(enabled) {
hasExternalBackdrop = enabled; hasExternalBackdrop = enabled;
setBackgroundContainerBackgroundEnabled(); setBackgroundContainerBackgroundEnabled();
} }
function getRandom(min, max) { let currentLoadingBackdrop;
return Math.floor(Math.random() * (max - min) + min);
}
var currentLoadingBackdrop;
function setBackdropImage(url) { function setBackdropImage(url) {
if (currentLoadingBackdrop) { if (currentLoadingBackdrop) {
currentLoadingBackdrop.destroy(); currentLoadingBackdrop.destroy();
currentLoadingBackdrop = null; currentLoadingBackdrop = null;
} }
var elem = getBackdropContainer(); const elem = getBackdropContainer();
var existingBackdropImage = elem.querySelector('.displayingBackdropImage'); const existingBackdropImage = elem.querySelector('.displayingBackdropImage');
if (existingBackdropImage && existingBackdropImage.getAttribute('data-url') === url) { if (existingBackdropImage && existingBackdropImage.getAttribute('data-url') === url) {
if (existingBackdropImage.getAttribute('data-url') === url) { if (existingBackdropImage.getAttribute('data-url') === url) {
@ -168,7 +169,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
existingBackdropImage.classList.remove('displayingBackdropImage'); existingBackdropImage.classList.remove('displayingBackdropImage');
} }
var instance = new Backdrop(); const instance = new Backdrop();
instance.load(url, elem, existingBackdropImage); instance.load(url, elem, existingBackdropImage);
currentLoadingBackdrop = instance; currentLoadingBackdrop = instance;
} }
@ -176,9 +177,9 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
function getItemImageUrls(item, imageOptions) { function getItemImageUrls(item, imageOptions) {
imageOptions = imageOptions || {}; imageOptions = imageOptions || {};
var apiClient = connectionManager.getApiClient(item.ServerId); const apiClient = connectionManager.getApiClient(item.ServerId);
if (item.BackdropImageTags && item.BackdropImageTags.length > 0) { if (item.BackdropImageTags && item.BackdropImageTags.length > 0) {
return item.BackdropImageTags.map(function (imgTag, index) { return item.BackdropImageTags.map((imgTag, index) => {
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, { return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
type: 'Backdrop', type: 'Backdrop',
tag: imgTag, tag: imgTag,
@ -189,7 +190,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
} }
if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
return item.ParentBackdropImageTags.map(function (imgTag, index) { return item.ParentBackdropImageTags.map((imgTag, index) => {
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, { return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
type: 'Backdrop', type: 'Backdrop',
tag: imgTag, tag: imgTag,
@ -203,13 +204,13 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
} }
function getImageUrls(items, imageOptions) { function getImageUrls(items, imageOptions) {
var list = []; const list = [];
var onImg = function (img) { const onImg = img => {
list.push(img); list.push(img);
}; };
for (var i = 0, length = items.length; i < length; i++) { for (let i = 0, length = items.length; i < length; i++) {
var itemImages = getItemImageUrls(items[i], imageOptions); const itemImages = getItemImageUrls(items[i], imageOptions);
itemImages.forEach(onImg); itemImages.forEach(onImg);
} }
@ -229,7 +230,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
// If you don't care about the order of the elements inside // If you don't care about the order of the elements inside
// the array, you should sort both arrays here. // the array, you should sort both arrays here.
for (var i = 0; i < a.length; ++i) { for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) { if (a[i] !== b[i]) {
return false; return false;
} }
@ -242,12 +243,12 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
return userSettings.enableBackdrops(); return userSettings.enableBackdrops();
} }
var rotationInterval; let rotationInterval;
var currentRotatingImages = []; let currentRotatingImages = [];
var currentRotationIndex = -1; let currentRotationIndex = -1;
function setBackdrops(items, imageOptions, enableImageRotation) { export function setBackdrops(items, imageOptions, enableImageRotation) {
if (enabled()) { if (enabled()) {
var images = getImageUrls(items, imageOptions); const images = getImageUrls(items, imageOptions);
if (images.length) { if (images.length) {
startRotation(images, enableImageRotation); startRotation(images, enableImageRotation);
@ -279,7 +280,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
return; return;
} }
var newIndex = currentRotationIndex + 1; let newIndex = currentRotationIndex + 1;
if (newIndex >= currentRotatingImages.length) { if (newIndex >= currentRotatingImages.length) {
newIndex = 0; newIndex = 0;
} }
@ -289,7 +290,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
} }
function clearRotation() { function clearRotation() {
var interval = rotationInterval; const interval = rotationInterval;
if (interval) { if (interval) {
clearInterval(interval); clearInterval(interval);
} }
@ -299,7 +300,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
currentRotationIndex = -1; currentRotationIndex = -1;
} }
function setBackdrop(url, imageOptions) { export function setBackdrop(url, imageOptions) {
if (url && typeof url !== 'string') { if (url && typeof url !== 'string') {
url = getImageUrls([url], imageOptions)[0]; url = getImageUrls([url], imageOptions)[0];
} }
@ -312,10 +313,11 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
} }
} }
return { /* eslint-enable indent */
setBackdrops: setBackdrops,
setBackdrop: setBackdrop, export default {
clear: clearBackdrop, setBackdrops: setBackdrops,
externalBackdrop: externalBackdrop setBackdrop: setBackdrop,
}; clearBackdrop: clearBackdrop,
}); externalBackdrop: externalBackdrop
};

View file

@ -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;
}
};
};
});

View file

@ -167,8 +167,9 @@ button::-moz-focus-inner {
position: relative; position: relative;
background-clip: content-box !important; background-clip: content-box !important;
color: inherit; color: inherit;
}
/* This is only needed for scalable cards */ .cardScalable .cardImageContainer {
height: 100%; height: 100%;
contain: strict; contain: strict;
} }
@ -192,9 +193,14 @@ button::-moz-focus-inner {
/* Needed in case this is a button */ /* Needed in case this is a button */
display: block; display: block;
/* Needed in case this is a button */
margin: 0 !important; margin: 0 !important;
border: 0 !important;
padding: 0 !important;
cursor: pointer;
color: inherit;
width: 100%;
font-family: inherit;
font-size: inherit;
/* Needed in safari */ /* Needed in safari */
height: 100%; height: 100%;
@ -203,19 +209,12 @@ button::-moz-focus-inner {
contain: strict; contain: strict;
} }
.cardContent-button { .cardContent:not(.defaultCardBackground) {
border: 0 !important; background-color: transparent;
padding: 0 !important;
cursor: pointer;
color: inherit;
width: 100%;
vertical-align: middle;
font-family: inherit;
font-size: inherit;
} }
.cardContent-button:not(.defaultCardBackground) { .cardBox:not(.visualCardBox) .cardPadder {
background-color: transparent; background-color: #242424;
} }
.visualCardBox .cardContent { .visualCardBox .cardContent {
@ -223,7 +222,8 @@ button::-moz-focus-inner {
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
} }
.cardContent-shadow { .cardContent-shadow,
.cardBox:not(.visualCardBox) .cardPadder {
box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37);
} }
@ -306,6 +306,10 @@ button::-moz-focus-inner {
text-align: left; text-align: left;
} }
.dialog .cardText {
text-overflow: initial;
}
.cardText-secondary { .cardText-secondary {
font-size: 86%; font-size: 86%;
} }

View file

@ -277,7 +277,7 @@ import 'programStyles';
*/ */
function getImageWidth(shape, screenWidth, isOrientationLandscape) { function getImageWidth(shape, screenWidth, isOrientationLandscape) {
const imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape); const imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape);
return Math.round(screenWidth / imagesPerRow) * 2; return Math.round(screenWidth / imagesPerRow);
} }
/** /**
@ -291,12 +291,10 @@ import 'programStyles';
const primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items); const primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items);
if (['auto', 'autohome', 'autooverflow', 'autoVertical'].includes(options.shape)) { if (['auto', 'autohome', 'autooverflow', 'autoVertical'].includes(options.shape)) {
const requestedShape = options.shape; const requestedShape = options.shape;
options.shape = null; options.shape = null;
if (primaryImageAspectRatio) { if (primaryImageAspectRatio) {
if (primaryImageAspectRatio >= 3) { if (primaryImageAspectRatio >= 3) {
options.shape = 'banner'; options.shape = 'banner';
options.coverImage = true; options.coverImage = true;
@ -368,9 +366,7 @@ import 'programStyles';
let apiClient; let apiClient;
let lastServerId; let lastServerId;
for (let i = 0; i < items.length; i++) { for (const [i, item] of items.entries()) {
let item = items[i];
let serverId = item.ServerId || options.serverId; let serverId = item.ServerId || options.serverId;
if (serverId !== lastServerId) { if (serverId !== lastServerId) {
@ -396,7 +392,6 @@ import 'programStyles';
} }
if (newIndexValue !== currentIndexValue) { if (newIndexValue !== currentIndexValue) {
if (hasOpenRow) { if (hasOpenRow) {
html += '</div>'; html += '</div>';
hasOpenRow = false; hasOpenRow = false;
@ -404,7 +399,6 @@ import 'programStyles';
} }
if (hasOpenSection) { if (hasOpenSection) {
html += '</div>'; html += '</div>';
if (isVertical) { if (isVertical) {
@ -428,7 +422,6 @@ import 'programStyles';
} }
if (options.rows && itemsInRow === 0) { if (options.rows && itemsInRow === 0) {
if (hasOpenRow) { if (hasOpenRow) {
html += '</div>'; html += '</div>';
hasOpenRow = false; hasOpenRow = false;
@ -503,94 +496,49 @@ import 'programStyles';
const primaryImageAspectRatio = item.PrimaryImageAspectRatio; const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
let forceName = false; let forceName = false;
let imgUrl = null; let imgUrl = null;
let imgTag = null;
let coverImage = false; let coverImage = false;
let uiAspect = null; let uiAspect = null;
let imgType = null;
let itemId = null;
if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Thumb;
type: 'Thumb',
maxWidth: width,
tag: item.ImageTags.Thumb
});
} else if ((options.preferBanner || shape === 'banner') && item.ImageTags && item.ImageTags.Banner) { } else if ((options.preferBanner || shape === 'banner') && item.ImageTags && item.ImageTags.Banner) {
imgType = 'Banner';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Banner;
type: 'Banner',
maxWidth: width,
tag: item.ImageTags.Banner
});
} else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) { } else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) {
imgType = 'Disc';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Disc;
type: 'Disc',
maxWidth: width,
tag: item.ImageTags.Disc
});
} else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) { } else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) {
imgType = 'Logo';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Logo;
type: 'Logo',
maxWidth: width,
tag: item.ImageTags.Logo
});
} else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) { } else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) {
imgType = 'Logo';
imgUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { imgTag = item.ParentLogoImageTag;
type: 'Logo', itemId = item.ParentLogoItemId;
maxWidth: width,
tag: item.ParentLogoImageTag
});
} else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) { } else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { imgTag = item.SeriesThumbImageTag;
type: 'Thumb', itemId = item.SeriesId;
maxWidth: width,
tag: item.SeriesThumbImageTag
});
} else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false && item.MediaType !== 'Photo') { } else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false && item.MediaType !== 'Photo') {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { imgTag = item.ParentThumbImageTag;
type: 'Thumb', itemId = item.ParentThumbItemId;
maxWidth: width,
tag: item.ParentThumbImageTag
});
} else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) { } else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) {
imgType = 'Backdrop';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.BackdropImageTags[0];
type: 'Backdrop',
maxWidth: width,
tag: item.BackdropImageTags[0]
});
forceName = true; forceName = true;
} else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') { } else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') {
imgType = 'Backdrop';
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { imgTag = item.ParentBackdropImageTags[0];
type: 'Backdrop', itemId = item.ParentBackdropItemId;
maxWidth: width, } else if (item.ImageTags && item.ImageTags.Primary && (item.Type !== 'Episode' || item.ChildCount !== 0)) {
tag: item.ParentBackdropImageTags[0] imgType = 'Primary';
}); imgTag = item.ImageTags.Primary;
} else if (item.ImageTags && item.ImageTags.Primary) {
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
imgUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Primary',
maxHeight: height,
maxWidth: width,
tag: item.ImageTags.Primary
});
if (options.preferThumb && options.showTitle !== false) { if (options.preferThumb && options.showTitle !== false) {
forceName = true; forceName = true;
} }
@ -601,18 +549,16 @@ import 'programStyles';
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2; coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
} }
} }
} else if (item.SeriesPrimaryImageTag) {
imgType = 'Primary';
imgTag = item.SeriesPrimaryImageTag;
itemId = item.SeriesId;
} else if (item.PrimaryImageTag) { } else if (item.PrimaryImageTag) {
imgType = 'Primary';
imgTag = item.PrimaryImageTag;
itemId = item.PrimaryImageItemId;
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
imgUrl = apiClient.getScaledImageUrl(item.PrimaryImageItemId || item.Id || item.ItemId, {
type: 'Primary',
maxHeight: height,
maxWidth: width,
tag: item.PrimaryImageTag
});
if (options.preferThumb && options.showTitle !== false) { if (options.preferThumb && options.showTitle !== false) {
forceName = true; forceName = true;
} }
@ -624,30 +570,15 @@ import 'programStyles';
} }
} }
} else if (item.ParentPrimaryImageTag) { } else if (item.ParentPrimaryImageTag) {
imgType = 'Primary';
imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, { imgTag = item.ParentPrimaryImageTag;
type: 'Primary', itemId = item.ParentPrimaryImageItemId;
maxWidth: width,
tag: item.ParentPrimaryImageTag
});
} 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) {
imgType = 'Primary';
imgTag = item.AlbumPrimaryImageTag;
itemId = item.AlbumId;
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
imgUrl = apiClient.getScaledImageUrl(item.AlbumId, {
type: 'Primary',
maxHeight: height,
maxWidth: width,
tag: item.AlbumPrimaryImageTag
});
if (primaryImageAspectRatio) { if (primaryImageAspectRatio) {
uiAspect = getDesiredAspect(shape); uiAspect = getDesiredAspect(shape);
if (uiAspect) { if (uiAspect) {
@ -655,57 +586,46 @@ import 'programStyles';
} }
} }
} else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) { } else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Thumb;
type: 'Thumb',
maxWidth: width,
tag: item.ImageTags.Thumb
});
} else if (item.BackdropImageTags && item.BackdropImageTags.length) { } else if (item.BackdropImageTags && item.BackdropImageTags.length) {
imgType = 'Backdrop';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.BackdropImageTags[0];
type: 'Backdrop',
maxWidth: width,
tag: item.BackdropImageTags[0]
});
} else if (item.ImageTags && item.ImageTags.Thumb) { } else if (item.ImageTags && item.ImageTags.Thumb) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.Id, { imgTag = item.ImageTags.Thumb;
type: 'Thumb',
maxWidth: width,
tag: item.ImageTags.Thumb
});
} else if (item.SeriesThumbImageTag && options.inheritThumb !== false) { } else if (item.SeriesThumbImageTag && options.inheritThumb !== false) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { imgTag = item.SeriesThumbImageTag;
type: 'Thumb', itemId = item.SeriesId;
maxWidth: width,
tag: item.SeriesThumbImageTag
});
} else if (item.ParentThumbItemId && options.inheritThumb !== false) { } else if (item.ParentThumbItemId && options.inheritThumb !== false) {
imgType = 'Thumb';
imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { imgTag = item.ParentThumbImageTag;
type: 'Thumb', itemId = item.ParentThumbItemId;
maxWidth: width,
tag: item.ParentThumbImageTag
});
} else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) { } else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) {
imgType = 'Backdrop';
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { imgTag = item.ParentBackdropImageTags[0];
type: 'Backdrop', itemId = item.ParentBackdropItemId;
maxWidth: width,
tag: item.ParentBackdropImageTags[0]
});
} }
if (!itemId) {
itemId = item.Id;
}
if (imgTag && imgType) {
imgUrl = apiClient.getScaledImageUrl(itemId, {
type: imgType,
maxHeight: height,
maxWidth: width,
tag: imgTag
});
}
let blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {};
return { return {
imgUrl: imgUrl, imgUrl: imgUrl,
blurhash: (blurHashes[imgType] || {})[imgTag],
forceName: forceName, forceName: forceName,
coverImage: coverImage coverImage: coverImage
}; };
@ -761,7 +681,6 @@ import 'programStyles';
let valid = 0; let valid = 0;
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
let currentCssClass = cssClass; let currentCssClass = cssClass;
let text = lines[i]; let text = lines[i];
@ -788,7 +707,6 @@ import 'programStyles';
} }
if (forceLines) { if (forceLines) {
let linesLength = maxLines || Math.min(lines.length, maxLines || lines.length); let linesLength = maxLines || Math.min(lines.length, maxLines || lines.length);
while (valid < linesLength) { while (valid < linesLength) {
@ -820,7 +738,6 @@ import 'programStyles';
let airTimeText = ''; let airTimeText = '';
if (item.StartDate) { if (item.StartDate) {
try { try {
let date = datetime.parseISO8601Date(item.StartDate); let date = datetime.parseISO8601Date(item.StartDate);
@ -867,9 +784,8 @@ import 'programStyles';
const showOtherText = isOuterFooter ? !overlayText : overlayText; const showOtherText = isOuterFooter ? !overlayText : overlayText;
if (isOuterFooter && options.cardLayout && layoutManager.mobile) { if (isOuterFooter && options.cardLayout && layoutManager.mobile) {
if (options.cardFooterAside !== 'none') { if (options.cardFooterAside !== 'none') {
html += '<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu"><span class="material-icons more_horiz"></span></button>'; html += '<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu"><span class="material-icons more_vert"></span></button>';
} }
} }
@ -882,9 +798,7 @@ import 'programStyles';
if (showOtherText) { if (showOtherText) {
if ((options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) { if ((options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) {
if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) { if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) {
if (item.SeriesId) { if (item.SeriesId) {
lines.push(getTextActionButton({ lines.push(getTextActionButton({
Id: item.SeriesId, Id: item.SeriesId,
@ -897,15 +811,12 @@ import 'programStyles';
lines.push(item.SeriesName); lines.push(item.SeriesName);
} }
} else { } else {
if (isUsingLiveTvNaming(item)) { if (isUsingLiveTvNaming(item)) {
lines.push(item.Name); lines.push(item.Name);
if (!item.EpisodeTitle) { if (!item.EpisodeTitle) {
titleAdded = true; titleAdded = true;
} }
} else { } else {
const parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || ''; const parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || '';
@ -923,7 +834,6 @@ import 'programStyles';
} }
if (showMediaTitle) { if (showMediaTitle) {
const name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, { const name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, {
includeParentInfo: options.includeParentInfoInTitle includeParentInfo: options.includeParentInfoInTitle
}); });
@ -940,7 +850,6 @@ import 'programStyles';
if (showOtherText) { if (showOtherText) {
if (options.showParentTitle && parentTitleUnderneath) { if (options.showParentTitle && parentTitleUnderneath) {
if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) { if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) {
item.AlbumArtists[0].Type = 'MusicArtist'; item.AlbumArtists[0].Type = 'MusicArtist';
item.AlbumArtists[0].IsFolder = true; item.AlbumArtists[0].IsFolder = true;
@ -974,7 +883,6 @@ import 'programStyles';
} }
if (options.showPremiereDate) { if (options.showPremiereDate) {
if (item.PremiereDate) { if (item.PremiereDate) {
try { try {
lines.push(datetime.toLocaleDateString( lines.push(datetime.toLocaleDateString(
@ -983,7 +891,6 @@ import 'programStyles';
)); ));
} catch (err) { } catch (err) {
lines.push(''); lines.push('');
} }
} else { } else {
lines.push(''); lines.push('');
@ -991,14 +898,10 @@ import 'programStyles';
} }
if (options.showYear || options.showSeriesYear) { if (options.showYear || options.showSeriesYear) {
if (item.Type === 'Series') { if (item.Type === 'Series') {
if (item.Status === 'Continuing') { if (item.Status === 'Continuing') {
lines.push(globalize.translate('SeriesYearToPresent', item.ProductionYear || '')); lines.push(globalize.translate('SeriesYearToPresent', item.ProductionYear || ''));
} else { } else {
if (item.EndDate && item.ProductionYear) { if (item.EndDate && item.ProductionYear) {
const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear(); const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
lines.push(item.ProductionYear + ((endYear === item.ProductionYear) ? '' : (' - ' + endYear))); lines.push(item.ProductionYear + ((endYear === item.ProductionYear) ? '' : (' - ' + endYear)));
@ -1012,9 +915,7 @@ import 'programStyles';
} }
if (options.showRuntime) { if (options.showRuntime) {
if (item.RunTimeTicks) { if (item.RunTimeTicks) {
lines.push(datetime.getDisplayRunningTime(item.RunTimeTicks)); lines.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
} else { } else {
lines.push(''); lines.push('');
@ -1022,14 +923,11 @@ import 'programStyles';
} }
if (options.showAirTime) { if (options.showAirTime) {
lines.push(getAirTimeText(item, options.showAirDateTime, options.showAirEndTime) || ''); lines.push(getAirTimeText(item, options.showAirDateTime, options.showAirEndTime) || '');
} }
if (options.showChannelName) { if (options.showChannelName) {
if (item.ChannelId) { if (item.ChannelId) {
lines.push(getTextActionButton({ lines.push(getTextActionButton({
Id: item.ChannelId, Id: item.ChannelId,
@ -1046,7 +944,6 @@ import 'programStyles';
} }
if (options.showCurrentProgram && item.Type === 'TvChannel') { if (options.showCurrentProgram && item.Type === 'TvChannel') {
if (item.CurrentProgram) { if (item.CurrentProgram) {
lines.push(item.CurrentProgram.Name); lines.push(item.CurrentProgram.Name);
} else { } else {
@ -1055,7 +952,6 @@ import 'programStyles';
} }
if (options.showCurrentProgramTime && item.Type === 'TvChannel') { if (options.showCurrentProgramTime && item.Type === 'TvChannel') {
if (item.CurrentProgram) { if (item.CurrentProgram) {
lines.push(getAirTimeText(item.CurrentProgram, false, true) || ''); lines.push(getAirTimeText(item.CurrentProgram, false, true) || '');
} else { } else {
@ -1065,7 +961,6 @@ import 'programStyles';
if (options.showSeriesTimerTime) { if (options.showSeriesTimerTime) {
if (item.RecordAnyTime) { if (item.RecordAnyTime) {
lines.push(globalize.translate('Anytime')); lines.push(globalize.translate('Anytime'));
} else { } else {
lines.push(datetime.getDisplayTime(item.StartDate)); lines.push(datetime.getDisplayTime(item.StartDate));
@ -1100,7 +995,6 @@ import 'programStyles';
} }
if (html) { if (html) {
if (!isOuterFooter || logoUrl || options.cardLayout) { if (!isOuterFooter || logoUrl || options.cardLayout) {
html = '<div class="' + footerClass + '">' + html; html = '<div class="' + footerClass + '">' + html;
@ -1146,27 +1040,21 @@ import 'programStyles';
let childText; let childText;
if (item.Type === 'Playlist') { if (item.Type === 'Playlist') {
childText = ''; childText = '';
if (item.RunTimeTicks) { if (item.RunTimeTicks) {
let minutes = item.RunTimeTicks / 600000000; let minutes = item.RunTimeTicks / 600000000;
minutes = minutes || 1; minutes = minutes || 1;
childText += globalize.translate('ValueMinutes', Math.round(minutes)); childText += globalize.translate('ValueMinutes', Math.round(minutes));
} else { } else {
childText += globalize.translate('ValueMinutes', 0); childText += globalize.translate('ValueMinutes', 0);
} }
counts.push(childText); counts.push(childText);
} else if (item.Type === 'Genre' || item.Type === 'Studio') { } else if (item.Type === 'Genre' || item.Type === 'Studio') {
if (item.MovieCount) { if (item.MovieCount) {
childText = item.MovieCount === 1 ? childText = item.MovieCount === 1 ?
globalize.translate('ValueOneMovie') : globalize.translate('ValueOneMovie') :
globalize.translate('ValueMovieCount', item.MovieCount); globalize.translate('ValueMovieCount', item.MovieCount);
@ -1175,7 +1063,6 @@ import 'programStyles';
} }
if (item.SeriesCount) { if (item.SeriesCount) {
childText = item.SeriesCount === 1 ? childText = item.SeriesCount === 1 ?
globalize.translate('ValueOneSeries') : globalize.translate('ValueOneSeries') :
globalize.translate('ValueSeriesCount', item.SeriesCount); globalize.translate('ValueSeriesCount', item.SeriesCount);
@ -1183,18 +1070,14 @@ import 'programStyles';
counts.push(childText); counts.push(childText);
} }
if (item.EpisodeCount) { if (item.EpisodeCount) {
childText = item.EpisodeCount === 1 ? childText = item.EpisodeCount === 1 ?
globalize.translate('ValueOneEpisode') : globalize.translate('ValueOneEpisode') :
globalize.translate('ValueEpisodeCount', item.EpisodeCount); globalize.translate('ValueEpisodeCount', item.EpisodeCount);
counts.push(childText); counts.push(childText);
} }
} else if (item.Type === 'MusicGenre' || options.context === 'MusicArtist') { } else if (item.Type === 'MusicGenre' || options.context === 'MusicArtist') {
if (item.AlbumCount) { if (item.AlbumCount) {
childText = item.AlbumCount === 1 ? childText = item.AlbumCount === 1 ?
globalize.translate('ValueOneAlbum') : globalize.translate('ValueOneAlbum') :
globalize.translate('ValueAlbumCount', item.AlbumCount); globalize.translate('ValueAlbumCount', item.AlbumCount);
@ -1202,7 +1085,6 @@ import 'programStyles';
counts.push(childText); counts.push(childText);
} }
if (item.SongCount) { if (item.SongCount) {
childText = item.SongCount === 1 ? childText = item.SongCount === 1 ?
globalize.translate('ValueOneSong') : globalize.translate('ValueOneSong') :
globalize.translate('ValueSongCount', item.SongCount); globalize.translate('ValueSongCount', item.SongCount);
@ -1210,16 +1092,13 @@ import 'programStyles';
counts.push(childText); counts.push(childText);
} }
if (item.MusicVideoCount) { if (item.MusicVideoCount) {
childText = item.MusicVideoCount === 1 ? childText = item.MusicVideoCount === 1 ?
globalize.translate('ValueOneMusicVideo') : globalize.translate('ValueOneMusicVideo') :
globalize.translate('ValueMusicVideoCount', item.MusicVideoCount); globalize.translate('ValueMusicVideoCount', item.MusicVideoCount);
counts.push(childText); counts.push(childText);
} }
} else if (item.Type === 'Series') { } else if (item.Type === 'Series') {
childText = item.RecursiveItemCount === 1 ? childText = item.RecursiveItemCount === 1 ?
globalize.translate('ValueOneEpisode') : globalize.translate('ValueOneEpisode') :
globalize.translate('ValueEpisodeCount', item.RecursiveItemCount); globalize.translate('ValueEpisodeCount', item.RecursiveItemCount);
@ -1235,10 +1114,11 @@ import 'programStyles';
/** /**
* Imports the refresh indicator element. * Imports the refresh indicator element.
*/ */
function requireRefreshIndicator() { function importRefreshIndicator() {
if (!refreshIndicatorLoaded) { if (!refreshIndicatorLoaded) {
refreshIndicatorLoaded = true; refreshIndicatorLoaded = true;
require(['emby-itemrefreshindicator']); /* eslint-disable-next-line no-unused-expressions */
import('emby-itemrefreshindicator');
} }
} }
@ -1272,13 +1152,11 @@ import 'programStyles';
let shape = options.shape; let shape = options.shape;
if (shape === 'mixed') { if (shape === 'mixed') {
shape = null; shape = null;
const primaryImageAspectRatio = item.PrimaryImageAspectRatio; const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
if (primaryImageAspectRatio) { if (primaryImageAspectRatio) {
if (primaryImageAspectRatio >= 1.33) { if (primaryImageAspectRatio >= 1.33) {
shape = 'mixedBackdrop'; shape = 'mixedBackdrop';
} else if (primaryImageAspectRatio > 0.71) { } else if (primaryImageAspectRatio > 0.71) {
@ -1321,6 +1199,7 @@ import 'programStyles';
const imgInfo = getCardImageUrl(item, apiClient, options, shape); const imgInfo = getCardImageUrl(item, apiClient, options, shape);
const imgUrl = imgInfo.imgUrl; const imgUrl = imgInfo.imgUrl;
const blurhash = imgInfo.blurhash;
const forceName = imgInfo.forceName; const forceName = imgInfo.forceName;
@ -1369,7 +1248,6 @@ import 'programStyles';
} }
if (overlayText) { if (overlayText) {
logoUrl = null; logoUrl = null;
footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter'; footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter';
@ -1384,7 +1262,7 @@ import 'programStyles';
} }
const mediaSourceCount = item.MediaSourceCount || 1; const mediaSourceCount = item.MediaSourceCount || 1;
if (mediaSourceCount > 1) { if (mediaSourceCount > 1 && options.disableIndicators !== true) {
innerCardFooter += '<div class="mediaSourceIndicator">' + mediaSourceCount + '</div>'; innerCardFooter += '<div class="mediaSourceIndicator">' + mediaSourceCount + '</div>';
} }
@ -1426,7 +1304,7 @@ import 'programStyles';
} }
if (options.overlayMoreButton) { if (options.overlayMoreButton) {
overlayButtons += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><span class="material-icons cardOverlayButtonIcon more_horiz"></span></button>'; overlayButtons += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><span class="material-icons cardOverlayButtonIcon more_vert"></span></button>';
} }
} }
@ -1441,57 +1319,59 @@ import 'programStyles';
let cardScalableClose = ''; let cardScalableClose = '';
let cardContentClass = 'cardContent'; let cardContentClass = 'cardContent';
if (!options.cardLayout) {
cardContentClass += ' cardContent-shadow'; let blurhashAttrib = '';
if (blurhash && blurhash.length > 0) {
blurhashAttrib = 'data-blurhash="' + blurhash + '"';
} }
if (layoutManager.tv) { if (layoutManager.tv) {
// Don't use the IMG tag with safari because it puts a white border around it // Don't use the IMG tag with safari because it puts a white border around it
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + '">'); cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + ' lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + '">');
cardImageContainerClose = '</div>'; cardImageContainerClose = '</div>';
} else { } else {
// Don't use the IMG tag with safari because it puts a white border around it // Don't use the IMG tag with safari because it puts a white border around it
cardImageContainerOpen = imgUrl ? ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction lazy" data-src="' + imgUrl + '">') : ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction">'); cardImageContainerOpen = imgUrl ? ('<button data-action="' + action + '" class="' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<button data-action="' + action + '" class="' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction">');
cardImageContainerClose = '</button>'; cardImageContainerClose = '</button>';
} }
let cardScalableClass = 'cardScalable'; let cardScalableClass = 'cardScalable';
cardImageContainerOpen = '<div class="' + cardBoxClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainerOpen; cardImageContainerOpen = '<div class="' + cardBoxClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder cardPadder-' + shape + '"></div>' + cardImageContainerOpen;
cardBoxClose = '</div>'; cardBoxClose = '</div>';
cardScalableClose = '</div>'; cardScalableClose = '</div>';
let indicatorsHtml = ''; if (options.disableIndicators !== true) {
let indicatorsHtml = '';
if (options.missingIndicator !== false) { if (options.missingIndicator !== false) {
indicatorsHtml += indicators.getMissingIndicator(item); indicatorsHtml += indicators.getMissingIndicator(item);
} }
indicatorsHtml += indicators.getSyncIndicator(item); indicatorsHtml += indicators.getSyncIndicator(item);
indicatorsHtml += indicators.getTimerIndicator(item); indicatorsHtml += indicators.getTimerIndicator(item);
indicatorsHtml += indicators.getTypeIndicator(item); indicatorsHtml += indicators.getTypeIndicator(item);
if (options.showGroupCount) { if (options.showGroupCount) {
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, {
minCount: 1
});
} else {
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
}
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, { if (item.Type === 'CollectionFolder' || item.CollectionType) {
minCount: 1 const refreshClass = item.RefreshProgress ? '' : ' class="hide"';
}); indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>';
} else { importRefreshIndicator();
indicatorsHtml += indicators.getPlayedIndicatorHtml(item); }
}
if (item.Type === 'CollectionFolder' || item.CollectionType) { if (indicatorsHtml) {
const refreshClass = item.RefreshProgress ? '' : ' class="hide"'; cardImageContainerOpen += '<div class="cardIndicators">' + indicatorsHtml + '</div>';
indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>'; }
requireRefreshIndicator();
}
if (indicatorsHtml) {
cardImageContainerOpen += '<div class="cardIndicators">' + indicatorsHtml + '</div>';
} }
if (!imgUrl) { if (!imgUrl) {
@ -1539,8 +1419,8 @@ import 'programStyles';
let additionalCardContent = ''; let additionalCardContent = '';
if (layoutManager.desktop) { if (layoutManager.desktop && !options.disableHoverMenu) {
additionalCardContent += getHoverMenuHtml(item, action); additionalCardContent += getHoverMenuHtml(item, action, options);
} }
return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + '</' + tagName + '>'; return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + '</' + tagName + '>';
@ -1550,9 +1430,10 @@ import 'programStyles';
* Generates HTML markup for the card overlay. * Generates HTML markup for the card overlay.
* @param {object} item - Item used to generate the card overlay. * @param {object} item - Item used to generate the card overlay.
* @param {string} action - Action assigned to the overlay. * @param {string} action - Action assigned to the overlay.
* @param {Array} options - Card builder options.
* @returns {string} HTML markup of the card overlay. * @returns {string} HTML markup of the card overlay.
*/ */
function getHoverMenuHtml(item, action) { function getHoverMenuHtml(item, action, options) {
let html = ''; let html = '';
html += '<div class="cardOverlayContainer itemAction" data-action="' + action + '">'; html += '<div class="cardOverlayContainer itemAction" data-action="' + action + '">';
@ -1568,20 +1449,20 @@ import 'programStyles';
const userData = item.UserData || {}; const userData = item.UserData || {};
if (itemHelper.canMarkPlayed(item)) { if (itemHelper.canMarkPlayed(item)) {
require(['emby-playstatebutton']); /* eslint-disable-next-line no-unused-expressions */
import('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) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover check"></span></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) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover check"></span></button>';
} }
if (itemHelper.canRate(item)) { if (itemHelper.canRate(item)) {
const likes = userData.Likes == null ? '' : userData.Likes; const likes = userData.Likes == null ? '' : userData.Likes;
require(['emby-ratingbutton']); /* eslint-disable-next-line no-unused-expressions */
import('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) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover favorite"></span></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) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover favorite"></span></button>';
} }
html += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover more_horiz"></span></button>'; html += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover more_vert"></span></button>';
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';
@ -1605,6 +1486,8 @@ import 'programStyles';
case 'MusicArtist': case 'MusicArtist':
case 'Person': case 'Person':
return '<span class="cardImageIcon material-icons person"></span>'; return '<span class="cardImageIcon material-icons person"></span>';
case 'Audio':
return '<span class="cardImageIcon material-icons audiotrack"></span>';
case 'Movie': case 'Movie':
return '<span class="cardImageIcon material-icons movie"></span>'; return '<span class="cardImageIcon material-icons movie"></span>';
case 'Series': case 'Series':
@ -1613,6 +1496,12 @@ import 'programStyles';
return '<span class="cardImageIcon material-icons book"></span>'; return '<span class="cardImageIcon material-icons book"></span>';
case 'Folder': case 'Folder':
return '<span class="cardImageIcon material-icons folder"></span>'; return '<span class="cardImageIcon material-icons folder"></span>';
case 'BoxSet':
return '<span class="cardImageIcon material-icons collections"></span>';
case 'Playlist':
return '<span class="cardImageIcon material-icons view_list"></span>';
case 'PhotoAlbum':
return '<span class="cardImageIcon material-icons photo_album"></span>';
} }
if (options && options.defaultCardImageIcon) { if (options && options.defaultCardImageIcon) {
@ -1646,7 +1535,6 @@ import 'programStyles';
const html = buildCardsHtmlInternal(items, options); const html = buildCardsHtmlInternal(items, options);
if (html) { if (html) {
if (options.itemsContainer.cardBuilderHtml !== html) { if (options.itemsContainer.cardBuilderHtml !== html) {
options.itemsContainer.innerHTML = html; options.itemsContainer.innerHTML = html;
@ -1659,7 +1547,6 @@ import 'programStyles';
imageLoader.lazyChildren(options.itemsContainer); imageLoader.lazyChildren(options.itemsContainer);
} else { } else {
options.itemsContainer.innerHTML = html; options.itemsContainer.innerHTML = html;
options.itemsContainer.cardBuilderHtml = null; options.itemsContainer.cardBuilderHtml = null;
} }
@ -1683,7 +1570,6 @@ import 'programStyles';
indicatorsElem = card.querySelector('.cardIndicators'); indicatorsElem = card.querySelector('.cardIndicators');
if (!indicatorsElem) { if (!indicatorsElem) {
const cardImageContainer = card.querySelector('.cardImageContainer'); const cardImageContainer = card.querySelector('.cardImageContainer');
indicatorsElem = document.createElement('div'); indicatorsElem = document.createElement('div');
indicatorsElem.classList.add('cardIndicators'); indicatorsElem.classList.add('cardIndicators');
@ -1707,11 +1593,9 @@ import 'programStyles';
let itemProgressBar = null; let itemProgressBar = null;
if (userData.Played) { if (userData.Played) {
playedIndicator = card.querySelector('.playedIndicator'); playedIndicator = card.querySelector('.playedIndicator');
if (!playedIndicator) { if (!playedIndicator) {
playedIndicator = document.createElement('div'); playedIndicator = document.createElement('div');
playedIndicator.classList.add('playedIndicator'); playedIndicator.classList.add('playedIndicator');
playedIndicator.classList.add('indicator'); playedIndicator.classList.add('indicator');
@ -1720,10 +1604,8 @@ import 'programStyles';
} }
playedIndicator.innerHTML = '<span class="material-icons indicatorIcon check"></span>'; playedIndicator.innerHTML = '<span class="material-icons indicatorIcon check"></span>';
} else { } else {
playedIndicator = card.querySelector('.playedIndicator'); playedIndicator = card.querySelector('.playedIndicator');
if (playedIndicator) { if (playedIndicator) {
playedIndicator.parentNode.removeChild(playedIndicator); playedIndicator.parentNode.removeChild(playedIndicator);
} }
} }
@ -1731,7 +1613,6 @@ import 'programStyles';
countIndicator = card.querySelector('.countIndicator'); countIndicator = card.querySelector('.countIndicator');
if (!countIndicator) { if (!countIndicator) {
countIndicator = document.createElement('div'); countIndicator = document.createElement('div');
countIndicator.classList.add('countIndicator'); countIndicator.classList.add('countIndicator');
indicatorsElem = ensureIndicators(card, indicatorsElem); indicatorsElem = ensureIndicators(card, indicatorsElem);
@ -1739,10 +1620,8 @@ import 'programStyles';
} }
countIndicator.innerHTML = userData.UnplayedItemCount; countIndicator.innerHTML = userData.UnplayedItemCount;
} else if (enableCountIndicator) { } else if (enableCountIndicator) {
countIndicator = card.querySelector('.countIndicator'); countIndicator = card.querySelector('.countIndicator');
if (countIndicator) { if (countIndicator) {
countIndicator.parentNode.removeChild(countIndicator); countIndicator.parentNode.removeChild(countIndicator);
} }
} }
@ -1754,7 +1633,6 @@ import 'programStyles';
}); });
if (progressHtml) { if (progressHtml) {
itemProgressBar = card.querySelector('.itemProgressBar'); itemProgressBar = card.querySelector('.itemProgressBar');
if (!itemProgressBar) { if (!itemProgressBar) {
@ -1773,7 +1651,6 @@ import 'programStyles';
itemProgressBar.innerHTML = progressHtml; itemProgressBar.innerHTML = progressHtml;
} else { } else {
itemProgressBar = card.querySelector('.itemProgressBar'); itemProgressBar = card.querySelector('.itemProgressBar');
if (itemProgressBar) { if (itemProgressBar) {
itemProgressBar.parentNode.removeChild(itemProgressBar); itemProgressBar.parentNode.removeChild(itemProgressBar);

View file

@ -1,13 +1,22 @@
define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) { /* eslint-disable indent */
'use strict';
var enableFocusTransform = !browser.slow && !browser.edge; /**
* Module for building cards from item data.
* @module components/cardBuilder/chaptercardbuilder
*/
function buildChapterCardsHtml(item, chapters, options) { import datetime from 'datetime';
import imageLoader from 'imageLoader';
import connectionManager from 'connectionManager';
import layoutManager from 'layoutManager';
import browser from 'browser';
const enableFocusTransform = !browser.slow && !browser.edge;
function buildChapterCardsHtml(item, chapters, options) {
// TODO move card creation code to Card component // TODO move card creation code to Card component
var className = 'card itemAction chapterCard'; let className = 'card itemAction chapterCard';
if (layoutManager.tv) { if (layoutManager.tv) {
className += ' show-focus'; className += ' show-focus';
@ -17,38 +26,36 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
} }
} }
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || []; const mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [];
var videoStream = mediaStreams.filter(function (i) { const videoStream = mediaStreams.filter(({Type}) => {
return i.Type === 'Video'; return Type === 'Video';
})[0] || {}; })[0] || {};
var shape = (options.backdropShape || 'backdrop'); let shape = (options.backdropShape || 'backdrop');
if (videoStream.Width && videoStream.Height) { if (videoStream.Width && videoStream.Height) {
if ((videoStream.Width / videoStream.Height) <= 1.2) { if ((videoStream.Width / videoStream.Height) <= 1.2) {
shape = (options.squareShape || 'square'); shape = (options.squareShape || 'square');
} }
} }
className += ' ' + shape + 'Card'; className += ` ${shape}Card`;
if (options.block || options.rows) { if (options.block || options.rows) {
className += ' block'; className += ' block';
} }
var html = ''; let html = '';
var itemsInRow = 0; let itemsInRow = 0;
var apiClient = connectionManager.getApiClient(item.ServerId); const apiClient = connectionManager.getApiClient(item.ServerId);
for (var i = 0, length = chapters.length; i < length; i++) {
for (let i = 0, length = chapters.length; i < length; i++) {
if (options.rows && itemsInRow === 0) { if (options.rows && itemsInRow === 0) {
html += '<div class="cardColumn">'; html += '<div class="cardColumn">';
} }
var chapter = chapters[i]; const chapter = chapters[i];
html += buildChapterCard(item, apiClient, chapter, i, options, className, shape); html += buildChapterCard(item, apiClient, chapter, i, options, className, shape);
itemsInRow++; itemsInRow++;
@ -62,51 +69,45 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
return html; return html;
} }
function getImgUrl(item, chapter, index, maxWidth, apiClient) { function getImgUrl({Id}, {ImageTag}, index, maxWidth, apiClient) {
if (ImageTag) {
return apiClient.getScaledImageUrl(Id, {
if (chapter.ImageTag) { maxWidth: maxWidth,
tag: ImageTag,
return apiClient.getScaledImageUrl(item.Id, {
maxWidth: maxWidth * 2,
tag: chapter.ImageTag,
type: 'Chapter', type: 'Chapter',
index: index index
}); });
} }
return null; return null;
} }
function buildChapterCard(item, apiClient, chapter, index, options, className, shape) { function buildChapterCard(item, apiClient, chapter, index, {width, coverImage}, className, shape) {
const imgUrl = getImgUrl(item, chapter, index, width || 400, apiClient);
var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient); let cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
if (coverImage) {
var cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
if (options.coverImage) {
cardImageContainerClass += ' coveredImage'; cardImageContainerClass += ' coveredImage';
} }
var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"'; const dataAttributes = ` data-action="play" data-isfolder="${item.IsFolder}" data-id="${item.Id}" data-serverid="${item.ServerId}" data-type="${item.Type}" data-mediatype="${item.MediaType}" data-positionticks="${chapter.StartPositionTicks}"`;
var cardImageContainer = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">'); let cardImageContainer = imgUrl ? (`<div class="${cardImageContainerClass} lazy" data-src="${imgUrl}">`) : (`<div class="${cardImageContainerClass}">`);
if (!imgUrl) { if (!imgUrl) {
cardImageContainer += '<span class="material-icons cardImageIcon local_movies"></span>'; cardImageContainer += '<span class="material-icons cardImageIcon local_movies"></span>';
} }
var nameHtml = ''; let nameHtml = '';
nameHtml += '<div class="cardText">' + chapter.Name + '</div>'; nameHtml += `<div class="cardText">${chapter.Name}</div>`;
nameHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + '</div>'; nameHtml += `<div class="cardText">${datetime.getDisplayRunningTime(chapter.StartPositionTicks)}</div>`;
var cardBoxCssClass = 'cardBox'; const cardBoxCssClass = 'cardBox';
var cardScalableClass = 'cardScalable'; const cardScalableClass = 'cardScalable';
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 `<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;
} }
function buildChapterCards(item, chapters, options) { export function buildChapterCards(item, chapters, options) {
if (options.parentContainer) { if (options.parentContainer) {
// Abort if the container has been disposed // Abort if the container has been disposed
if (!document.body.contains(options.parentContainer)) { if (!document.body.contains(options.parentContainer)) {
@ -121,15 +122,16 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
} }
} }
var html = buildChapterCardsHtml(item, chapters, options); const html = buildChapterCardsHtml(item, chapters, options);
options.itemsContainer.innerHTML = html; options.itemsContainer.innerHTML = html;
imageLoader.lazyChildren(options.itemsContainer); imageLoader.lazyChildren(options.itemsContainer);
} }
return { /* eslint-enable indent */
buildChapterCards: buildChapterCards
}; export default {
buildChapterCards: buildChapterCards
};
});

View file

@ -1,8 +1,13 @@
define(['cardBuilder'], function (cardBuilder) { /* eslint-disable indent */
'use strict';
function buildPeopleCards(items, options) { /**
* Module for building cards from item data.
* @module components/cardBuilder/peoplecardbuilder
*/
import cardBuilder from 'cardBuilder';
export function buildPeopleCards(items, options) {
options = Object.assign(options || {}, { options = Object.assign(options || {}, {
cardLayout: false, cardLayout: false,
centerText: true, centerText: true,
@ -15,8 +20,8 @@ define(['cardBuilder'], function (cardBuilder) {
cardBuilder.buildCards(items, options); cardBuilder.buildCards(items, options);
} }
return { /* eslint-enable indent */
buildPeopleCards: buildPeopleCards
};
}); export default {
buildPeopleCards: buildPeopleCards
};

View file

@ -1,10 +1,21 @@
define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'actionsheet', 'emby-input', 'paper-icon-button-light', 'emby-button', 'listViewStyle', 'material-icons', 'formDialogStyle'], function (dom, dialogHelper, loading, connectionManager, globalize, actionsheet) { import dom from 'dom';
'use strict'; import dialogHelper from 'dialogHelper';
import loading from 'loading';
import connectionManager from 'connectionManager';
import globalize from 'globalize';
import actionsheet from 'actionsheet';
import 'emby-input';
import 'paper-icon-button-light';
import 'emby-button';
import 'listViewStyle';
import 'material-icons';
import 'formDialogStyle';
return function (options) { export default class channelMapper {
constructor(options) {
function mapChannel(button, channelId, providerChannelId) { function mapChannel(button, channelId, providerChannelId) {
loading.show(); loading.show();
var providerId = options.providerId; const providerId = options.providerId;
connectionManager.getApiClient(options.serverId).ajax({ connectionManager.getApiClient(options.serverId).ajax({
type: 'POST', type: 'POST',
url: ApiClient.getUrl('LiveTv/ChannelMappings'), url: ApiClient.getUrl('LiveTv/ChannelMappings'),
@ -14,8 +25,8 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
providerChannelId: providerChannelId providerChannelId: providerChannelId
}, },
dataType: 'json' dataType: 'json'
}).then(function (mapping) { }).then(mapping => {
var listItem = dom.parentWithClass(button, 'listItem'); const listItem = dom.parentWithClass(button, 'listItem');
button.setAttribute('data-providerid', mapping.ProviderChannelId); button.setAttribute('data-providerid', mapping.ProviderChannelId);
listItem.querySelector('.secondary').innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName); listItem.querySelector('.secondary').innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName);
loading.hide(); loading.hide();
@ -23,42 +34,42 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
} }
function onChannelsElementClick(e) { function onChannelsElementClick(e) {
var btnMap = dom.parentWithClass(e.target, 'btnMap'); const btnMap = dom.parentWithClass(e.target, 'btnMap');
if (btnMap) { if (btnMap) {
var channelId = btnMap.getAttribute('data-id'); const channelId = btnMap.getAttribute('data-id');
var providerChannelId = btnMap.getAttribute('data-providerid'); const providerChannelId = btnMap.getAttribute('data-providerid');
var menuItems = currentMappingOptions.ProviderChannels.map(function (m) { const menuItems = currentMappingOptions.ProviderChannels.map(m => {
return { return {
name: m.Name, name: m.Name,
id: m.Id, id: m.Id,
selected: m.Id.toLowerCase() === providerChannelId.toLowerCase() selected: m.Id.toLowerCase() === providerChannelId.toLowerCase()
}; };
}).sort(function (a, b) { }).sort((a, b) => {
return a.name.localeCompare(b.name); return a.name.localeCompare(b.name);
}); });
actionsheet.show({ actionsheet.show({
positionTo: btnMap, positionTo: btnMap,
items: menuItems items: menuItems
}).then(function (newChannelId) { }).then(newChannelId => {
mapChannel(btnMap, channelId, newChannelId); mapChannel(btnMap, channelId, newChannelId);
}); });
} }
} }
function getChannelMappingOptions(serverId, providerId) { function getChannelMappingOptions(serverId, providerId) {
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
return apiClient.getJSON(apiClient.getUrl('LiveTv/ChannelMappingOptions', { return apiClient.getJSON(apiClient.getUrl('LiveTv/ChannelMappingOptions', {
providerId: providerId providerId: providerId
})); }));
} }
function getMappingSecondaryName(mapping, providerName) { function getMappingSecondaryName(mapping, providerName) {
return (mapping.ProviderChannelName || '') + ' - ' + providerName; return `${mapping.ProviderChannelName || ''} - ${providerName}`;
} }
function getTunerChannelHtml(channel, providerName) { function getTunerChannelHtml(channel, providerName) {
var html = ''; let html = '';
html += '<div class="listItem">'; html += '<div class="listItem">';
html += '<span class="material-icons listItemIcon dvr"></span>'; html += '<span class="material-icons listItemIcon dvr"></span>';
html += '<div class="listItemBody two-line">'; html += '<div class="listItemBody two-line">';
@ -73,16 +84,16 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';
html += '<button class="btnMap autoSize" is="paper-icon-button-light" type="button" data-id="' + channel.Id + '" data-providerid="' + channel.ProviderChannelId + '"><span class="material-icons mode_edit"></span></button>'; html += `<button class="btnMap autoSize" is="paper-icon-button-light" type="button" data-id="${channel.Id}" data-providerid="${channel.ProviderChannelId}"><span class="material-icons mode_edit"></span></button>`;
return html += '</div>'; return html += '</div>';
} }
function getEditorHtml() { function getEditorHtml() {
var html = ''; let html = '';
html += '<div class="formDialogContent">'; html += '<div class="formDialogContent smoothScrollY">';
html += '<div class="dialogContentInner dialog-content-centered">'; html += '<div class="dialogContentInner dialog-content-centered">';
html += '<form style="margin:auto;">'; html += '<form style="margin:auto;">';
html += '<h1>' + globalize.translate('HeaderChannels') + '</h1>'; html += `<h1>${globalize.translate('HeaderChannels')}</h1>`;
html += '<div class="channels paperList">'; html += '<div class="channels paperList">';
html += '</div>'; html += '</div>';
html += '</form>'; html += '</form>';
@ -91,30 +102,29 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
} }
function initEditor(dlg, options) { function initEditor(dlg, options) {
getChannelMappingOptions(options.serverId, options.providerId).then(function (result) { getChannelMappingOptions(options.serverId, options.providerId).then(result => {
currentMappingOptions = result; currentMappingOptions = result;
var channelsElement = dlg.querySelector('.channels'); const channelsElement = dlg.querySelector('.channels');
channelsElement.innerHTML = result.TunerChannels.map(function (channel) { channelsElement.innerHTML = result.TunerChannels.map(channel => {
return getTunerChannelHtml(channel, result.ProviderName); return getTunerChannelHtml(channel, result.ProviderName);
}).join(''); }).join('');
channelsElement.addEventListener('click', onChannelsElementClick); channelsElement.addEventListener('click', onChannelsElementClick);
}); });
} }
var currentMappingOptions; let currentMappingOptions;
var self = this;
self.show = function () { this.show = () => {
var dialogOptions = { const dialogOptions = {
removeOnClose: true removeOnClose: true
}; };
dialogOptions.size = 'small'; dialogOptions.size = 'small';
var dlg = dialogHelper.createDialog(dialogOptions); const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');
dlg.classList.add('ui-body-a'); dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a'); dlg.classList.add('background-theme-a');
var html = ''; let html = '';
var title = globalize.translate('MapChannels'); const title = globalize.translate('MapChannels');
html += '<div class="formDialogHeader">'; html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>'; html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">'; html += '<h3 class="formDialogHeaderTitle">';
@ -124,13 +134,13 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
html += getEditorHtml(); html += getEditorHtml();
dlg.innerHTML = html; dlg.innerHTML = html;
initEditor(dlg, options); initEditor(dlg, options);
dlg.querySelector('.btnCancel').addEventListener('click', function () { dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg); dialogHelper.close(dlg);
}); });
return new Promise(function (resolve, reject) { return new Promise(resolve => {
dlg.addEventListener('close', resolve); dlg.addEventListener('close', resolve);
dialogHelper.open(dlg); dialogHelper.open(dlg);
}); });
}; };
}; }
}); }

View file

@ -1,16 +1,31 @@
define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (dom, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) { import dom from 'dom';
'use strict'; import dialogHelper from 'dialogHelper';
import loading from 'loading';
import layoutManager from 'layoutManager';
import connectionManager from 'connectionManager';
import appRouter from 'appRouter';
import globalize from 'globalize';
import 'emby-checkbox';
import 'emby-input';
import 'paper-icon-button-light';
import 'emby-select';
import 'material-icons';
import 'css!./../formdialog';
import 'emby-button';
import 'flexStyles';
var currentServerId; /* eslint-disable indent */
let currentServerId;
function onSubmit(e) { function onSubmit(e) {
loading.show(); loading.show();
var panel = dom.parentWithClass(this, 'dialog'); const panel = dom.parentWithClass(this, 'dialog');
var collectionId = panel.querySelector('#selectCollectionToAddTo').value; const collectionId = panel.querySelector('#selectCollectionToAddTo').value;
var apiClient = connectionManager.getApiClient(currentServerId); const apiClient = connectionManager.getApiClient(currentServerId);
if (collectionId) { if (collectionId) {
addToCollection(apiClient, panel, collectionId); addToCollection(apiClient, panel, collectionId);
@ -23,8 +38,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
} }
function createCollection(apiClient, dlg) { function createCollection(apiClient, dlg) {
const url = apiClient.getUrl('Collections', {
var url = apiClient.getUrl('Collections', {
Name: dlg.querySelector('#txtNewCollectionName').value, Name: dlg.querySelector('#txtNewCollectionName').value,
IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked, IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked,
@ -36,27 +50,23 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
url: url, url: url,
dataType: 'json' dataType: 'json'
}).then(function (result) { }).then(result => {
loading.hide(); loading.hide();
var id = result.Id; const id = result.Id;
dlg.submitted = true; dlg.submitted = true;
dialogHelper.close(dlg); dialogHelper.close(dlg);
redirectToCollection(apiClient, id); redirectToCollection(apiClient, id);
}); });
} }
function redirectToCollection(apiClient, id) { function redirectToCollection(apiClient, id) {
appRouter.showItem(id, apiClient.serverId()); appRouter.showItem(id, apiClient.serverId());
} }
function addToCollection(apiClient, dlg, id) { function addToCollection(apiClient, dlg, id) {
const url = apiClient.getUrl(`Collections/${id}/Items`, {
var url = apiClient.getUrl('Collections/' + id + '/Items', {
Ids: dlg.querySelector('.fldSelectedItemIds').value || '' Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
}); });
@ -65,14 +75,13 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
type: 'POST', type: 'POST',
url: url url: url
}).then(function () { }).then(() => {
loading.hide(); loading.hide();
dlg.submitted = true; dlg.submitted = true;
dialogHelper.close(dlg); dialogHelper.close(dlg);
require(['toast'], function (toast) { import('toast').then(({default: toast}) => {
toast(globalize.translate('MessageItemsAdded')); toast(globalize.translate('MessageItemsAdded'));
}); });
}); });
@ -83,14 +92,13 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
} }
function populateCollections(panel) { function populateCollections(panel) {
loading.show(); loading.show();
var select = panel.querySelector('#selectCollectionToAddTo'); const select = panel.querySelector('#selectCollectionToAddTo');
panel.querySelector('.newCollectionInfo').classList.add('hide'); panel.querySelector('.newCollectionInfo').classList.add('hide');
var options = { const options = {
Recursive: true, Recursive: true,
IncludeItemTypes: 'BoxSet', IncludeItemTypes: 'BoxSet',
@ -98,16 +106,14 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
EnableTotalRecordCount: false EnableTotalRecordCount: false
}; };
var apiClient = connectionManager.getApiClient(currentServerId); const apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) { apiClient.getItems(apiClient.getCurrentUserId(), options).then(result => {
let html = '';
var html = ''; html += `<option value="">${globalize.translate('OptionNew')}</option>`;
html += '<option value="">' + globalize.translate('OptionNew') + '</option>'; html += result.Items.map(i => {
return `<option value="${i.Id}">${i.Name}</option>`;
html += result.Items.map(function (i) {
return '<option value="' + i.Id + '">' + i.Name + '</option>';
}); });
select.innerHTML = html; select.innerHTML = html;
@ -119,8 +125,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
} }
function getEditorHtml() { function getEditorHtml() {
let html = '';
var html = '';
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">'; html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
html += '<div class="dialogContentInner dialog-content-centered">'; html += '<div class="dialogContentInner dialog-content-centered">';
@ -134,27 +139,27 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
html += '<br/>'; html += '<br/>';
html += '<br/>'; html += '<br/>';
html += '<div class="selectContainer">'; html += '<div class="selectContainer">';
html += '<select is="emby-select" label="' + globalize.translate('LabelCollection') + '" id="selectCollectionToAddTo" autofocus></select>'; html += `<select is="emby-select" label="${globalize.translate('LabelCollection')}" id="selectCollectionToAddTo" autofocus></select>`;
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';
html += '<div class="newCollectionInfo">'; html += '<div class="newCollectionInfo">';
html += '<div class="inputContainer">'; html += '<div class="inputContainer">';
html += '<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="' + globalize.translate('LabelName') + '" />'; html += `<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="${globalize.translate('LabelName')}" />`;
html += '<div class="fieldDescription">' + globalize.translate('NewCollectionNameExample') + '</div>'; html += `<div class="fieldDescription">${globalize.translate('NewCollectionNameExample')}</div>`;
html += '</div>'; html += '</div>';
html += '<label class="checkboxContainer">'; html += '<label class="checkboxContainer">';
html += '<input is="emby-checkbox" type="checkbox" id="chkEnableInternetMetadata" />'; html += '<input is="emby-checkbox" type="checkbox" id="chkEnableInternetMetadata" />';
html += '<span>' + globalize.translate('SearchForCollectionInternetMetadata') + '</span>'; html += `<span>${globalize.translate('SearchForCollectionInternetMetadata')}</span>`;
html += '</label>'; html += '</label>';
// newCollectionInfo // newCollectionInfo
html += '</div>'; html += '</div>';
html += '<div class="formDialogFooter">'; html += '<div class="formDialogFooter">';
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('ButtonOk') + '</button>'; html += `<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">${globalize.translate('ButtonOk')}</button>`;
html += '</div>'; html += '</div>';
html += '<input type="hidden" class="fldSelectedItemIds" />'; html += '<input type="hidden" class="fldSelectedItemIds" />';
@ -167,7 +172,6 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
} }
function initEditor(content, items) { function initEditor(content, items) {
content.querySelector('#selectCollectionToAddTo').addEventListener('change', function () { content.querySelector('#selectCollectionToAddTo').addEventListener('change', function () {
if (this.value) { if (this.value) {
content.querySelector('.newCollectionInfo').classList.add('hide'); content.querySelector('.newCollectionInfo').classList.add('hide');
@ -188,7 +192,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
} else { } else {
content.querySelector('.fldSelectCollection').classList.add('hide'); content.querySelector('.fldSelectCollection').classList.add('hide');
var selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo'); const selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo');
selectCollectionToAddTo.innerHTML = ''; selectCollectionToAddTo.innerHTML = '';
selectCollectionToAddTo.value = ''; selectCollectionToAddTo.value = '';
triggerChange(selectCollectionToAddTo); triggerChange(selectCollectionToAddTo);
@ -196,79 +200,70 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
} }
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) { import('scrollHelper').then(scrollHelper => {
var fn = on ? 'on' : 'off'; const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });
} }
function CollectionEditor() { export class showEditor {
constructor(options) {
const items = options.items || {};
currentServerId = options.serverId;
} const dialogOptions = {
removeOnClose: true,
CollectionEditor.prototype.show = function (options) { scrollY: false
};
var items = options.items || {};
currentServerId = options.serverId;
var dialogOptions = {
removeOnClose: true,
scrollY: false
};
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
var html = '';
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"><span class="material-icons arrow_back"></span></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') + '"><span class="material-icons info"></span><span style="margin-left:.25em;">' + globalize.translate('Help') + '</span></a>';
}
html += '</div>';
html += getEditorHtml();
dlg.innerHTML = html;
initEditor(dlg, items);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
return dialogHelper.open(dlg).then(function () {
if (layoutManager.tv) { if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false); dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
} }
if (dlg.submitted) { const dlg = dialogHelper.createDialog(dialogOptions);
return Promise.resolve();
dlg.classList.add('formDialog');
let html = '';
const 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"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += title;
html += '</h3>';
html += '</div>';
html += getEditorHtml();
dlg.innerHTML = html;
initEditor(dlg, items);
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
} }
return Promise.reject(); return dialogHelper.open(dlg).then(() => {
}); if (layoutManager.tv) {
}; centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
return CollectionEditor; if (dlg.submitted) {
}); return Promise.resolve();
}
return Promise.reject();
});
}
}
/* eslint-enable indent */
export default showEditor;

View file

@ -1,13 +1,16 @@
define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize) { import browser from 'browser';
'use strict'; import dialog from 'dialog';
import globalize from 'globalize';
/* eslint-disable indent */
export default (() => {
function replaceAll(str, find, replace) { function replaceAll(str, find, replace) {
return str.split(find).join(replace); return str.split(find).join(replace);
} }
if (browser.tv && window.confirm) { if (browser.tv && window.confirm) {
// Use the native confirm dialog // Use the native confirm dialog
return function (options) { return options => {
if (typeof options === 'string') { if (typeof options === 'string') {
options = { options = {
title: '', title: '',
@ -15,8 +18,8 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
}; };
} }
var text = replaceAll(options.text || '', '<br/>', '\n'); const text = replaceAll(options.text || '', '<br/>', '\n');
var result = confirm(text); const result = confirm(text);
if (result) { if (result) {
return Promise.resolve(); return Promise.resolve();
@ -26,8 +29,8 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
}; };
} else { } else {
// Use our own dialog // Use our own dialog
return function (text, title) { return (text, title) => {
var options; let options;
if (typeof text === 'string') { if (typeof text === 'string') {
options = { options = {
title: title, title: title,
@ -37,7 +40,7 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
options = text; options = text;
} }
var items = []; const items = [];
items.push({ items.push({
name: options.cancelText || globalize.translate('ButtonCancel'), name: options.cancelText || globalize.translate('ButtonCancel'),
@ -53,7 +56,7 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
options.buttons = items; options.buttons = items;
return dialog(options).then(function (result) { return dialog.show(options).then(result => {
if (result === 'ok') { if (result === 'ok') {
return Promise.resolve(); return Promise.resolve();
} }
@ -62,4 +65,5 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
}); });
}; };
} }
}); })();
/* eslint-enable indent */

View file

@ -1,57 +0,0 @@
define(['connectionManager', 'confirm', 'appRouter', 'globalize'], function (connectionManager, confirm, appRouter, globalize) {
'use strict';
function alertText(options) {
return new Promise(function (resolve, reject) {
require(['alert'], function (alert) {
alert(options).then(resolve, resolve);
});
});
}
function deleteItem(options) {
var item = options.item;
var itemId = item.Id;
var parentId = item.SeasonId || item.SeriesId || item.ParentId;
var serverId = item.ServerId;
var msg = globalize.translate('ConfirmDeleteItem');
var title = globalize.translate('HeaderDeleteItem');
var apiClient = connectionManager.getApiClient(item.ServerId);
return confirm({
title: title,
text: msg,
confirmText: globalize.translate('Delete'),
primary: 'delete'
}).then(function () {
return apiClient.deleteItem(itemId).then(function () {
if (options.navigate) {
if (parentId) {
appRouter.showItem(parentId, serverId);
} else {
appRouter.goHome();
}
}
}, function (err) {
var result = function () {
return Promise.reject(err);
};
return alertText(globalize.translate('ErrorDeletingItem')).then(result, result);
});
});
}
return {
deleteItem: deleteItem
};
});

View file

@ -1,20 +1,30 @@
define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (dialogHelper, dom, layoutManager, scrollHelper, globalize, require) { import dialogHelper from 'dialogHelper';
'use strict'; import dom from 'dom';
import layoutManager from 'layoutManager';
import scrollHelper from 'scrollHelper';
import globalize from 'globalize';
import 'material-icons';
import 'emby-button';
import 'paper-icon-button-light';
import 'emby-input';
import 'formDialogStyle';
import 'flexStyles';
/* eslint-disable indent */
function showDialog(options, template) { function showDialog(options, template) {
const dialogOptions = {
var dialogOptions = {
removeOnClose: true, removeOnClose: true,
scrollY: false scrollY: false
}; };
var enableTvLayout = layoutManager.tv; const enableTvLayout = layoutManager.tv;
if (enableTvLayout) { if (enableTvLayout) {
dialogOptions.size = 'fullscreen'; dialogOptions.size = 'fullscreen';
} }
var dlg = dialogHelper.createDialog(dialogOptions); const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');
@ -22,7 +32,7 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
dlg.classList.add('align-items-center'); dlg.classList.add('align-items-center');
dlg.classList.add('justify-content-center'); dlg.classList.add('justify-content-center');
var formDialogContent = dlg.querySelector('.formDialogContent'); const formDialogContent = dlg.querySelector('.formDialogContent');
formDialogContent.classList.add('no-grow'); formDialogContent.classList.add('no-grow');
if (enableTvLayout) { if (enableTvLayout) {
@ -30,41 +40,36 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
formDialogContent.style['max-height'] = '60%'; formDialogContent.style['max-height'] = '60%';
scrollHelper.centerFocus.on(formDialogContent, false); scrollHelper.centerFocus.on(formDialogContent, false);
} else { } else {
formDialogContent.style.maxWidth = (Math.min((options.buttons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)) + 'px'; formDialogContent.style.maxWidth = `${Math.min((options.buttons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)}px`;
dlg.classList.add('dialog-fullscreen-lowres'); dlg.classList.add('dialog-fullscreen-lowres');
} }
//dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
// dialogHelper.close(dlg);
//});
if (options.title) { if (options.title) {
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || ''; dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || '';
} else { } else {
dlg.querySelector('.formDialogHeaderTitle').classList.add('hide'); dlg.querySelector('.formDialogHeaderTitle').classList.add('hide');
} }
var displayText = options.html || options.text || ''; const displayText = options.html || options.text || '';
dlg.querySelector('.text').innerHTML = displayText; dlg.querySelector('.text').innerHTML = displayText;
if (!displayText) { if (!displayText) {
dlg.querySelector('.dialogContentInner').classList.add('hide'); dlg.querySelector('.dialogContentInner').classList.add('hide');
} }
var i; let i;
var length; let length;
var html = ''; let html = '';
var hasDescriptions = false; let hasDescriptions = false;
for (i = 0, length = options.buttons.length; i < length; i++) { for (i = 0, length = options.buttons.length; i < length; i++) {
const item = options.buttons[i];
const autoFocus = i === 0 ? ' autofocus' : '';
var item = options.buttons[i]; let buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
var autoFocus = i === 0 ? ' autofocus' : '';
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
if (item.type) { if (item.type) {
buttonClass += ' button-' + item.type; buttonClass += ` button-${item.type}`;
} }
if (item.description) { if (item.description) {
@ -75,10 +80,10 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
buttonClass += ' formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom'; buttonClass += ' formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom';
} }
html += '<button is="emby-button" type="button" class="' + buttonClass + '" data-id="' + item.id + '"' + autoFocus + '>' + item.name + '</button>'; html += `<button is="emby-button" type="button" class="${buttonClass}" data-id="${item.id}"${autoFocus}>${item.name}</button>`;
if (item.description) { if (item.description) {
html += '<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">' + item.description + '</div>'; html += `<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">${item.description}</div>`;
} }
} }
@ -88,19 +93,18 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
dlg.querySelector('.formDialogFooter').classList.add('formDialogFooter-vertical'); dlg.querySelector('.formDialogFooter').classList.add('formDialogFooter-vertical');
} }
var dialogResult; let dialogResult;
function onButtonClick() { function onButtonClick() {
dialogResult = this.getAttribute('data-id'); dialogResult = this.getAttribute('data-id');
dialogHelper.close(dlg); dialogHelper.close(dlg);
} }
var buttons = dlg.querySelectorAll('.btnOption'); const buttons = dlg.querySelectorAll('.btnOption');
for (i = 0, length = buttons.length; i < length; i++) { for (i = 0, length = buttons.length; i < length; i++) {
buttons[i].addEventListener('click', onButtonClick); buttons[i].addEventListener('click', onButtonClick);
} }
return dialogHelper.open(dlg).then(function () { return dialogHelper.open(dlg).then(() => {
if (enableTvLayout) { if (enableTvLayout) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
} }
@ -113,9 +117,8 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
}); });
} }
return function (text, title) { export async function show(text, title) {
let options;
var options;
if (typeof text === 'string') { if (typeof text === 'string') {
options = { options = {
title: title, title: title,
@ -125,10 +128,13 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
options = text; options = text;
} }
return new Promise(function (resolve, reject) { const { default: template } = await import('text!./dialog.template.html');
require(['text!./dialog.template.html'], function (template) { return new Promise((resolve, reject) => {
showDialog(options, template).then(resolve, reject); showDialog(options, template).then(resolve, reject);
});
}); });
}; }
});
/* eslint-enable indent */
export default {
show: show
};

View file

@ -4,12 +4,8 @@
<div class="formDialogContent smoothScrollY"> <div class="formDialogContent smoothScrollY">
<div class="dialogContentInner dialog-content-centered" style="padding-top:1em;padding-bottom: 1em; text-align: center;"> <div class="dialogContentInner dialog-content-centered" style="padding-top:1em;padding-bottom: 1em; text-align: center;">
<div class="text"></div>
<div class="text">
</div>
</div> </div>
</div> </div>
<div class="formDialogFooter formDialogFooter-clear formDialogFooter-flex" style="padding-bottom: 1.5em;"> <div class="formDialogFooter formDialogFooter-clear formDialogFooter-flex" style="margin:1em"></div>
</div>

View file

@ -1,10 +1,17 @@
define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', 'dom', 'css!./dialoghelper.css', 'scrollStyles'], function (appRouter, focusManager, browser, layoutManager, inputManager, dom) { import appRouter from 'appRouter';
'use strict'; import focusManager from 'focusManager';
import browser from 'browser';
import layoutManager from 'layoutManager';
import inputManager from 'inputManager';
import dom from 'dom';
import 'css!./dialoghelper.css';
import 'scrollStyles';
var globalOnOpenCallback; /* eslint-disable indent */
let globalOnOpenCallback;
function enableAnimation() { function enableAnimation() {
// too slow // too slow
if (browser.tv) { if (browser.tv) {
return false; return false;
@ -14,7 +21,6 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function removeCenterFocus(dlg) { function removeCenterFocus(dlg) {
if (layoutManager.tv) { if (layoutManager.tv) {
if (dlg.classList.contains('scrollX')) { if (dlg.classList.contains('scrollX')) {
centerFocus(dlg, true, false); centerFocus(dlg, true, false);
@ -25,9 +31,8 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function tryRemoveElement(elem) { function tryRemoveElement(elem) {
var parentNode = elem.parentNode; const parentNode = elem.parentNode;
if (parentNode) { if (parentNode) {
// Seeing crashes in edge webview // Seeing crashes in edge webview
try { try {
parentNode.removeChild(elem); parentNode.removeChild(elem);
@ -38,15 +43,13 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function DialogHashHandler(dlg, hash, resolve) { function DialogHashHandler(dlg, hash, resolve) {
const self = this;
var self = this;
self.originalUrl = window.location.href; self.originalUrl = window.location.href;
var activeElement = document.activeElement; const activeElement = document.activeElement;
var removeScrollLockOnClose = false; let removeScrollLockOnClose = false;
function onHashChange(e) { function onHashChange(e) {
const isBack = self.originalUrl === window.location.href;
var isBack = self.originalUrl === window.location.href;
if (isBack || !isOpened(dlg)) { if (isBack || !isOpened(dlg)) {
window.removeEventListener('popstate', onHashChange); window.removeEventListener('popstate', onHashChange);
@ -59,7 +62,6 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function onBackCommand(e) { function onBackCommand(e) {
if (e.detail.command === 'back') { if (e.detail.command === 'back') {
self.closedByBack = true; self.closedByBack = true;
e.preventDefault(); e.preventDefault();
@ -69,7 +71,6 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function onDialogClosed() { function onDialogClosed() {
if (!isHistoryEnabled(dlg)) { if (!isHistoryEnabled(dlg)) {
inputManager.off(dlg, onBackCommand); inputManager.off(dlg, onBackCommand);
} }
@ -84,7 +85,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
if (!self.closedByBack && isHistoryEnabled(dlg)) { if (!self.closedByBack && isHistoryEnabled(dlg)) {
var state = history.state || {}; const state = history.state || {};
if (state.dialogId === hash) { if (state.dialogId === hash) {
history.back(); history.back();
} }
@ -97,7 +98,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
if (dlg.getAttribute('data-removeonclose') !== 'false') { if (dlg.getAttribute('data-removeonclose') !== 'false') {
removeCenterFocus(dlg); removeCenterFocus(dlg);
var dialogContainer = dlg.dialogContainer; const dialogContainer = dlg.dialogContainer;
if (dialogContainer) { if (dialogContainer) {
tryRemoveElement(dialogContainer); tryRemoveElement(dialogContainer);
dlg.dialogContainer = null; dlg.dialogContainer = null;
@ -108,7 +109,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
//resolve(); //resolve();
// if we just called history.back(), then use a timeout to allow the history events to fire first // if we just called history.back(), then use a timeout to allow the history events to fire first
setTimeout(function () { setTimeout(() => {
resolve({ resolve({
element: dlg, element: dlg,
closedByBack: self.closedByBack closedByBack: self.closedByBack
@ -118,7 +119,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
dlg.addEventListener('close', onDialogClosed); dlg.addEventListener('close', onDialogClosed);
var center = !dlg.classList.contains('dialog-fixedSize'); const center = !dlg.classList.contains('dialog-fixedSize');
if (center) { if (center) {
dlg.classList.add('centeredDialog'); dlg.classList.add('centeredDialog');
} }
@ -141,7 +142,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
animateDialogOpen(dlg); animateDialogOpen(dlg);
if (isHistoryEnabled(dlg)) { if (isHistoryEnabled(dlg)) {
appRouter.pushState({ dialogId: hash }, 'Dialog', '#' + hash); appRouter.pushState({ dialogId: hash }, 'Dialog', `#${hash}`);
window.addEventListener('popstate', onHashChange); window.addEventListener('popstate', onHashChange);
} else { } else {
@ -150,11 +151,10 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function addBackdropOverlay(dlg) { function addBackdropOverlay(dlg) {
const backdrop = document.createElement('div');
var backdrop = document.createElement('div');
backdrop.classList.add('dialogBackdrop'); backdrop.classList.add('dialogBackdrop');
var backdropParent = dlg.dialogContainer || dlg; const backdropParent = dlg.dialogContainer || dlg;
backdropParent.parentNode.insertBefore(backdrop, backdropParent); backdropParent.parentNode.insertBefore(backdrop, backdropParent);
dlg.backdrop = backdrop; dlg.backdrop = backdrop;
@ -162,7 +162,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
void backdrop.offsetWidth; void backdrop.offsetWidth;
backdrop.classList.add('dialogBackdropOpened'); backdrop.classList.add('dialogBackdropOpened');
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', function (e) { dom.addEventListener((dlg.dialogContainer || backdrop), 'click', e => {
if (e.target === dlg.dialogContainer) { if (e.target === dlg.dialogContainer) {
close(dlg); close(dlg);
} }
@ -170,7 +170,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
passive: true passive: true
}); });
dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', function (e) { dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', e => {
if (e.target === dlg.dialogContainer) { if (e.target === dlg.dialogContainer) {
// Close the application dialog menu // Close the application dialog menu
close(dlg); close(dlg);
@ -184,37 +184,33 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
return dlg.getAttribute('data-history') === 'true'; return dlg.getAttribute('data-history') === 'true';
} }
function open(dlg) { export function open(dlg) {
if (globalOnOpenCallback) { if (globalOnOpenCallback) {
globalOnOpenCallback(dlg); globalOnOpenCallback(dlg);
} }
var parent = dlg.parentNode; const parent = dlg.parentNode;
if (parent) { if (parent) {
parent.removeChild(dlg); parent.removeChild(dlg);
} }
var dialogContainer = document.createElement('div'); const dialogContainer = document.createElement('div');
dialogContainer.classList.add('dialogContainer'); dialogContainer.classList.add('dialogContainer');
dialogContainer.appendChild(dlg); dialogContainer.appendChild(dlg);
dlg.dialogContainer = dialogContainer; dlg.dialogContainer = dialogContainer;
document.body.appendChild(dialogContainer); document.body.appendChild(dialogContainer);
return new Promise(function (resolve, reject) { return new Promise((resolve, reject) => {
new DialogHashHandler(dlg, `dlg${new Date().getTime()}`, resolve);
new DialogHashHandler(dlg, 'dlg' + new Date().getTime(), resolve);
}); });
} }
function isOpened(dlg) { function isOpened(dlg) {
//return dlg.opened; //return dlg.opened;
return !dlg.classList.contains('hide'); return !dlg.classList.contains('hide');
} }
function close(dlg) { export function close(dlg) {
if (isOpened(dlg)) { if (isOpened(dlg)) {
if (isHistoryEnabled(dlg)) { if (isHistoryEnabled(dlg)) {
history.back(); history.back();
@ -225,15 +221,13 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function closeDialog(dlg) { function closeDialog(dlg) {
if (!dlg.classList.contains('hide')) { if (!dlg.classList.contains('hide')) {
dlg.dispatchEvent(new CustomEvent('closing', { dlg.dispatchEvent(new CustomEvent('closing', {
bubbles: false, bubbles: false,
cancelable: false cancelable: false
})); }));
var onAnimationFinish = function () { const onAnimationFinish = () => {
focusManager.popScope(dlg); focusManager.popScope(dlg);
dlg.classList.add('hide'); dlg.classList.add('hide');
@ -248,8 +242,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function animateDialogOpen(dlg) { function animateDialogOpen(dlg) {
const onAnimationFinish = () => {
var onAnimationFinish = function () {
focusManager.pushScope(dlg); focusManager.pushScope(dlg);
if (dlg.getAttribute('data-autofocus') === 'true') { if (dlg.getAttribute('data-autofocus') === 'true') {
@ -263,8 +256,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
}; };
if (enableAnimation()) { if (enableAnimation()) {
const onFinish = () => {
var onFinish = function () {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, { dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true once: true
}); });
@ -280,27 +272,24 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function animateDialogClose(dlg, onAnimationFinish) { function animateDialogClose(dlg, onAnimationFinish) {
if (enableAnimation()) { if (enableAnimation()) {
let animated = true;
var animated = true;
switch (dlg.animationConfig.exit.name) { switch (dlg.animationConfig.exit.name) {
case 'fadeout': case 'fadeout':
dlg.style.animation = 'fadeout ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both'; dlg.style.animation = `fadeout ${dlg.animationConfig.exit.timing.duration}ms ease-out normal both`;
break; break;
case 'scaledown': case 'scaledown':
dlg.style.animation = 'scaledown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both'; dlg.style.animation = `scaledown ${dlg.animationConfig.exit.timing.duration}ms ease-out normal both`;
break; break;
case 'slidedown': case 'slidedown':
dlg.style.animation = 'slidedown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both'; dlg.style.animation = `slidedown ${dlg.animationConfig.exit.timing.duration}ms ease-out normal both`;
break; break;
default: default:
animated = false; animated = false;
break; break;
} }
var onFinish = function () { const onFinish = () => {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, { dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true once: true
}); });
@ -318,10 +307,9 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
onAnimationFinish(); onAnimationFinish();
} }
var supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style; const supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
function shouldLockDocumentScroll(options) { function shouldLockDocumentScroll(options) {
if (supportsOverscrollBehavior && (options.size || !browser.touch)) { if (supportsOverscrollBehavior && (options.size || !browser.touch)) {
return false; return false;
} }
@ -342,8 +330,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function removeBackdrop(dlg) { function removeBackdrop(dlg) {
const backdrop = dlg.backdrop;
var backdrop = dlg.backdrop;
if (!backdrop) { if (!backdrop) {
return; return;
@ -351,12 +338,11 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
dlg.backdrop = null; dlg.backdrop = null;
var onAnimationFinish = function () { const onAnimationFinish = () => {
tryRemoveElement(backdrop); tryRemoveElement(backdrop);
}; };
if (enableAnimation()) { if (enableAnimation()) {
backdrop.classList.remove('dialogBackdropOpened'); backdrop.classList.remove('dialogBackdropOpened');
// this is not firing animatonend // this is not firing animatonend
@ -368,20 +354,19 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
} }
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
require(['scrollHelper'], function (scrollHelper) { import('scrollHelper').then(scrollHelper => {
var fn = on ? 'on' : 'off'; const fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz); scrollHelper.centerFocus[fn](elem, horiz);
}); });
} }
function createDialog(options) { export function createDialog(options) {
options = options || {}; options = options || {};
// If there's no native dialog support, use a plain div // If there's no native dialog support, use a plain div
// Also not working well in samsung tizen browser, content inside not clickable // Also not working well in samsung tizen browser, content inside not clickable
// Just go ahead and always use a plain div because we're seeing issues overlaying absoltutely positioned content over a modal dialog // Just go ahead and always use a plain div because we're seeing issues overlaying absoltutely positioned content over a modal dialog
var dlg = document.createElement('div'); const dlg = document.createElement('div');
dlg.classList.add('focuscontainer'); dlg.classList.add('focuscontainer');
dlg.classList.add('hide'); dlg.classList.add('hide');
@ -406,17 +391,17 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
dlg.setAttribute('data-autofocus', 'true'); dlg.setAttribute('data-autofocus', 'true');
} }
var defaultEntryAnimation; let defaultEntryAnimation;
var defaultExitAnimation; let defaultExitAnimation;
defaultEntryAnimation = 'scaleup'; defaultEntryAnimation = 'scaleup';
defaultExitAnimation = 'scaledown'; defaultExitAnimation = 'scaledown';
var entryAnimation = options.entryAnimation || defaultEntryAnimation; const entryAnimation = options.entryAnimation || defaultEntryAnimation;
var exitAnimation = options.exitAnimation || defaultExitAnimation; const exitAnimation = options.exitAnimation || defaultExitAnimation;
// If it's not fullscreen then lower the default animation speed to make it open really fast // If it's not fullscreen then lower the default animation speed to make it open really fast
var entryAnimationDuration = options.entryAnimationDuration || (options.size !== 'fullscreen' ? 180 : 280); const entryAnimationDuration = options.entryAnimationDuration || (options.size !== 'fullscreen' ? 180 : 280);
var exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220); const exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220);
dlg.animationConfig = { dlg.animationConfig = {
// scale up // scale up
@ -461,24 +446,22 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
if (options.size) { if (options.size) {
dlg.classList.add('dialog-fixedSize'); dlg.classList.add('dialog-fixedSize');
dlg.classList.add('dialog-' + options.size); dlg.classList.add(`dialog-${options.size}`);
} }
if (enableAnimation()) { if (enableAnimation()) {
switch (dlg.animationConfig.entry.name) { switch (dlg.animationConfig.entry.name) {
case 'fadein': case 'fadein':
dlg.style.animation = 'fadein ' + entryAnimationDuration + 'ms ease-out normal'; dlg.style.animation = `fadein ${entryAnimationDuration}ms ease-out normal`;
break; break;
case 'scaleup': case 'scaleup':
dlg.style.animation = 'scaleup ' + entryAnimationDuration + 'ms ease-out normal both'; dlg.style.animation = `scaleup ${entryAnimationDuration}ms ease-out normal both`;
break; break;
case 'slideup': case 'slideup':
dlg.style.animation = 'slideup ' + entryAnimationDuration + 'ms ease-out normal'; dlg.style.animation = `slideup ${entryAnimationDuration}ms ease-out normal`;
break; break;
case 'slidedown': case 'slidedown':
dlg.style.animation = 'slidedown ' + entryAnimationDuration + 'ms ease-out normal'; dlg.style.animation = `slidedown ${entryAnimationDuration}ms ease-out normal`;
break; break;
default: default:
break; break;
@ -488,12 +471,15 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
return dlg; return dlg;
} }
return { export function setOnOpen(val) {
open: open, globalOnOpenCallback = val;
close: close, }
createDialog: createDialog,
setOnOpen: function (val) { /* eslint-enable indent */
globalOnOpenCallback = val;
} export default {
}; open: open,
}); close: close,
createDialog: createDialog,
setOnOpen: setOnOpen
};

View file

@ -126,25 +126,10 @@
} }
@media all and (min-width: 80em) and (min-height: 45em) { @media all and (min-width: 80em) and (min-height: 45em) {
.dialog-medium {
width: 80%;
height: 80%;
}
.dialog-medium-tall {
width: 80%;
height: 90%;
}
.dialog-small { .dialog-small {
width: 60%; width: 60%;
height: 80%; height: 80%;
} }
.dialog-fullscreen-border {
width: 90%;
height: 90%;
}
} }
.noScroll { .noScroll {

View file

@ -1,9 +1,19 @@
define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-input', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-button'], function(loading, dialogHelper, dom, globalize) { import loading from 'loading';
'use strict'; import dialogHelper from 'dialogHelper';
import dom from 'dom';
import globalize from 'globalize';
import 'listViewStyle';
import 'emby-input';
import 'paper-icon-button-light';
import 'css!./directorybrowser';
import 'formDialogStyle';
import 'emby-button';
/* eslint-disable indent */
function getSystemInfo() { function getSystemInfo() {
return systemInfo ? Promise.resolve(systemInfo) : ApiClient.getPublicSystemInfo().then( return systemInfo ? Promise.resolve(systemInfo) : ApiClient.getPublicSystemInfo().then(
function(info) { info => {
systemInfo = info; systemInfo = info;
return info; return info;
} }
@ -21,9 +31,9 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
loading.show(); loading.show();
var promises = []; const promises = [];
if ('Network' === path) { if (path === 'Network') {
promises.push(ApiClient.getNetworkDevices()); promises.push(ApiClient.getNetworkDevices());
} else { } else {
if (path) { if (path) {
@ -35,10 +45,10 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
} }
Promise.all(promises).then( Promise.all(promises).then(
function(responses) { responses => {
var folders = responses[0]; const folders = responses[0];
var parentPath = responses[1] || ''; const parentPath = responses[1] || '';
var html = ''; let html = '';
page.querySelector('.results').scrollTop = 0; page.querySelector('.results').scrollTop = 0;
page.querySelector('#txtDirectoryPickerPath').value = path || ''; page.querySelector('#txtDirectoryPickerPath').value = path || '';
@ -46,9 +56,9 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
if (path) { if (path) {
html += getItem('lnkPath lnkDirectory', '', parentPath, '...'); html += getItem('lnkPath lnkDirectory', '', parentPath, '...');
} }
for (var i = 0, length = folders.length; i < length; i++) { for (let i = 0, length = folders.length; i < length; i++) {
var folder = folders[i]; const folder = folders[i];
var cssClass = 'File' === folder.Type ? 'lnkPath lnkFile' : 'lnkPath lnkDirectory'; const cssClass = folder.Type === 'File' ? 'lnkPath lnkFile' : 'lnkPath lnkDirectory';
html += getItem(cssClass, folder.Type, folder.Path, folder.Name); html += getItem(cssClass, folder.Type, folder.Path, folder.Name);
} }
@ -58,7 +68,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
page.querySelector('.results').innerHTML = html; page.querySelector('.results').innerHTML = html;
loading.hide(); loading.hide();
}, function() { }, () => {
if (updatePathOnError) { if (updatePathOnError) {
page.querySelector('#txtDirectoryPickerPath').value = ''; page.querySelector('#txtDirectoryPickerPath').value = '';
page.querySelector('.results').innerHTML = ''; page.querySelector('.results').innerHTML = '';
@ -69,8 +79,8 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
} }
function getItem(cssClass, type, path, name) { function getItem(cssClass, type, path, name) {
var html = ''; let html = '';
html += '<div class="listItem listItem-border ' + cssClass + '" data-type="' + type + '" data-path="' + path + '">'; html += `<div class="listItem listItem-border ${cssClass}" data-type="${type}" data-path="${path}">`;
html += '<div class="listItemBody" style="padding-left:0;padding-top:.5em;padding-bottom:.5em;">'; html += '<div class="listItemBody" style="padding-left:0;padding-top:.5em;padding-bottom:.5em;">';
html += '<div class="listItemBodyText">'; html += '<div class="listItemBodyText">';
html += name; html += name;
@ -82,20 +92,19 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
} }
function getEditorHtml(options, systemInfo) { function getEditorHtml(options, systemInfo) {
var html = ''; let html = '';
html += '<div class="formDialogContent scrollY">'; html += '<div class="formDialogContent scrollY">';
html += '<div class="dialogContentInner dialog-content-centered" style="padding-top:2em;">'; html += '<div class="dialogContentInner dialog-content-centered" style="padding-top:2em;">';
if (!options.pathReadOnly) { if (!options.pathReadOnly) {
var instruction = options.instruction ? options.instruction + '<br/><br/>' : ''; const instruction = options.instruction ? `${options.instruction}<br/><br/>` : '';
html += '<div class="infoBanner" style="margin-bottom:1.5em;">'; html += '<div class="infoBanner" style="margin-bottom:1.5em;">';
html += instruction; html += instruction;
html += globalize.translate('MessageDirectoryPickerInstruction', '<b>\\\\server</b>', '<b>\\\\192.168.1.101</b>'); if (systemInfo.OperatingSystem.toLowerCase() === 'bsd') {
if ('bsd' === systemInfo.OperatingSystem.toLowerCase()) {
html += '<br/>'; html += '<br/>';
html += '<br/>'; html += '<br/>';
html += globalize.translate('MessageDirectoryPickerBSDInstruction'); html += globalize.translate('MessageDirectoryPickerBSDInstruction');
html += '<br/>'; html += '<br/>';
} else if ('linux' === systemInfo.OperatingSystem.toLowerCase()) { } else if (systemInfo.OperatingSystem.toLowerCase() === 'linux') {
html += '<br/>'; html += '<br/>';
html += '<br/>'; html += '<br/>';
html += globalize.translate('MessageDirectoryPickerLinuxInstruction'); html += globalize.translate('MessageDirectoryPickerLinuxInstruction');
@ -106,17 +115,17 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
html += '<form style="margin:auto;">'; html += '<form style="margin:auto;">';
html += '<div class="inputContainer" style="display: flex; align-items: center;">'; html += '<div class="inputContainer" style="display: flex; align-items: center;">';
html += '<div style="flex-grow:1;">'; html += '<div style="flex-grow:1;">';
var labelKey; let labelKey;
if (options.includeFiles !== true) { if (options.includeFiles !== true) {
labelKey = 'LabelFolder'; labelKey = 'LabelFolder';
} else { } else {
labelKey = 'LabelPath'; labelKey = 'LabelPath';
} }
var readOnlyAttribute = options.pathReadOnly ? ' readonly' : ''; const readOnlyAttribute = options.pathReadOnly ? ' readonly' : '';
html += '<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ' + readOnlyAttribute + ' label="' + globalize.translate(labelKey) + '"/>'; html += `<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ${readOnlyAttribute} label="${globalize.translate(labelKey)}"/>`;
html += '</div>'; html += '</div>';
if (!readOnlyAttribute) { if (!readOnlyAttribute) {
html += '<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="' + globalize.translate('ButtonRefresh') + '"><span class="material-icons search"></span></button>'; html += `<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="${globalize.translate('ButtonRefresh')}"><span class="material-icons search"></span></button>`;
} }
html += '</div>'; html += '</div>';
if (!readOnlyAttribute) { if (!readOnlyAttribute) {
@ -124,14 +133,14 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
} }
if (options.enableNetworkSharePath) { if (options.enableNetworkSharePath) {
html += '<div class="inputContainer" style="margin-top:2em;">'; html += '<div class="inputContainer" style="margin-top:2em;">';
html += '<input is="emby-input" id="txtNetworkPath" type="text" label="' + globalize.translate('LabelOptionalNetworkPath') + '"/>'; html += `<input is="emby-input" id="txtNetworkPath" type="text" label="${globalize.translate('LabelOptionalNetworkPath')}"/>`;
html += '<div class="fieldDescription">'; html += '<div class="fieldDescription">';
html += globalize.translate('LabelOptionalNetworkPathHelp'); html += globalize.translate('LabelOptionalNetworkPathHelp', '<b>\\\\server</b>', '<b>\\\\192.168.1.101</b>');
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';
} }
html += '<div class="formDialogFooter">'; html += '<div class="formDialogFooter">';
html += '<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">' + globalize.translate('ButtonOk') + '</button>'; html += `<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">${globalize.translate('ButtonOk')}</button>`;
html += '</div>'; html += '</div>';
html += '</form>'; html += '</form>';
html += '</div>'; html += '</div>';
@ -148,7 +157,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
} }
function alertTextWithOptions(options) { function alertTextWithOptions(options) {
require(['alert'], function(alert) { import('alert').then(({default: alert}) => {
alert(options); alert(options);
}); });
} }
@ -161,7 +170,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
ValidateWriteable: validateWriteable, ValidateWriteable: validateWriteable,
Path: path Path: path
} }
}).catch(function(response) { }).catch(response => {
if (response) { if (response) {
if (response.status === 404) { if (response.status === 404) {
alertText(globalize.translate('PathNotFound')); alertText(globalize.translate('PathNotFound'));
@ -181,10 +190,10 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
} }
function initEditor(content, options, fileOptions) { function initEditor(content, options, fileOptions) {
content.addEventListener('click', function(e) { content.addEventListener('click', e => {
var lnkPath = dom.parentWithClass(e.target, 'lnkPath'); const lnkPath = dom.parentWithClass(e.target, 'lnkPath');
if (lnkPath) { if (lnkPath) {
var path = lnkPath.getAttribute('data-path'); const path = lnkPath.getAttribute('data-path');
if (lnkPath.classList.contains('lnkFile')) { if (lnkPath.classList.contains('lnkFile')) {
content.querySelector('#txtDirectoryPickerPath').value = path; content.querySelector('#txtDirectoryPickerPath').value = path;
} else { } else {
@ -193,25 +202,25 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
} }
}); });
content.addEventListener('click', function(e) { content.addEventListener('click', e => {
if (dom.parentWithClass(e.target, 'btnRefreshDirectories')) { if (dom.parentWithClass(e.target, 'btnRefreshDirectories')) {
var path = content.querySelector('#txtDirectoryPickerPath').value; const path = content.querySelector('#txtDirectoryPickerPath').value;
refreshDirectoryBrowser(content, path, fileOptions); refreshDirectoryBrowser(content, path, fileOptions);
} }
}); });
content.addEventListener('change', function(e) { content.addEventListener('change', e => {
var txtDirectoryPickerPath = dom.parentWithTag(e.target, 'INPUT'); const txtDirectoryPickerPath = dom.parentWithTag(e.target, 'INPUT');
if (txtDirectoryPickerPath && 'txtDirectoryPickerPath' === txtDirectoryPickerPath.id) { if (txtDirectoryPickerPath && txtDirectoryPickerPath.id === 'txtDirectoryPickerPath') {
refreshDirectoryBrowser(content, txtDirectoryPickerPath.value, fileOptions); refreshDirectoryBrowser(content, txtDirectoryPickerPath.value, fileOptions);
} }
}); });
content.querySelector('form').addEventListener('submit', function(e) { content.querySelector('form').addEventListener('submit', function(e) {
if (options.callback) { if (options.callback) {
var networkSharePath = this.querySelector('#txtNetworkPath'); let networkSharePath = this.querySelector('#txtNetworkPath');
networkSharePath = networkSharePath ? networkSharePath.value : null; networkSharePath = networkSharePath ? networkSharePath.value : null;
var path = this.querySelector('#txtDirectoryPickerPath').value; const path = this.querySelector('#txtDirectoryPickerPath').value;
validatePath(path, options.validateWriteable, ApiClient).then(options.callback(path, networkSharePath)); validatePath(path, options.validateWriteable, ApiClient).then(options.callback(path, networkSharePath));
} }
e.preventDefault(); e.preventDefault();
@ -225,77 +234,79 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
return Promise.resolve(options.path); return Promise.resolve(options.path);
} else { } else {
return ApiClient.getJSON(ApiClient.getUrl('Environment/DefaultDirectoryBrowser')).then( return ApiClient.getJSON(ApiClient.getUrl('Environment/DefaultDirectoryBrowser')).then(
function(result) { result => {
return result.Path || ''; return result.Path || '';
}, function() { }, () => {
return ''; return '';
} }
); );
} }
} }
function directoryBrowser() { class directoryBrowser {
var currentDialog; constructor() {
var self = this; let currentDialog;
self.show = function(options) { this.show = options => {
options = options || {}; options = options || {};
var fileOptions = { const fileOptions = {
includeDirectories: true includeDirectories: true
}; };
if (options.includeDirectories != null) { if (options.includeDirectories != null) {
fileOptions.includeDirectories = options.includeDirectories; fileOptions.includeDirectories = options.includeDirectories;
}
if (options.includeFiles != null) {
fileOptions.includeFiles = options.includeFiles;
}
Promise.all([getSystemInfo(), getDefaultPath(options)]).then(
function(responses) {
var systemInfo = responses[0];
var initialPath = responses[1];
var dlg = dialogHelper.createDialog({
size: 'medium-tall',
removeOnClose: true,
scrollY: false
});
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
dlg.classList.add('directoryPicker');
dlg.classList.add('formDialog');
var html = '';
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCloseDialog autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += options.header || globalize.translate('HeaderSelectPath');
html += '</h3>';
html += '</div>';
html += getEditorHtml(options, systemInfo);
dlg.innerHTML = html;
initEditor(dlg, options, fileOptions);
dlg.addEventListener('close', onDialogClosed);
dialogHelper.open(dlg);
dlg.querySelector('.btnCloseDialog').addEventListener('click', function() {
dialogHelper.close(dlg);
});
currentDialog = dlg;
dlg.querySelector('#txtDirectoryPickerPath').value = initialPath;
var txtNetworkPath = dlg.querySelector('#txtNetworkPath');
if (txtNetworkPath) {
txtNetworkPath.value = options.networkSharePath || '';
}
if (!options.pathReadOnly) {
refreshDirectoryBrowser(dlg, initialPath, fileOptions, true);
}
} }
); if (options.includeFiles != null) {
}; fileOptions.includeFiles = options.includeFiles;
self.close = function() { }
if (currentDialog) { Promise.all([getSystemInfo(), getDefaultPath(options)]).then(
dialogHelper.close(currentDialog); responses => {
} const systemInfo = responses[0];
}; const initialPath = responses[1];
const dlg = dialogHelper.createDialog({
size: 'small',
removeOnClose: true,
scrollY: false
});
dlg.classList.add('ui-body-a');
dlg.classList.add('background-theme-a');
dlg.classList.add('directoryPicker');
dlg.classList.add('formDialog');
let html = '';
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCloseDialog autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += options.header || globalize.translate('HeaderSelectPath');
html += '</h3>';
html += '</div>';
html += getEditorHtml(options, systemInfo);
dlg.innerHTML = html;
initEditor(dlg, options, fileOptions);
dlg.addEventListener('close', onDialogClosed);
dialogHelper.open(dlg);
dlg.querySelector('.btnCloseDialog').addEventListener('click', () => {
dialogHelper.close(dlg);
});
currentDialog = dlg;
dlg.querySelector('#txtDirectoryPickerPath').value = initialPath;
const txtNetworkPath = dlg.querySelector('#txtNetworkPath');
if (txtNetworkPath) {
txtNetworkPath.value = options.networkSharePath || '';
}
if (!options.pathReadOnly) {
refreshDirectoryBrowser(dlg, initialPath, fileOptions, true);
}
}
);
};
this.close = () => {
if (currentDialog) {
dialogHelper.close(currentDialog);
}
};
}
} }
var systemInfo; let systemInfo;
return directoryBrowser;
}); /* eslint-enable indent */
export default directoryBrowser;

View file

@ -0,0 +1,248 @@
import browser from 'browser';
import layoutManager from 'layoutManager';
import pluginManager from 'pluginManager';
import appHost from 'apphost';
import focusManager from 'focusManager';
import datetime from 'datetime';
import globalize from 'globalize';
import loading from 'loading';
import connectionManager from 'connectionManager';
import skinManager from 'skinManager';
import events from 'events';
import 'emby-select';
import 'emby-checkbox';
import 'emby-button';
/* eslint-disable indent */
function fillThemes(context, userSettings) {
const select = context.querySelector('#selectTheme');
skinManager.getThemes().then(themes => {
select.innerHTML = themes.map(t => {
return `<option value="${t.id}">${t.name}</option>`;
}).join('');
// get default theme
var defaultTheme = themes.find(theme => {
return theme.default;
});
// set the current theme
select.value = userSettings.theme() || defaultTheme.id;
});
}
function loadScreensavers(context, userSettings) {
const selectScreensaver = context.querySelector('.selectScreensaver');
const options = pluginManager.ofType('screensaver').map(plugin => {
return {
name: plugin.name,
value: plugin.id
};
});
options.unshift({
name: globalize.translate('None'),
value: 'none'
});
selectScreensaver.innerHTML = options.map(o => {
return `<option value="${o.value}">${o.name}</option>`;
}).join('');
selectScreensaver.value = userSettings.screensaver();
if (!selectScreensaver.value) {
// TODO: set the default instead of none
selectScreensaver.value = 'none';
}
}
function showOrHideMissingEpisodesField(context) {
if (browser.tizen || browser.web0s) {
context.querySelector('.fldDisplayMissingEpisodes').classList.add('hide');
return;
}
context.querySelector('.fldDisplayMissingEpisodes').classList.remove('hide');
}
function loadForm(context, user, userSettings) {
if (appHost.supports('displaylanguage')) {
context.querySelector('.languageSection').classList.remove('hide');
} else {
context.querySelector('.languageSection').classList.add('hide');
}
if (appHost.supports('displaymode')) {
context.querySelector('.fldDisplayMode').classList.remove('hide');
} else {
context.querySelector('.fldDisplayMode').classList.add('hide');
}
if (appHost.supports('externallinks')) {
context.querySelector('.learnHowToContributeContainer').classList.remove('hide');
} else {
context.querySelector('.learnHowToContributeContainer').classList.add('hide');
}
if (appHost.supports('screensaver')) {
context.querySelector('.selectScreensaverContainer').classList.remove('hide');
} else {
context.querySelector('.selectScreensaverContainer').classList.add('hide');
}
if (datetime.supportsLocalization()) {
context.querySelector('.fldDateTimeLocale').classList.remove('hide');
} else {
context.querySelector('.fldDateTimeLocale').classList.add('hide');
}
if (!browser.tizen && !browser.web0s) {
context.querySelector('.fldBackdrops').classList.remove('hide');
context.querySelector('.fldThemeSong').classList.remove('hide');
context.querySelector('.fldThemeVideo').classList.remove('hide');
} else {
context.querySelector('.fldBackdrops').classList.add('hide');
context.querySelector('.fldThemeSong').classList.add('hide');
context.querySelector('.fldThemeVideo').classList.add('hide');
}
fillThemes(context, userSettings);
loadScreensavers(context, userSettings);
context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false;
context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs();
context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos();
context.querySelector('#chkFadein').checked = userSettings.enableFastFadein();
context.querySelector('#chkBlurhash').checked = userSettings.enableBlurhash();
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
context.querySelector('#chkDetailsBanner').checked = userSettings.detailsBanner();
context.querySelector('#selectLanguage').value = userSettings.language() || '';
context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || '';
context.querySelector('#txtLibraryPageSize').value = userSettings.libraryPageSize();
context.querySelector('.selectLayout').value = layoutManager.getSavedLayout() || '';
showOrHideMissingEpisodesField(context);
loading.hide();
}
function saveUser(context, user, userSettingsInstance, apiClient) {
user.Configuration.DisplayMissingEpisodes = context.querySelector('.chkDisplayMissingEpisodes').checked;
if (appHost.supports('displaylanguage')) {
userSettingsInstance.language(context.querySelector('#selectLanguage').value);
}
userSettingsInstance.dateTimeLocale(context.querySelector('.selectDateTimeLocale').value);
userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked);
userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked);
userSettingsInstance.theme(context.querySelector('#selectTheme').value);
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);
userSettingsInstance.enableBlurhash(context.querySelector('#chkBlurhash').checked);
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
userSettingsInstance.detailsBanner(context.querySelector('#chkDetailsBanner').checked);
if (user.Id === apiClient.getCurrentUserId()) {
skinManager.setTheme(userSettingsInstance.theme());
}
layoutManager.setLayout(context.querySelector('.selectLayout').value);
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
}
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loading.show();
apiClient.getUser(userId).then(user => {
saveUser(context, user, userSettings, apiClient).then(() => {
loading.hide();
if (enableSaveConfirmation) {
import('toast').then(({default: toast}) => {
toast(globalize.translate('SettingsSaved'));
});
}
events.trigger(instance, 'saved');
}, () => {
loading.hide();
});
});
}
function onSubmit(e) {
const self = this;
const apiClient = connectionManager.getApiClient(self.options.serverId);
const userId = self.options.userId;
const userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(() => {
const enableSaveConfirmation = self.options.enableSaveConfirmation;
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
});
// Disable default form submission
if (e) {
e.preventDefault();
}
return false;
}
async function embed(options, self) {
const { default: template } = await import('text!./displaySettings.template.html');
options.element.innerHTML = globalize.translateHtml(template, 'core');
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
if (options.enableSaveButton) {
options.element.querySelector('.btnSave').classList.remove('hide');
}
self.loadData(options.autoFocus);
}
class DisplaySettings {
constructor(options) {
this.options = options;
embed(options, this);
}
loadData(autoFocus) {
const self = this;
const context = self.options.element;
loading.show();
const userId = self.options.userId;
const apiClient = connectionManager.getApiClient(self.options.serverId);
const userSettings = self.options.userSettings;
return apiClient.getUser(userId).then(user => {
return userSettings.setUserInfo(userId, apiClient).then(() => {
self.dataLoaded = true;
loadForm(context, user, userSettings);
if (autoFocus) {
focusManager.autoFocus(context);
}
});
});
}
submit() {
onSubmit.call(this);
}
destroy() {
this.options = null;
}
}
/* eslint-enable indent */
export default DisplaySettings;

View file

@ -1,5 +1,4 @@
<form style="margin: 0 auto;"> <form style="margin: 0 auto;">
<h2 class="sectionTitle"> <h2 class="sectionTitle">
${Display} ${Display}
</h2> </h2>
@ -56,7 +55,7 @@
<div class="fieldDescription"> <div class="fieldDescription">
<div>${LabelDisplayLanguageHelp}</div> <div>${LabelDisplayLanguageHelp}</div>
<div class="learnHowToContributeContainer hide" style="margin-top: .25em;"> <div class="learnHowToContributeContainer hide" style="margin-top: .25em;">
<a is="emby-linkbutton" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">${LearnHowYouCanContribute}</a> <a is="emby-linkbutton" rel="noopener noreferrer" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">${LearnHowYouCanContribute}</a>
</div> </div>
</div> </div>
</div> </div>
@ -123,37 +122,41 @@
<div class="fieldDescription">${LabelPleaseRestart}</div> <div class="fieldDescription">${LabelPleaseRestart}</div>
</div> </div>
<div class="selectContainer hide selectSkinContainer">
<select is="emby-select" class="selectSkin" label="${LabelSkin}"></select>
</div>
<div class="selectContainer"> <div class="selectContainer">
<select id="selectTheme" is="emby-select" label="${LabelTheme}"></select> <select id="selectTheme" is="emby-select" label="${LabelTheme}"></select>
</div> </div>
<div class="selectContainer selectDashboardThemeContainer hide">
<select id="selectDashboardTheme" is="emby-select" label="${LabelDashboardTheme}"></select>
</div>
<div class="selectContainer hide selectScreensaverContainer"> <div class="selectContainer hide selectScreensaverContainer">
<select is="emby-select" class="selectScreensaver" label="${LabelScreensaver}"></select> <select is="emby-select" class="selectScreensaver" label="${LabelScreensaver}"></select>
</div> </div>
<div class="selectContainer fldSoundEffects hide"> <div class="inputContainer inputContainer-withDescription">
<select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select>
</div>
<div class="inputContainer inputContainer-withDescription fldFadein">
<input is="emby-input" type="number" id="txtLibraryPageSize" pattern="[0-9]*" required="required" min="0" max="1000" step="1" label="${LabelLibraryPageSize}" /> <input is="emby-input" type="number" id="txtLibraryPageSize" pattern="[0-9]*" required="required" min="0" max="1000" step="1" label="${LabelLibraryPageSize}" />
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div> <div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription fldFadein"> <div class="checkboxContainer checkboxContainer-withDescription">
<label> <label>
<input type="checkbox" is="emby-checkbox" id="chkFadein" /> <input type="checkbox" is="emby-checkbox" id="chkFadein" />
<span>${EnableFastImageFadeIn}</span> <span>${EnableFasterAnimations}</span>
</label> </label>
<div class="fieldDescription checkboxFieldDescription">${EnableFastImageFadeInHelp}</div> <div class="fieldDescription checkboxFieldDescription">${EnableFasterAnimationsHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkBlurhash" />
<span>${EnableBlurHash}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${EnableBlurHashHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkDetailsBanner" />
<span>${EnableDetailsBanner}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${EnableDetailsBannerHelp}</div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide"> <div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide">
@ -180,13 +183,6 @@
<div class="fieldDescription checkboxFieldDescription">${EnableThemeVideosHelp}</div> <div class="fieldDescription checkboxFieldDescription">${EnableThemeVideosHelp}</div>
</div> </div>
<div class="checkboxContainer hide fldAutorun">
<label>
<input type="checkbox" is="emby-checkbox" class="chkRunAtStartup" />
<span>${RunAtStartup}</span>
</label>
</div>
<div class="checkboxContainer checkboxContainer-withDescription fldDisplayMissingEpisodes hide"> <div class="checkboxContainer checkboxContainer-withDescription fldDisplayMissingEpisodes hide">
<label> <label>
<input type="checkbox" is="emby-checkbox" class="chkDisplayMissingEpisodes" /> <input type="checkbox" is="emby-checkbox" class="chkDisplayMissingEpisodes" />

View file

@ -1,317 +0,0 @@
define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-button'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) {
'use strict';
function fillThemes(select, isDashboard) {
select.innerHTML = skinManager.getThemes().map(function (t) {
var value = t.id;
if (t.isDefault && !isDashboard) {
value = '';
} else if (t.isDefaultServerDashboard && isDashboard) {
value = '';
}
return '<option value="' + value + '">' + t.name + '</option>';
}).join('');
}
function loadScreensavers(context, userSettings) {
var selectScreensaver = context.querySelector('.selectScreensaver');
var options = pluginManager.ofType('screensaver').map(function (plugin) {
return {
name: plugin.name,
value: plugin.id
};
});
options.unshift({
name: globalize.translate('None'),
value: 'none'
});
selectScreensaver.innerHTML = options.map(function (o) {
return '<option value="' + o.value + '">' + o.name + '</option>';
}).join('');
selectScreensaver.value = userSettings.screensaver();
if (!selectScreensaver.value) {
// TODO: set the default instead of none
selectScreensaver.value = 'none';
}
}
function loadSoundEffects(context, userSettings) {
var selectSoundEffects = context.querySelector('.selectSoundEffects');
var options = pluginManager.ofType('soundeffects').map(function (plugin) {
return {
name: plugin.name,
value: plugin.id
};
});
options.unshift({
name: globalize.translate('None'),
value: 'none'
});
selectSoundEffects.innerHTML = options.map(function (o) {
return '<option value="' + o.value + '">' + o.name + '</option>';
}).join('');
selectSoundEffects.value = userSettings.soundEffects();
if (!selectSoundEffects.value) {
// TODO: set the default instead of none
selectSoundEffects.value = 'none';
}
}
function loadSkins(context, userSettings) {
var selectSkin = context.querySelector('.selectSkin');
var options = pluginManager.ofType('skin').map(function (plugin) {
return {
name: plugin.name,
value: plugin.id
};
});
selectSkin.innerHTML = options.map(function (o) {
return '<option value="' + o.value + '">' + o.name + '</option>';
}).join('');
selectSkin.value = userSettings.skin();
if (!selectSkin.value && options.length) {
selectSkin.value = options[0].value;
}
if (options.length > 1 && appHost.supports('skins')) {
context.querySelector('.selectSkinContainer').classList.remove('hide');
} else {
context.querySelector('.selectSkinContainer').classList.add('hide');
}
}
function showOrHideMissingEpisodesField(context, user, apiClient) {
if (browser.tizen || browser.web0s) {
context.querySelector('.fldDisplayMissingEpisodes').classList.add('hide');
return;
}
context.querySelector('.fldDisplayMissingEpisodes').classList.remove('hide');
}
function loadForm(context, user, userSettings, apiClient) {
var loggedInUserId = apiClient.getCurrentUserId();
var userId = user.Id;
if (user.Policy.IsAdministrator) {
context.querySelector('.selectDashboardThemeContainer').classList.remove('hide');
} else {
context.querySelector('.selectDashboardThemeContainer').classList.add('hide');
}
if (appHost.supports('displaylanguage')) {
context.querySelector('.languageSection').classList.remove('hide');
} else {
context.querySelector('.languageSection').classList.add('hide');
}
if (appHost.supports('displaymode')) {
context.querySelector('.fldDisplayMode').classList.remove('hide');
} else {
context.querySelector('.fldDisplayMode').classList.add('hide');
}
if (appHost.supports('externallinks')) {
context.querySelector('.learnHowToContributeContainer').classList.remove('hide');
} else {
context.querySelector('.learnHowToContributeContainer').classList.add('hide');
}
if (appHost.supports('runatstartup')) {
context.querySelector('.fldAutorun').classList.remove('hide');
} else {
context.querySelector('.fldAutorun').classList.add('hide');
}
if (appHost.supports('soundeffects')) {
context.querySelector('.fldSoundEffects').classList.remove('hide');
} else {
context.querySelector('.fldSoundEffects').classList.add('hide');
}
if (appHost.supports('screensaver')) {
context.querySelector('.selectScreensaverContainer').classList.remove('hide');
} else {
context.querySelector('.selectScreensaverContainer').classList.add('hide');
}
if (datetime.supportsLocalization()) {
context.querySelector('.fldDateTimeLocale').classList.remove('hide');
} else {
context.querySelector('.fldDateTimeLocale').classList.add('hide');
}
if (!browser.tizen && !browser.web0s) {
context.querySelector('.fldBackdrops').classList.remove('hide');
context.querySelector('.fldThemeSong').classList.remove('hide');
context.querySelector('.fldThemeVideo').classList.remove('hide');
} else {
context.querySelector('.fldBackdrops').classList.add('hide');
context.querySelector('.fldThemeSong').classList.add('hide');
context.querySelector('.fldThemeVideo').classList.add('hide');
}
context.querySelector('.chkRunAtStartup').checked = appSettings.runAtStartup();
var selectTheme = context.querySelector('#selectTheme');
var selectDashboardTheme = context.querySelector('#selectDashboardTheme');
fillThemes(selectTheme);
fillThemes(selectDashboardTheme, true);
loadScreensavers(context, userSettings);
loadSoundEffects(context, userSettings);
loadSkins(context, userSettings);
context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false;
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() || '';
context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || '';
context.querySelector('#txtLibraryPageSize').value = userSettings.libraryPageSize();
selectDashboardTheme.value = userSettings.dashboardTheme() || '';
selectTheme.value = userSettings.theme() || '';
context.querySelector('.selectLayout').value = layoutManager.getSavedLayout() || '';
showOrHideMissingEpisodesField(context, user, apiClient);
loading.hide();
}
function saveUser(context, user, userSettingsInstance, apiClient) {
appSettings.runAtStartup(context.querySelector('.chkRunAtStartup').checked);
user.Configuration.DisplayMissingEpisodes = context.querySelector('.chkDisplayMissingEpisodes').checked;
if (appHost.supports('displaylanguage')) {
userSettingsInstance.language(context.querySelector('#selectLanguage').value);
}
userSettingsInstance.dateTimeLocale(context.querySelector('.selectDateTimeLocale').value);
userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked);
userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked);
userSettingsInstance.dashboardTheme(context.querySelector('#selectDashboardTheme').value);
userSettingsInstance.theme(context.querySelector('#selectTheme').value);
userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value);
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
if (user.Id === apiClient.getCurrentUserId()) {
skinManager.setTheme(userSettingsInstance.theme());
}
layoutManager.setLayout(context.querySelector('.selectLayout').value);
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
}
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loading.show();
apiClient.getUser(userId).then(function (user) {
saveUser(context, user, userSettings, apiClient).then(function () {
loading.hide();
if (enableSaveConfirmation) {
require(['toast'], function (toast) {
toast(globalize.translate('SettingsSaved'));
});
}
events.trigger(instance, 'saved');
}, function () {
loading.hide();
});
});
}
function onSubmit(e) {
var self = this;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userId = self.options.userId;
var userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(function () {
var enableSaveConfirmation = self.options.enableSaveConfirmation;
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
});
// Disable default form submission
if (e) {
e.preventDefault();
}
return false;
}
function embed(options, self) {
require(['text!./displaysettings.template.html'], function (template) {
options.element.innerHTML = globalize.translateDocument(template, 'core');
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
if (options.enableSaveButton) {
options.element.querySelector('.btnSave').classList.remove('hide');
}
self.loadData(options.autoFocus);
});
}
function DisplaySettings(options) {
this.options = options;
embed(options, this);
}
DisplaySettings.prototype.loadData = function (autoFocus) {
var self = this;
var context = self.options.element;
loading.show();
var userId = self.options.userId;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userSettings = self.options.userSettings;
return apiClient.getUser(userId).then(function (user) {
return userSettings.setUserInfo(userId, apiClient).then(function () {
self.dataLoaded = true;
loadForm(context, user, userSettings, apiClient);
if (autoFocus) {
focusManager.autoFocus(context);
}
});
});
};
DisplaySettings.prototype.submit = function () {
onSubmit.call(this);
};
DisplaySettings.prototype.destroy = function () {
this.options = null;
};
return DisplaySettings;
});

View file

@ -1,5 +1,14 @@
define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoader', 'globalize', 'layoutManager', 'scrollStyles', 'emby-itemscontainer'], function (loading, libraryBrowser, cardBuilder, dom, appHost, imageLoader, globalize, layoutManager) { import loading from 'loading';
'use strict'; import cardBuilder from 'cardBuilder';
import dom from 'dom';
import appHost from 'apphost';
import imageLoader from 'imageLoader';
import globalize from 'globalize';
import layoutManager from 'layoutManager';
import 'scrollStyles';
import 'emby-itemscontainer';
/* eslint-disable indent */
function enableScrollX() { function enableScrollX() {
return !layoutManager.desktop; return !layoutManager.desktop;
@ -94,8 +103,8 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
} }
function loadSection(elem, userId, topParentId, section, isSingleSection) { function loadSection(elem, userId, topParentId, section, isSingleSection) {
var screenWidth = dom.getWindowSize().innerWidth; const screenWidth = dom.getWindowSize().innerWidth;
var options = { const options = {
SortBy: 'SortName', SortBy: 'SortName',
SortOrder: 'Ascending', SortOrder: 'Ascending',
Filters: 'IsFavorite', Filters: 'IsFavorite',
@ -118,9 +127,9 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
} }
} }
var promise; let promise;
if ('MusicArtist' === section.types) { if (section.types === 'MusicArtist') {
promise = ApiClient.getArtists(userId, options); promise = ApiClient.getArtists(userId, options);
} else { } else {
options.IncludeItemTypes = section.types; options.IncludeItemTypes = section.types;
@ -128,7 +137,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
} }
return promise.then(function (result) { return promise.then(function (result) {
var html = ''; let html = '';
if (result.Items.length) { if (result.Items.length) {
if (html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">', !layoutManager.tv && options.Limit && result.Items.length >= options.Limit) { if (html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">', !layoutManager.tv && options.Limit && result.Items.length >= options.Limit) {
@ -144,7 +153,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
html += '</div>'; html += '</div>';
if (enableScrollX()) { if (enableScrollX()) {
var scrollXClass = 'scrollX hiddenScrollX'; let scrollXClass = 'scrollX hiddenScrollX';
if (layoutManager.tv) { if (layoutManager.tv) {
scrollXClass += ' smoothScrollX'; scrollXClass += ' smoothScrollX';
} }
@ -154,14 +163,13 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
html += '<div is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right">'; html += '<div is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right">';
} }
var supportsImageAnalysis = appHost.supports('imageanalysis'); let cardLayout = appHost.preferVisualCards && section.autoCardLayout && section.showTitle;
var cardLayout = (appHost.preferVisualCards || supportsImageAnalysis) && section.autoCardLayout && section.showTitle;
cardLayout = false; cardLayout = false;
html += cardBuilder.getCardsHtml(result.Items, { html += cardBuilder.getCardsHtml(result.Items, {
preferThumb: section.preferThumb, preferThumb: section.preferThumb,
shape: section.shape, shape: section.shape,
centerText: section.centerText && !cardLayout, centerText: section.centerText && !cardLayout,
overlayText: false !== section.overlayText, overlayText: section.overlayText !== false,
showTitle: section.showTitle, showTitle: section.showTitle,
showParentTitle: section.showParentTitle, showParentTitle: section.showParentTitle,
scalable: true, scalable: true,
@ -180,10 +188,10 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
}); });
} }
function loadSections(page, userId, topParentId, types) { export function loadSections(page, userId, topParentId, types) {
loading.show(); loading.show();
var sections = getSections(); let sections = getSections();
var sectionid = getParameterByName('sectionid'); const sectionid = getParameterByName('sectionid');
if (sectionid) { if (sectionid) {
sections = sections.filter(function (s) { sections = sections.filter(function (s) {
@ -193,30 +201,28 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
if (types) { if (types) {
sections = sections.filter(function (s) { sections = sections.filter(function (s) {
return -1 !== types.indexOf(s.id); return types.indexOf(s.id) !== -1;
}); });
} }
var i; let elem = page.querySelector('.favoriteSections');
var length;
var elem = page.querySelector('.favoriteSections');
if (!elem.innerHTML) { if (!elem.innerHTML) {
var html = ''; let html = '';
for (i = 0, length = sections.length; i < length; i++) { for (let i = 0, length = sections.length; i < length; i++) {
html += '<div class="verticalSection section' + sections[i].id + '"></div>'; html += '<div class="verticalSection section' + sections[i].id + '"></div>';
} }
elem.innerHTML = html; elem.innerHTML = html;
} }
var promises = []; const promises = [];
for (i = 0, length = sections.length; i < length; i++) { for (let i = 0, length = sections.length; i < length; i++) {
var section = sections[i]; const section = sections[i];
elem = page.querySelector('.section' + section.id); elem = page.querySelector('.section' + section.id);
promises.push(loadSection(elem, userId, topParentId, section, 1 === sections.length)); promises.push(loadSection(elem, userId, topParentId, section, sections.length === 1));
} }
Promise.all(promises).then(function () { Promise.all(promises).then(function () {
@ -224,7 +230,8 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
}); });
} }
return { export default {
render: loadSections render: loadSections
}; };
});
/* eslint-enable indent */

View file

@ -1,24 +1,20 @@
define([], function () { /* eslint-disable indent */
'use strict'; export function getFetchPromise(request) {
const headers = request.headers || {};
function getFetchPromise(request) {
var headers = request.headers || {};
if (request.dataType === 'json') { if (request.dataType === 'json') {
headers.accept = 'application/json'; headers.accept = 'application/json';
} }
var fetchRequest = { const fetchRequest = {
headers: headers, headers: headers,
method: request.type, method: request.type,
credentials: 'same-origin' credentials: 'same-origin'
}; };
var contentType = request.contentType; let contentType = request.contentType;
if (request.data) { if (request.data) {
if (typeof request.data === 'string') { if (typeof request.data === 'string') {
fetchRequest.body = request.data; fetchRequest.body = request.data;
} else { } else {
@ -29,16 +25,15 @@ define([], function () {
} }
if (contentType) { if (contentType) {
headers['Content-Type'] = contentType; headers['Content-Type'] = contentType;
} }
var url = request.url; let url = request.url;
if (request.query) { if (request.query) {
var paramString = paramsToString(request.query); const paramString = paramsToString(request.query);
if (paramString) { if (paramString) {
url += '?' + paramString; url += `?${paramString}`;
} }
} }
@ -50,12 +45,10 @@ define([], function () {
} }
function fetchWithTimeout(url, options, timeoutMs) { function fetchWithTimeout(url, options, timeoutMs) {
console.debug(`fetchWithTimeout: timeoutMs: ${timeoutMs}, url: ${url}`);
console.debug('fetchWithTimeout: timeoutMs: ' + timeoutMs + ', url: ' + url);
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
const timeout = setTimeout(reject, timeoutMs);
var timeout = setTimeout(reject, timeoutMs);
options = options || {}; options = options || {};
options.credentials = 'same-origin'; options.credentials = 'same-origin';
@ -63,50 +56,46 @@ define([], function () {
fetch(url, options).then(function (response) { fetch(url, options).then(function (response) {
clearTimeout(timeout); clearTimeout(timeout);
console.debug('fetchWithTimeout: succeeded connecting to url: ' + url); console.debug(`fetchWithTimeout: succeeded connecting to url: ${url}`);
resolve(response); resolve(response);
}, function (error) { }, function (error) {
clearTimeout(timeout); clearTimeout(timeout);
console.debug('fetchWithTimeout: timed out connecting to url: ' + url); console.debug(`fetchWithTimeout: timed out connecting to url: ${url}`);
reject(); reject(error);
}); });
}); });
} }
/**
* @param params {Record<string, string | number | boolean>}
* @returns {string} Query string
*/
function paramsToString(params) { function paramsToString(params) {
return Object.entries(params)
var values = []; // eslint-disable-next-line no-unused-vars
.filter(([_, v]) => v !== null && v !== undefined && v !== '')
for (var key in params) { .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&');
var value = params[key];
if (value !== null && value !== undefined && value !== '') {
values.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
}
}
return values.join('&');
} }
function ajax(request) { export function ajax(request) {
if (!request) { if (!request) {
throw new Error('Request cannot be null'); throw new Error('Request cannot be null');
} }
request.headers = request.headers || {}; request.headers = request.headers || {};
console.debug('requesting url: ' + request.url); console.debug(`requesting url: ${request.url}`);
return getFetchPromise(request).then(function (response) { return getFetchPromise(request).then(function (response) {
console.debug('response status: ' + response.status + ', url: ' + request.url); console.debug(`response status: ${response.status}, url: ${request.url}`);
if (response.status < 400) { if (response.status < 400) {
if (request.dataType === 'json' || request.headers.accept === 'application/json') { if (request.dataType === 'json' || request.headers.accept === 'application/json') {
return response.json(); return response.json();
} else if (request.dataType === 'text' || (response.headers.get('Content-Type') || '').toLowerCase().indexOf('text/') === 0) { } else if (request.dataType === 'text' || (response.headers.get('Content-Type') || '').toLowerCase().startsWith('text/')) {
return response.text(); return response.text();
} else { } else {
return response; return response;
@ -115,12 +104,8 @@ define([], function () {
return Promise.reject(response); return Promise.reject(response);
} }
}, function (err) { }, function (err) {
console.error('request failed to url: ' + request.url); console.error(`request failed to url: ${request.url}`);
throw err; throw err;
}); });
} }
return { /* eslint-enable indent */
getFetchPromise: getFetchPromise,
ajax: ajax
};
});

View file

@ -1,21 +1,28 @@
define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'browser', 'require', 'emby-checkbox', 'emby-collapse', 'css!./style'], function (dom, dialogHelper, globalize, connectionManager, events, browser, require) { import dom from 'dom';
'use strict'; import dialogHelper from 'dialogHelper';
import globalize from 'globalize';
import connectionManager from 'connectionManager';
import events from 'events';
import 'emby-checkbox';
import 'emby-collapse';
import 'css!./style.css';
/* eslint-disable indent */
function renderOptions(context, selector, cssClass, items, isCheckedFn) { function renderOptions(context, selector, cssClass, items, isCheckedFn) {
var elem = context.querySelector(selector); const elem = context.querySelector(selector);
if (items.length) { if (items.length) {
elem.classList.remove('hide'); elem.classList.remove('hide');
} else { } else {
elem.classList.add('hide'); elem.classList.add('hide');
} }
var html = ''; let html = '';
html += '<div class="checkboxList">'; html += '<div class="checkboxList">';
html += items.map(function (filter) { html += items.map(function (filter) {
var itemHtml = ''; let itemHtml = '';
var checkedHtml = isCheckedFn(filter) ? ' checked' : ''; const checkedHtml = isCheckedFn(filter) ? 'checked' : '';
itemHtml += '<label>'; itemHtml += '<label>';
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter + '" class="' + cssClass + '"/>'; itemHtml += `<input is="emby-checkbox" type="checkbox" ${checkedHtml} data-filter="${filter}" class="${cssClass}"/>`;
itemHtml += '<span>' + filter + '</span>'; itemHtml += `<span>${filter}</span>`;
itemHtml += '</label>'; itemHtml += '</label>';
return itemHtml; return itemHtml;
}).join(''); }).join('');
@ -24,21 +31,24 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
} }
function renderFilters(context, result, query) { function renderFilters(context, result, query) {
if (result.Tags) {
result.Tags.length = Math.min(result.Tags.length, 50);
}
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) { renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
var delimeter = '|'; const delimeter = '|';
return (delimeter + (query.Genres || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; return (delimeter + (query.Genres || '') + delimeter).includes(delimeter + i + delimeter);
}); });
renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) { renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
var delimeter = '|'; const delimeter = '|';
return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; return (delimeter + (query.OfficialRatings || '') + delimeter).includes(delimeter + i + delimeter);
}); });
renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) { renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
var delimeter = '|'; const delimeter = '|';
return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; return (delimeter + (query.Tags || '') + delimeter).includes(delimeter + i + delimeter);
}); });
renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) { renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
var delimeter = ','; const delimeter = ',';
return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; return (delimeter + (query.Years || '') + delimeter).includes(delimeter + i + delimeter);
}); });
} }
@ -52,59 +62,58 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
}); });
} }
/**
* @param context {HTMLDivElement} Dialog
* @param options {any} Options
*/
function updateFilterControls(context, options) { function updateFilterControls(context, options) {
var elems; const query = options.query;
var i;
var length;
var query = options.query;
if (options.mode == 'livetvchannels') { if (options.mode === 'livetvchannels') {
context.querySelector('.chkFavorite').checked = query.IsFavorite == true; context.querySelector('.chkFavorite').checked = query.IsFavorite === true;
context.querySelector('.chkLikes').checked = query.IsLiked == true; context.querySelector('.chkLikes').checked = query.IsLiked === true;
context.querySelector('.chkDislikes').checked = query.IsDisliked == true; context.querySelector('.chkDislikes').checked = query.IsDisliked === true;
} else { } else {
elems = context.querySelectorAll('.chkStandardFilter'); for (const elem of context.querySelectorAll('.chkStandardFilter')) {
for (i = 0, length = elems.length; i < length; i++) { const filters = `,${query.Filters || ''}`;
var chkStandardFilter = elems[i]; const filterName = elem.getAttribute('data-filter');
var filters = ',' + (query.Filters || ''); elem.checked = filters.includes(`,${filterName}`);
var filterName = chkStandardFilter.getAttribute('data-filter');
chkStandardFilter.checked = filters.indexOf(',' + filterName) != -1;
} }
} }
elems = context.querySelectorAll('.chkVideoTypeFilter'); for (const elem of context.querySelectorAll('.chkVideoTypeFilter')) {
for (i = 0, length = elems.length; i < length; i++) { const filters = `,${query.VideoTypes || ''}`;
var chkVideoTypeFilter = elems[i]; const filterName = elem.getAttribute('data-filter');
var filters = ',' + (query.VideoTypes || ''); elem.checked = filters.includes(`,${filterName}`);
var filterName = chkVideoTypeFilter.getAttribute('data-filter');
chkVideoTypeFilter.checked = filters.indexOf(',' + filterName) != -1;
} }
context.querySelector('.chk3DFilter').checked = query.Is3D == true; context.querySelector('.chk3DFilter').checked = query.Is3D === true;
context.querySelector('.chkHDFilter').checked = query.IsHD == true; context.querySelector('.chkHDFilter').checked = query.IsHD === true;
context.querySelector('.chk4KFilter').checked = query.Is4K == true; context.querySelector('.chk4KFilter').checked = query.Is4K === true;
context.querySelector('.chkSDFilter').checked = query.IsHD == true; context.querySelector('.chkSDFilter').checked = query.IsHD === true;
context.querySelector('#chkSubtitle').checked = query.HasSubtitles == true; context.querySelector('#chkSubtitle').checked = query.HasSubtitles === true;
context.querySelector('#chkTrailer').checked = query.HasTrailer == true; context.querySelector('#chkTrailer').checked = query.HasTrailer === true;
context.querySelector('#chkThemeSong').checked = query.HasThemeSong == true; context.querySelector('#chkThemeSong').checked = query.HasThemeSong === true;
context.querySelector('#chkThemeVideo').checked = query.HasThemeVideo == true; context.querySelector('#chkThemeVideo').checked = query.HasThemeVideo === true;
context.querySelector('#chkSpecialFeature').checked = query.HasSpecialFeature == true; context.querySelector('#chkSpecialFeature').checked = query.HasSpecialFeature === true;
context.querySelector('#chkSpecialEpisode').checked = query.ParentIndexNumber == 0; context.querySelector('#chkSpecialEpisode').checked = query.ParentIndexNumber === 0;
context.querySelector('#chkMissingEpisode').checked = query.IsMissing == true; context.querySelector('#chkMissingEpisode').checked = query.IsMissing === true;
context.querySelector('#chkFutureEpisode').checked = query.IsUnaired == true; context.querySelector('#chkFutureEpisode').checked = query.IsUnaired === true;
for (i = 0, length = elems.length; i < length; i++) { for (const elem of context.querySelectorAll('.chkStatus')) {
var chkStatus = elems[i]; const filters = `,${query.SeriesStatus || ''}`;
var filters = ',' + (query.SeriesStatus || ''); const filterName = elem.getAttribute('data-filter');
var filterName = chkStatus.getAttribute('data-filter'); elem.checked = filters.includes(`,${filterName}`);
chkStatus.checked = filters.indexOf(',' + filterName) != -1;
} }
} }
/**
* @param instance {FilterDialog} An instance of FilterDialog
*/
function triggerChange(instance) { function triggerChange(instance) {
events.trigger(instance, 'filterchange'); events.trigger(instance, 'filterchange');
} }
function setVisibility(context, options) { function setVisibility(context, options) {
if (options.mode == 'livetvchannels' || options.mode == 'albums' || options.mode == 'artists' || options.mode == 'albumartists' || options.mode == 'songs') { if (options.mode === 'livetvchannels' || options.mode === 'albums' || options.mode === 'artists' || options.mode === 'albumartists' || options.mode === 'songs') {
hideByClass(context, 'videoStandard'); hideByClass(context, 'videoStandard');
} }
@ -115,263 +124,287 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
context.querySelector('.yearFilters').classList.remove('hide'); context.querySelector('.yearFilters').classList.remove('hide');
} }
if (options.mode == 'movies' || options.mode == 'episodes') { if (options.mode === 'movies' || options.mode === 'episodes') {
context.querySelector('.videoTypeFilters').classList.remove('hide'); context.querySelector('.videoTypeFilters').classList.remove('hide');
} }
if (options.mode == 'movies' || options.mode == 'series' || options.mode == 'episodes') { if (options.mode === 'movies' || options.mode === 'series' || options.mode === 'episodes') {
context.querySelector('.features').classList.remove('hide'); context.querySelector('.features').classList.remove('hide');
} }
if (options.mode == 'series') { if (options.mode === 'series') {
context.querySelector('.seriesStatus').classList.remove('hide'); context.querySelector('.seriesStatus').classList.remove('hide');
} }
if (options.mode == 'episodes') { if (options.mode === 'episodes') {
showByClass(context, 'episodeFilter'); showByClass(context, 'episodeFilter');
} }
} }
function showByClass(context, className) { function showByClass(context, className) {
var elems = context.querySelectorAll('.' + className); for (const elem of context.querySelectorAll(`.${className}`)) {
elem.classList.remove('hide');
for (var i = 0, length = elems.length; i < length; i++) {
elems[i].classList.remove('hide');
} }
} }
function hideByClass(context, className) { function hideByClass(context, className) {
var elems = context.querySelectorAll('.' + className); for (const elem of context.querySelectorAll(`.${className}`)) {
elem.classList.add('hide');
for (var i = 0, length = elems.length; i < length; i++) {
elems[i].classList.add('hide');
} }
} }
function enableDynamicFilters(mode) { function enableDynamicFilters(mode) {
return mode == 'movies' || mode == 'series' || mode == 'albums' || mode == 'albumartists' || mode == 'artists' || mode == 'songs' || mode == 'episodes'; return mode === 'movies' || mode === 'series' || mode === 'albums' || mode === 'albumartists' || mode === 'artists' || mode === 'songs' || mode === 'episodes';
} }
return function (options) { class FilterDialog {
function onFavoriteChange() { constructor(options) {
var query = options.query; /**
query.StartIndex = 0; * @private
query.IsFavorite = !!this.checked || null; */
triggerChange(self); this.options = options;
} }
function onStandardFilterChange() { /**
var query = options.query; * @private
var filterName = this.getAttribute('data-filter'); */
var filters = query.Filters || ''; onFavoriteChange(elem) {
filters = (',' + filters).replace(',' + filterName, '').substring(1); const query = this.options.query;
query.StartIndex = 0;
query.IsFavorite = !!elem.checked || null;
triggerChange(this);
}
if (this.checked) { /**
filters = filters ? filters + ',' + filterName : filterName; * @private
*/
onStandardFilterChange(elem) {
const query = this.options.query;
const filterName = elem.getAttribute('data-filter');
let filters = query.Filters || '';
filters = (`,${filters}`).replace(`,${filterName}`, '').substring(1);
if (elem.checked) {
filters = filters ? `${filters},${filterName}` : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.Filters = filters; query.Filters = filters;
triggerChange(self); triggerChange(this);
} }
function onVideoTypeFilterChange() { /**
var query = options.query; * @private
var filterName = this.getAttribute('data-filter'); */
var filters = query.VideoTypes || ''; onVideoTypeFilterChange(elem) {
filters = (',' + filters).replace(',' + filterName, '').substring(1); const query = this.options.query;
const filterName = elem.getAttribute('data-filter');
let filters = query.VideoTypes || '';
filters = (`,${filters}`).replace(`,${filterName}`, '').substring(1);
if (this.checked) { if (elem.checked) {
filters = filters ? filters + ',' + filterName : filterName; filters = filters ? `${filters},${filterName}` : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.VideoTypes = filters; query.VideoTypes = filters;
triggerChange(self); triggerChange(this);
} }
function onStatusChange() { /**
var query = options.query; * @private
var filterName = this.getAttribute('data-filter'); */
var filters = query.SeriesStatus || ''; onStatusChange(elem) {
filters = (',' + filters).replace(',' + filterName, '').substring(1); const query = this.options.query;
const filterName = elem.getAttribute('data-filter');
let filters = query.SeriesStatus || '';
filters = (`,${filters}`).replace(`,${filterName}`, '').substring(1);
if (this.checked) { if (elem.checked) {
filters = filters ? filters + ',' + filterName : filterName; filters = filters ? `${filters},${filterName}` : filterName;
} }
query.SeriesStatus = filters; query.SeriesStatus = filters;
query.StartIndex = 0; query.StartIndex = 0;
triggerChange(self); triggerChange(this);
} }
function bindEvents(context) { /**
var elems; * @param context {HTMLDivElement} The dialog
var i; */
var length; bindEvents(context) {
var query = options.query; const query = this.options.query;
if (options.mode == 'livetvchannels') { if (this.options.mode === 'livetvchannels') {
elems = context.querySelectorAll('.chkFavorite'); for (const elem of context.querySelectorAll('.chkFavorite')) {
for (i = 0, length = elems.length; i < length; i++) { elem.addEventListener('change', () => this.onFavoriteChange(elem));
elems[i].addEventListener('change', onFavoriteChange);
} }
context.querySelector('.chkLikes').addEventListener('change', function () {
const chkLikes = context.querySelector('.chkLikes');
chkLikes.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsLiked = this.checked ? true : null; query.IsLiked = chkLikes.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('.chkDislikes').addEventListener('change', function () { const chkDislikes = context.querySelector('.chkDislikes');
chkDislikes.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsDisliked = this.checked ? true : null; query.IsDisliked = chkDislikes.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
} else { } else {
elems = context.querySelectorAll('.chkStandardFilter'); for (const elem of context.querySelectorAll('.chkStandardFilter')) {
for (i = 0, length = elems.length; i < length; i++) { elem.addEventListener('change', () => this.onStandardFilterChange(elem));
elems[i].addEventListener('change', onStandardFilterChange);
} }
} }
elems = context.querySelectorAll('.chkVideoTypeFilter');
for (i = 0, length = elems.length; i < length; i++) { for (const elem of context.querySelectorAll('.chkVideoTypeFilter')) {
elems[i].addEventListener('change', onVideoTypeFilterChange); elem.addEventListener('change', () => this.onVideoTypeFilterChange(elem));
} }
context.querySelector('.chk3DFilter').addEventListener('change', function () { const chk3DFilter = context.querySelector('.chk3DFilter');
chk3DFilter.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.Is3D = this.checked ? true : null; query.Is3D = chk3DFilter.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('.chk4KFilter').addEventListener('change', function () { const chk4KFilter = context.querySelector('.chk4KFilter');
chk4KFilter.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.Is4K = this.checked ? true : null; query.Is4K = chk4KFilter.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('.chkHDFilter').addEventListener('change', function () { const chkHDFilter = context.querySelector('.chkHDFilter');
chkHDFilter.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsHD = this.checked ? true : null; query.IsHD = chkHDFilter.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('.chkSDFilter').addEventListener('change', function () { const chkSDFilter = context.querySelector('.chkSDFilter');
chkSDFilter.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsHD = this.checked ? false : null; query.IsHD = chkSDFilter.checked ? false : null;
triggerChange(self); triggerChange(this);
}); });
elems = context.querySelectorAll('.chkStatus'); for (const elem of context.querySelectorAll('.chkStatus')) {
for (i = 0, length = elems.length; i < length; i++) { elem.addEventListener('change', () => this.onStatusChange(elem));
elems[i].addEventListener('change', onStatusChange);
} }
context.querySelector('#chkTrailer').addEventListener('change', function () { const chkTrailer = context.querySelector('#chkTrailer');
chkTrailer.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasTrailer = this.checked ? true : null; query.HasTrailer = chkTrailer.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkThemeSong').addEventListener('change', function () { const chkThemeSong = context.querySelector('#chkThemeSong');
chkThemeSong.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasThemeSong = this.checked ? true : null; query.HasThemeSong = chkThemeSong.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkSpecialFeature').addEventListener('change', function () { const chkSpecialFeature = context.querySelector('#chkSpecialFeature');
chkSpecialFeature.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasSpecialFeature = this.checked ? true : null; query.HasSpecialFeature = chkSpecialFeature.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkThemeVideo').addEventListener('change', function () { const chkThemeVideo = context.querySelector('#chkThemeVideo');
chkThemeVideo.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasThemeVideo = this.checked ? true : null; query.HasThemeVideo = chkThemeVideo.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkMissingEpisode').addEventListener('change', function () { const chkMissingEpisode = context.querySelector('#chkMissingEpisode');
chkMissingEpisode.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.IsMissing = this.checked ? true : false; query.IsMissing = !!chkMissingEpisode.checked;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkSpecialEpisode').addEventListener('change', function () { const chkSpecialEpisode = context.querySelector('#chkSpecialEpisode');
chkSpecialEpisode.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.ParentIndexNumber = this.checked ? 0 : null; query.ParentIndexNumber = chkSpecialEpisode.checked ? 0 : null;
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkFutureEpisode').addEventListener('change', function () { const chkFutureEpisode = context.querySelector('#chkFutureEpisode');
chkFutureEpisode.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
if (this.checked) { if (chkFutureEpisode.checked) {
query.IsUnaired = true; query.IsUnaired = true;
query.IsVirtualUnaired = null; query.IsVirtualUnaired = null;
} else { } else {
query.IsUnaired = null; query.IsUnaired = null;
query.IsVirtualUnaired = false; query.IsVirtualUnaired = false;
} }
triggerChange(self); triggerChange(this);
}); });
context.querySelector('#chkSubtitle').addEventListener('change', function () { const chkSubtitle = context.querySelector('#chkSubtitle');
chkSubtitle.addEventListener('change', () => {
query.StartIndex = 0; query.StartIndex = 0;
query.HasSubtitles = this.checked ? true : null; query.HasSubtitles = chkSubtitle.checked ? true : null;
triggerChange(self); triggerChange(this);
}); });
context.addEventListener('change', function (e) { context.addEventListener('change', (e) => {
var chkGenreFilter = dom.parentWithClass(e.target, 'chkGenreFilter'); const chkGenreFilter = dom.parentWithClass(e.target, 'chkGenreFilter');
if (chkGenreFilter) { if (chkGenreFilter) {
var filterName = chkGenreFilter.getAttribute('data-filter'); const filterName = chkGenreFilter.getAttribute('data-filter');
var filters = query.Genres || ''; let filters = query.Genres || '';
var delimiter = '|'; const delimiter = '|';
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
if (chkGenreFilter.checked) { if (chkGenreFilter.checked) {
filters = filters ? (filters + delimiter + filterName) : filterName; filters = filters ? (filters + delimiter + filterName) : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.Genres = filters; query.Genres = filters;
triggerChange(self); triggerChange(this);
return; return;
} }
var chkTagFilter = dom.parentWithClass(e.target, 'chkTagFilter'); const chkTagFilter = dom.parentWithClass(e.target, 'chkTagFilter');
if (chkTagFilter) { if (chkTagFilter) {
var filterName = chkTagFilter.getAttribute('data-filter'); const filterName = chkTagFilter.getAttribute('data-filter');
var filters = query.Tags || ''; let filters = query.Tags || '';
var delimiter = '|'; const delimiter = '|';
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
if (chkTagFilter.checked) { if (chkTagFilter.checked) {
filters = filters ? (filters + delimiter + filterName) : filterName; filters = filters ? (filters + delimiter + filterName) : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.Tags = filters; query.Tags = filters;
triggerChange(self); triggerChange(this);
return; return;
} }
var chkYearFilter = dom.parentWithClass(e.target, 'chkYearFilter'); const chkYearFilter = dom.parentWithClass(e.target, 'chkYearFilter');
if (chkYearFilter) { if (chkYearFilter) {
var filterName = chkYearFilter.getAttribute('data-filter'); const filterName = chkYearFilter.getAttribute('data-filter');
var filters = query.Years || ''; let filters = query.Years || '';
var delimiter = ','; const delimiter = ',';
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
if (chkYearFilter.checked) { if (chkYearFilter.checked) {
filters = filters ? (filters + delimiter + filterName) : filterName; filters = filters ? (filters + delimiter + filterName) : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.Years = filters; query.Years = filters;
triggerChange(self); triggerChange(this);
return; return;
} }
var chkOfficialRatingFilter = dom.parentWithClass(e.target, 'chkOfficialRatingFilter'); const chkOfficialRatingFilter = dom.parentWithClass(e.target, 'chkOfficialRatingFilter');
if (chkOfficialRatingFilter) { if (chkOfficialRatingFilter) {
var filterName = chkOfficialRatingFilter.getAttribute('data-filter'); const filterName = chkOfficialRatingFilter.getAttribute('data-filter');
var filters = query.OfficialRatings || ''; let filters = query.OfficialRatings || '';
var delimiter = '|'; const delimiter = '|';
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
if (chkOfficialRatingFilter.checked) { if (chkOfficialRatingFilter.checked) {
filters = filters ? (filters + delimiter + filterName) : filterName; filters = filters ? (filters + delimiter + filterName) : filterName;
} }
query.StartIndex = 0; query.StartIndex = 0;
query.OfficialRatings = filters; query.OfficialRatings = filters;
triggerChange(self); triggerChange(this);
return;
} }
}); });
} }
var self = this; show() {
return import('text!./filterdialog.template.html').then(({default: template}) => {
self.show = function () { return new Promise((resolve) => {
return new Promise(function (resolve, reject) { const dlg = dialogHelper.createDialog({
require(['text!./filterdialog.template.html'], function (template) {
var dlg = dialogHelper.createDialog({
removeOnClose: true, removeOnClose: true,
modal: false modal: false
}); });
@ -379,19 +412,22 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
dlg.classList.add('background-theme-a'); dlg.classList.add('background-theme-a');
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');
dlg.classList.add('filterDialog'); dlg.classList.add('filterDialog');
dlg.innerHTML = globalize.translateDocument(template); dlg.innerHTML = globalize.translateHtml(template);
setVisibility(dlg, options); setVisibility(dlg, this.options);
dialogHelper.open(dlg); dialogHelper.open(dlg);
dlg.addEventListener('close', resolve); dlg.addEventListener('close', resolve);
updateFilterControls(dlg, options); updateFilterControls(dlg, this.options);
bindEvents(dlg); this.bindEvents(dlg);
if (enableDynamicFilters(options.mode)) { if (enableDynamicFilters(this.options.mode)) {
dlg.classList.add('dynamicFilterDialog'); dlg.classList.add('dynamicFilterDialog');
var apiClient = connectionManager.getApiClient(options.serverId); const apiClient = connectionManager.getApiClient(this.options.serverId);
loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), options.query); loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), this.options.query);
} }
}); });
}); });
}; }
}; }
});
/* eslint-enable indent */
export default FilterDialog;

View file

@ -2,19 +2,15 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
'use strict'; 'use strict';
function onSubmit(e) { function onSubmit(e) {
e.preventDefault(); e.preventDefault();
return false; return false;
} }
function renderOptions(context, selector, cssClass, items, isCheckedFn) { function renderOptions(context, selector, cssClass, items, isCheckedFn) {
var elem = context.querySelector(selector); var elem = context.querySelector(selector);
if (items.length) { if (items.length) {
elem.classList.remove('hide'); elem.classList.remove('hide');
} else { } else {
elem.classList.add('hide'); elem.classList.add('hide');
} }
@ -22,7 +18,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
var html = ''; var html = '';
html += items.map(function (filter) { html += items.map(function (filter) {
var itemHtml = ''; var itemHtml = '';
var checkedHtml = isCheckedFn(filter) ? ' checked' : ''; var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
@ -32,45 +27,20 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
itemHtml += '</label>'; itemHtml += '</label>';
return itemHtml; return itemHtml;
}).join(''); }).join('');
elem.querySelector('.filterOptions').innerHTML = html; elem.querySelector('.filterOptions').innerHTML = html;
} }
function renderDynamicFilters(context, result, options) { function renderDynamicFilters(context, result, options) {
// If there's a huge number of these they will be really show to render
//if (result.Tags) {
// result.Tags.length = Math.min(result.Tags.length, 50);
//}
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) { renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
// Switching from | to , // Switching from | to ,
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|'; var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1; return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
}); });
//renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
// var delimeter = '|';
// return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
//});
//renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
// var delimeter = '|';
// return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
//});
//renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
// var delimeter = ',';
// return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
//});
} }
function loadDynamicFilters(context, options) { function loadDynamicFilters(context, options) {
var apiClient = connectionManager.getApiClient(options.serverId); var apiClient = connectionManager.getApiClient(options.serverId);
var filterMenuOptions = Object.assign(options.filterMenuOptions, { var filterMenuOptions = Object.assign(options.filterMenuOptions, {
@ -81,16 +51,11 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
}); });
apiClient.getFilters(filterMenuOptions).then(function (result) { apiClient.getFilters(filterMenuOptions).then(function (result) {
renderDynamicFilters(context, result, options); renderDynamicFilters(context, result, options);
}, function () {
// older server
}); });
} }
function initEditor(context, settings) { function initEditor(context, settings) {
context.querySelector('form').addEventListener('submit', onSubmit); context.querySelector('form').addEventListener('submit', onSubmit);
var elems = context.querySelectorAll('.simpleFilter'); var elems = context.querySelectorAll('.simpleFilter');
@ -98,7 +63,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
var length; var length;
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].tagName === 'INPUT') { if (elems[i].tagName === 'INPUT') {
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false; elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
} else { } else {
@ -110,7 +74,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
elems = context.querySelectorAll('.chkVideoTypeFilter'); elems = context.querySelectorAll('.chkVideoTypeFilter');
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1; elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
} }
@ -118,7 +81,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
elems = context.querySelectorAll('.chkSeriesStatus'); elems = context.querySelectorAll('.chkSeriesStatus');
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1; elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
} }
@ -136,12 +98,10 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
} }
function saveValues(context, settings, settingsKey) { function saveValues(context, settings, settingsKey) {
var elems = context.querySelectorAll('.simpleFilter'); var elems = context.querySelectorAll('.simpleFilter');
var i; var i;
var length; var length;
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].tagName === 'INPUT') { if (elems[i].tagName === 'INPUT') {
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]); setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
} else { } else {
@ -154,7 +114,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
elems = context.querySelectorAll('.chkVideoTypeFilter'); elems = context.querySelectorAll('.chkVideoTypeFilter');
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].checked) { if (elems[i].checked) {
videoTypes.push(elems[i].getAttribute('data-filter')); videoTypes.push(elems[i].getAttribute('data-filter'));
} }
@ -166,7 +125,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
elems = context.querySelectorAll('.chkSeriesStatus'); elems = context.querySelectorAll('.chkSeriesStatus');
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].checked) { if (elems[i].checked) {
seriesStatuses.push(elems[i].getAttribute('data-filter')); seriesStatuses.push(elems[i].getAttribute('data-filter'));
} }
@ -177,7 +135,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
elems = context.querySelectorAll('.chkGenreFilter'); elems = context.querySelectorAll('.chkGenreFilter');
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].checked) { if (elems[i].checked) {
genres.push(elems[i].getAttribute('data-filter')); genres.push(elems[i].getAttribute('data-filter'));
} }
@ -186,7 +143,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
} }
function setBasicFilter(context, key, elem) { function setBasicFilter(context, key, elem) {
var value = elem.checked; var value = elem.checked;
value = value ? value : null; value = value ? value : null;
userSettings.setFilter(key, value); userSettings.setFilter(key, value);
@ -200,7 +156,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
} }
function moveCheckboxFocus(elem, offset) { function moveCheckboxFocus(elem, offset) {
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap'); var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
var elems = focusManager.getFocusableElements(parent); var elems = focusManager.getFocusableElements(parent);
@ -225,7 +180,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
function onInputCommand(e) { function onInputCommand(e) {
switch (e.detail.command) { switch (e.detail.command) {
case 'left': case 'left':
moveCheckboxFocus(e.target, -1); moveCheckboxFocus(e.target, -1);
e.preventDefault(); e.preventDefault();
@ -244,7 +198,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
} }
function bindCheckboxInput(context, on) { function bindCheckboxInput(context, on) {
var elems = context.querySelectorAll('.checkboxList-verticalwrap'); var elems = context.querySelectorAll('.checkboxList-verticalwrap');
for (var i = 0, length = elems.length; i < length; i++) { for (var i = 0, length = elems.length; i < length; i++) {
if (on) { if (on) {
@ -256,11 +209,8 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
} }
FilterMenu.prototype.show = function (options) { FilterMenu.prototype.show = function (options) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
require(['text!./filtermenu.template.html'], function (template) { require(['text!./filtermenu.template.html'], function (template) {
var dialogOptions = { var dialogOptions = {
removeOnClose: true, removeOnClose: true,
scrollY: false scrollY: false
@ -286,7 +236,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
html += template; html += template;
dlg.innerHTML = globalize.translateDocument(html, 'core'); dlg.innerHTML = globalize.translateHtml(html, 'core');
var settingElements = dlg.querySelectorAll('.viewSetting'); var settingElements = dlg.querySelectorAll('.viewSetting');
for (var i = 0, length = settingElements.length; i < length; i++) { for (var i = 0, length = settingElements.length; i < length; i++) {
@ -303,7 +253,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
bindCheckboxInput(dlg, true); bindCheckboxInput(dlg, true);
dlg.querySelector('.btnCancel').addEventListener('click', function () { dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg); dialogHelper.close(dlg);
}); });
@ -314,17 +263,10 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
var submitted; var submitted;
dlg.querySelector('form').addEventListener('change', function () { dlg.querySelector('form').addEventListener('change', function () {
submitted = true; submitted = true;
//if (options.onChange) {
// saveValues(dlg, options.settings, options.settingsKey);
// options.onChange();
//}
}, true); }, true);
dialogHelper.open(dlg).then(function () { dialogHelper.open(dlg).then(function () {
bindCheckboxInput(dlg, false); bindCheckboxInput(dlg, false);
if (layoutManager.tv) { if (layoutManager.tv) {
@ -332,7 +274,6 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
} }
if (submitted) { if (submitted) {
//if (!options.onChange) { //if (!options.onChange) {
saveValues(dlg, options.settings, options.settingsKey); saveValues(dlg, options.settings, options.settingsKey);
resolve(); resolve();

View file

@ -7,14 +7,12 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function popScope(elem) { function popScope(elem) {
if (scopes.length) { if (scopes.length) {
scopes.length -= 1; scopes.length -= 1;
} }
} }
function autoFocus(view, defaultToFirst, findAutoFocusElement) { function autoFocus(view, defaultToFirst, findAutoFocusElement) {
var element; var element;
if (findAutoFocusElement !== false) { if (findAutoFocusElement !== false) {
element = view.querySelector('*[autofocus]'); element = view.querySelector('*[autofocus]');
@ -37,7 +35,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function focus(element) { function focus(element) {
try { try {
element.focus({ element.focus({
preventScroll: scrollManager.isEnabled() preventScroll: scrollManager.isEnabled()
@ -50,16 +47,13 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A']; var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'];
var focusableContainerTagNames = ['BODY', 'DIALOG']; var focusableContainerTagNames = ['BODY', 'DIALOG'];
var focusableQuery = focusableTagNames.map(function (t) { var focusableQuery = focusableTagNames.map(function (t) {
if (t === 'INPUT') { if (t === 'INPUT') {
t += ':not([type="range"]):not([type="file"])'; t += ':not([type="range"]):not([type="file"])';
} }
return t + ':not([tabindex="-1"]):not(:disabled)'; return t + ':not([tabindex="-1"]):not(:disabled)';
}).join(',') + ',.focusable'; }).join(',') + ',.focusable';
function isFocusable(elem) { function isFocusable(elem) {
if (focusableTagNames.indexOf(elem.tagName) !== -1) { if (focusableTagNames.indexOf(elem.tagName) !== -1) {
return true; return true;
} }
@ -83,7 +77,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function focusableParent(elem) { function focusableParent(elem) {
var originalElement = elem; var originalElement = elem;
while (!isFocusable(elem)) { while (!isFocusable(elem)) {
@ -101,7 +94,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
// Determines if a focusable element can be focused at a given point in time // Determines if a focusable element can be focused at a given point in time
function isCurrentlyFocusableInternal(elem) { function isCurrentlyFocusableInternal(elem) {
// http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom // http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
if (elem.offsetParent === null) { if (elem.offsetParent === null) {
return false; return false;
@ -112,7 +104,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
// Determines if a focusable element can be focused at a given point in time // Determines if a focusable element can be focused at a given point in time
function isCurrentlyFocusable(elem) { function isCurrentlyFocusable(elem) {
if (elem.disabled) { if (elem.disabled) {
return false; return false;
} }
@ -143,7 +134,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
var focusableElements = []; var focusableElements = [];
for (var i = 0, length = elems.length; i < length; i++) { for (var i = 0, length = elems.length; i < length; i++) {
var elem = elems[i]; var elem = elems[i];
if (excludeClass && elem.classList.contains(excludeClass)) { if (excludeClass && elem.classList.contains(excludeClass)) {
@ -163,7 +153,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function isFocusContainer(elem, direction) { function isFocusContainer(elem, direction) {
if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) { if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) {
return true; return true;
} }
@ -217,7 +206,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function getOffset(elem) { function getOffset(elem) {
var box; var box;
// Support: BlackBerry 5, iOS 3 (original iPhone) // Support: BlackBerry 5, iOS 3 (original iPhone)
@ -234,7 +222,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
if (box.right === null) { if (box.right === null) {
// Create a new object because some browsers will throw an error when trying to set data onto the Rect object // Create a new object because some browsers will throw an error when trying to set data onto the Rect object
var newBox = { var newBox = {
top: box.top, top: box.top,
@ -253,7 +240,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function nav(activeElement, direction, container, focusableElements) { function nav(activeElement, direction, container, focusableElements) {
activeElement = activeElement || document.activeElement; activeElement = activeElement || document.activeElement;
if (activeElement) { if (activeElement) {
@ -272,14 +258,10 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
var rect = getOffset(activeElement); var rect = getOffset(activeElement);
// Get elements and work out x/y points // Get elements and work out x/y points
var cache = [];
var point1x = parseFloat(rect.left) || 0; var point1x = parseFloat(rect.left) || 0;
var point1y = parseFloat(rect.top) || 0; var point1y = parseFloat(rect.top) || 0;
var point2x = parseFloat(point1x + rect.width - 1) || point1x; var point2x = parseFloat(point1x + rect.width - 1) || point1x;
var point2y = parseFloat(point1y + rect.height - 1) || point1y; var point2y = parseFloat(point1y + rect.height - 1) || point1y;
// Shortcuts to help with compression
var min = Math.min;
var max = Math.max;
var sourceMidX = rect.left + (rect.width / 2); var sourceMidX = rect.left + (rect.width / 2);
var sourceMidY = rect.top + (rect.height / 2); var sourceMidY = rect.top + (rect.height / 2);
@ -301,10 +283,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
continue; continue;
} }
//if (!isCurrentlyFocusableInternal(curr)) {
// continue;
//}
var elementRect = getOffset(curr); var elementRect = getOffset(curr);
// not currently visible // not currently visible
@ -313,7 +291,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
switch (direction) { switch (direction) {
case 0: case 0:
// left // left
if (elementRect.left >= rect.left) { if (elementRect.left >= rect.left) {
@ -369,7 +346,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
var distY; var distY;
switch (direction) { switch (direction) {
case 0: case 0:
// left // left
distX = Math.abs(point1x - Math.min(point1x, x2)); distX = Math.abs(point1x - Math.min(point1x, x2));
@ -403,7 +379,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
if (nearestElement) { if (nearestElement) {
// See if there's a focusable container, and if so, send the focus command to that // See if there's a focusable container, and if so, send the focus command to that
if (activeElement) { if (activeElement) {
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable'); var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
@ -418,12 +393,10 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function intersectsInternal(a1, a2, b1, b2) { function intersectsInternal(a1, a2, b1, b2) {
return (b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2); return (b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2);
} }
function intersects(a1, a2, b1, b2) { function intersects(a1, a2, b1, b2) {
return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2); return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2);
} }
@ -434,11 +407,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function focusFirst(container, focusableSelector) { function focusFirst(container, focusableSelector) {
var elems = container.querySelectorAll(focusableSelector); var elems = container.querySelectorAll(focusableSelector);
for (var i = 0, length = elems.length; i < length; i++) { for (var i = 0, length = elems.length; i < length; i++) {
var elem = elems[i]; var elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) { if (isCurrentlyFocusableInternal(elem)) {
@ -449,11 +420,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function focusLast(container, focusableSelector) { function focusLast(container, focusableSelector) {
var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse(); var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse();
for (var i = 0, length = elems.length; i < length; i++) { for (var i = 0, length = elems.length; i < length; i++) {
var elem = elems[i]; var elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) { if (isCurrentlyFocusableInternal(elem)) {
@ -464,7 +433,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
} }
function moveFocus(sourceElement, container, focusableSelector, offset) { function moveFocus(sourceElement, container, focusableSelector, offset) {
var elems = container.querySelectorAll(focusableSelector); var elems = container.querySelectorAll(focusableSelector);
var list = []; var list = [];
var i; var i;
@ -472,7 +440,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
var elem; var elem;
for (i = 0, length = elems.length; i < length; i++) { for (i = 0, length = elems.length; i < length; i++) {
elem = elems[i]; elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) { if (isCurrentlyFocusableInternal(elem)) {
@ -483,7 +450,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
var currentIndex = -1; var currentIndex = -1;
for (i = 0, length = list.length; i < length; i++) { for (i = 0, length = list.length; i < length; i++) {
elem = list[i]; elem = list[i];
if (sourceElement === elem || elem.contains(sourceElement)) { if (sourceElement === elem || elem.contains(sourceElement)) {

View file

@ -19,6 +19,10 @@
margin-bottom: 0; margin-bottom: 0;
} }
.formDialogHeaderTitle:first-child {
margin-left: 1em;
}
.formDialogContent:not(.no-grow) { .formDialogContent:not(.no-grow) {
flex-grow: 1; flex-grow: 1;
} }
@ -46,10 +50,16 @@
right: 0; right: 0;
display: flex; display: flex;
position: absolute; position: absolute;
padding: 1.25em 1em; padding: 1em 1em;
/* Without this emby-checkbox is able to appear on top */ /* Without this emby-checkbox is able to appear on top */
z-index: 1; z-index: 1;
align-items: flex-end;
justify-content: center;
flex-wrap: wrap;
}
.layout-tv .formDialogFooter {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
@ -69,8 +79,12 @@
.formDialogFooterItem { .formDialogFooterItem {
margin: 0.5em !important; margin: 0.5em !important;
flex-grow: 1;
text-align: center; text-align: center;
flex-basis: 12em;
}
.layout-tv .formDialogFooterItem {
flex-grow: 1;
flex-basis: 0; flex-basis: 0;
} }

View file

@ -1,5 +1,8 @@
define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, connectionManager) { /* eslint-disable indent */
'use strict';
import dom from 'dom';
import appRouter from 'appRouter';
import connectionManager from 'connectionManager';
function onGroupedCardClick(e, card) { function onGroupedCardClick(e, card) {
var itemId = card.getAttribute('data-id'); var itemId = card.getAttribute('data-id');
@ -18,11 +21,11 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn
if (!actionableParent || actionableParent.classList.contains('cardContent')) { if (!actionableParent || actionableParent.classList.contains('cardContent')) {
apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) { apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
if (1 === items.length) { if (items.length === 1) {
return void appRouter.showItem(items[0]); return void appRouter.showItem(items[0]);
} }
var url = 'itemdetails.html?id=' + itemId + '&serverId=' + serverId; var url = 'details?id=' + itemId + '&serverId=' + serverId;
Dashboard.navigate(url); Dashboard.navigate(url);
}); });
e.stopPropagation(); e.stopPropagation();
@ -31,7 +34,7 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn
} }
} }
function onItemsContainerClick(e) { export default function onItemsContainerClick(e) {
var groupedCard = dom.parentWithClass(e.target, 'groupedCard'); var groupedCard = dom.parentWithClass(e.target, 'groupedCard');
if (groupedCard) { if (groupedCard) {
@ -39,7 +42,4 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn
} }
} }
return { /* eslint-enable indent */
onItemsContainerClick: onItemsContainerClick
};
});

View file

@ -2,12 +2,10 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
'use strict'; 'use strict';
function saveCategories(context, options) { function saveCategories(context, options) {
var categories = []; var categories = [];
var chkCategorys = context.querySelectorAll('.chkCategory'); var chkCategorys = context.querySelectorAll('.chkCategory');
for (var i = 0, length = chkCategorys.length; i < length; i++) { for (var i = 0, length = chkCategorys.length; i < length; i++) {
var type = chkCategorys[i].getAttribute('data-type'); var type = chkCategorys[i].getAttribute('data-type');
if (chkCategorys[i].checked) { if (chkCategorys[i].checked) {
@ -25,12 +23,10 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
} }
function loadCategories(context, options) { function loadCategories(context, options) {
var selectedCategories = options.categories || []; var selectedCategories = options.categories || [];
var chkCategorys = context.querySelectorAll('.chkCategory'); var chkCategorys = context.querySelectorAll('.chkCategory');
for (var i = 0, length = chkCategorys.length; i < length; i++) { for (var i = 0, length = chkCategorys.length; i < length; i++) {
var type = chkCategorys[i].getAttribute('data-type'); var type = chkCategorys[i].getAttribute('data-type');
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1; chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
@ -38,13 +34,11 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
} }
function save(context) { function save(context) {
var i; var i;
var length; var length;
var chkIndicators = context.querySelectorAll('.chkIndicator'); var chkIndicators = context.querySelectorAll('.chkIndicator');
for (i = 0, length = chkIndicators.length; i < length; i++) { for (i = 0, length = chkIndicators.length; i < length; i++) {
var type = chkIndicators[i].getAttribute('data-type'); var type = chkIndicators[i].getAttribute('data-type');
userSettings.set('guide-indicator-' + type, chkIndicators[i].checked); userSettings.set('guide-indicator-' + type, chkIndicators[i].checked);
} }
@ -62,13 +56,11 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
} }
function load(context) { function load(context) {
var i; var i;
var length; var length;
var chkIndicators = context.querySelectorAll('.chkIndicator'); var chkIndicators = context.querySelectorAll('.chkIndicator');
for (i = 0, length = chkIndicators.length; i < length; i++) { for (i = 0, length = chkIndicators.length; i < length; i++) {
var type = chkIndicators[i].getAttribute('data-type'); var type = chkIndicators[i].getAttribute('data-type');
if (chkIndicators[i].getAttribute('data-default') === 'true') { if (chkIndicators[i].getAttribute('data-default') === 'true') {
@ -90,13 +82,10 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
} }
function showEditor(options) { function showEditor(options) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var settingsChanged = false; var settingsChanged = false;
require(['text!./guide-settings.template.html'], function (template) { require(['text!./guide-settings.template.html'], function (template) {
var dialogOptions = { var dialogOptions = {
removeOnClose: true, removeOnClose: true,
scrollY: false scrollY: false
@ -114,17 +103,15 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio
var html = ''; var html = '';
html += globalize.translateDocument(template, 'core'); html += globalize.translateHtml(template, 'core');
dlg.innerHTML = html; dlg.innerHTML = html;
dlg.addEventListener('change', function () { dlg.addEventListener('change', function () {
settingsChanged = true; settingsChanged = true;
}); });
dlg.addEventListener('close', function () { dlg.addEventListener('close', function () {
if (layoutManager.tv) { if (layoutManager.tv) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
} }

View file

@ -1,5 +1,7 @@
<div class="formDialogHeader"> <div class="formDialogHeader">
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button> <button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
<span class="material-icons arrow_back" aria-hidden="true"></span>
</button>
<h3 class="formDialogHeaderTitle"> <h3 class="formDialogHeaderTitle">
${Settings} ${Settings}
</h3> </h3>

View file

@ -1,8 +1,11 @@
define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-programcell', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'registerElement'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) { define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-programcell', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'webcomponents'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) {
'use strict'; 'use strict';
function showViewSettings(instance) { playbackManager = playbackManager.default || playbackManager;
browser = browser.default || browser;
loading = loading.default || loading;
function showViewSettings(instance) {
require(['guide-settings-dialog'], function (guideSettingsDialog) { require(['guide-settings-dialog'], function (guideSettingsDialog) {
guideSettingsDialog.show(instance.categoryOptions).then(function () { guideSettingsDialog.show(instance.categoryOptions).then(function () {
instance.refresh(); instance.refresh();
@ -11,7 +14,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function updateProgramCellOnScroll(cell, scrollPct) { function updateProgramCellOnScroll(cell, scrollPct) {
var left = cell.posLeft; var left = cell.posLeft;
if (!left) { if (!left) {
left = parseFloat(cell.style.left.replace('%', '')); left = parseFloat(cell.style.left.replace('%', ''));
@ -43,11 +45,9 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
if (guideProgramName) { if (guideProgramName) {
if (pctOfWidth > 0 && pctOfWidth <= 100) { if (pctOfWidth > 0 && pctOfWidth <= 100) {
//guideProgramName.style.marginLeft = pctOfWidth + '%';
guideProgramName.style.transform = 'translateX(' + pctOfWidth + '%)'; guideProgramName.style.transform = 'translateX(' + pctOfWidth + '%)';
caret.classList.remove('hide'); caret.classList.remove('hide');
} else { } else {
//guideProgramName.style.marginLeft = '0';
guideProgramName.style.transform = 'none'; guideProgramName.style.transform = 'none';
caret.classList.add('hide'); caret.classList.add('hide');
} }
@ -56,7 +56,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var isUpdatingProgramCellScroll = false; var isUpdatingProgramCellScroll = false;
function updateProgramCellsOnScroll(programGrid, programCells) { function updateProgramCellsOnScroll(programGrid, programCells) {
if (isUpdatingProgramCellScroll) { if (isUpdatingProgramCellScroll) {
return; return;
} }
@ -64,13 +63,11 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
isUpdatingProgramCellScroll = true; isUpdatingProgramCellScroll = true;
requestAnimationFrame(function () { requestAnimationFrame(function () {
var scrollLeft = programGrid.scrollLeft; var scrollLeft = programGrid.scrollLeft;
var scrollPct = scrollLeft ? (scrollLeft / programGrid.scrollWidth) * 100 : 0; var scrollPct = scrollLeft ? (scrollLeft / programGrid.scrollWidth) * 100 : 0;
for (var i = 0, length = programCells.length; i < length; i++) { for (var i = 0, length = programCells.length; i < length; i++) {
updateProgramCellOnScroll(programCells[i], scrollPct); updateProgramCellOnScroll(programCells[i], scrollPct);
} }
@ -79,14 +76,12 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function onProgramGridClick(e) { function onProgramGridClick(e) {
if (!layoutManager.tv) { if (!layoutManager.tv) {
return; return;
} }
var programCell = dom.parentWithClass(e.target, 'programCell'); var programCell = dom.parentWithClass(e.target, 'programCell');
if (programCell) { if (programCell) {
var startDate = programCell.getAttribute('data-startdate'); var startDate = programCell.getAttribute('data-startdate');
var endDate = programCell.getAttribute('data-enddate'); var endDate = programCell.getAttribute('data-enddate');
startDate = datetime.parseISO8601Date(startDate, { toLocal: true }).getTime(); startDate = datetime.parseISO8601Date(startDate, { toLocal: true }).getTime();
@ -94,7 +89,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var now = new Date().getTime(); var now = new Date().getTime();
if (now >= startDate && now < endDate) { if (now >= startDate && now < endDate) {
var channelId = programCell.getAttribute('data-channelid'); var channelId = programCell.getAttribute('data-channelid');
var serverId = programCell.getAttribute('data-serverid'); var serverId = programCell.getAttribute('data-serverid');
@ -110,7 +104,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function Guide(options) { function Guide(options) {
var self = this; var self = this;
var items = {}; var items = {};
@ -121,7 +114,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var cellCurationMinutes = 30; var cellCurationMinutes = 30;
var cellDurationMs = cellCurationMinutes * 60 * 1000; var cellDurationMs = cellCurationMinutes * 60 * 1000;
var msPerDay = 86400000; var msPerDay = 86400000;
var totalRendererdMs = msPerDay;
var currentDate; var currentDate;
var currentStartIndex = 0; var currentStartIndex = 0;
@ -132,7 +124,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var programGrid; var programGrid;
self.refresh = function () { self.refresh = function () {
currentDate = null; currentDate = null;
reloadPage(options.element); reloadPage(options.element);
restartAutoRefresh(); restartAutoRefresh();
@ -151,7 +142,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
}; };
self.destroy = function () { self.destroy = function () {
stopAutoRefresh(); stopAutoRefresh();
events.off(serverNotifications, 'TimerCreated', onTimerCreated); events.off(serverNotifications, 'TimerCreated', onTimerCreated);
@ -165,7 +155,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
}; };
function restartAutoRefresh() { function restartAutoRefresh() {
stopAutoRefresh(); stopAutoRefresh();
var intervalMs = 60000 * 15; // (minutes) var intervalMs = 60000 * 15; // (minutes)
@ -183,15 +172,11 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function normalizeDateToTimeslot(date) { function normalizeDateToTimeslot(date) {
var minutesOffset = date.getMinutes() - cellCurationMinutes; var minutesOffset = date.getMinutes() - cellCurationMinutes;
if (minutesOffset >= 0) { if (minutesOffset >= 0) {
date.setHours(date.getHours(), cellCurationMinutes, 0, 0); date.setHours(date.getHours(), cellCurationMinutes, 0, 0);
} else { } else {
date.setHours(date.getHours(), 0, 0, 0); date.setHours(date.getHours(), 0, 0, 0);
} }
@ -207,7 +192,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function reloadGuide(context, newStartDate, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) { function reloadGuide(context, newStartDate, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) {
var apiClient = connectionManager.getApiClient(options.serverId); var apiClient = connectionManager.getApiClient(options.serverId);
var channelQuery = { var channelQuery = {
@ -290,12 +274,10 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
}; };
apiClient.getLiveTvChannels(channelQuery).then(function (channelsResult) { apiClient.getLiveTvChannels(channelQuery).then(function (channelsResult) {
var btnPreviousPage = context.querySelector('.btnPreviousPage'); var btnPreviousPage = context.querySelector('.btnPreviousPage');
var btnNextPage = context.querySelector('.btnNextPage'); var btnNextPage = context.querySelector('.btnNextPage');
if (channelsResult.TotalRecordCount > channelLimit) { if (channelsResult.TotalRecordCount > channelLimit) {
context.querySelector('.guideOptions').classList.remove('hide'); context.querySelector('.guideOptions').classList.remove('hide');
btnPreviousPage.classList.remove('hide'); btnPreviousPage.classList.remove('hide');
@ -312,7 +294,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} else { } else {
btnNextPage.disabled = true; btnNextPage.disabled = true;
} }
} else { } else {
context.querySelector('.guideOptions').classList.add('hide'); context.querySelector('.guideOptions').classList.add('hide');
} }
@ -343,22 +324,17 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) { apiClient.getLiveTvPrograms(programQuery).then(function (programsResult) {
renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender); renderGuide(context, date, channelsResult.Items, programsResult.Items, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender);
hideLoading(); hideLoading();
}); });
}); });
} }
function getDisplayTime(date) { function getDisplayTime(date) {
if ((typeof date).toString().toLowerCase() === 'string') { if ((typeof date).toString().toLowerCase() === 'string') {
try { try {
date = datetime.parseISO8601Date(date, { toLocal: true }); date = datetime.parseISO8601Date(date, { toLocal: true });
} catch (err) { } catch (err) {
return date; return date;
} }
@ -368,7 +344,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function getTimeslotHeadersHtml(startDate, endDateTime) { function getTimeslotHeadersHtml(startDate, endDateTime) {
var html = ''; var html = '';
// clone // clone
@ -377,7 +352,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
html += '<div class="timeslotHeadersInner">'; html += '<div class="timeslotHeadersInner">';
while (startDate.getTime() < endDateTime) { while (startDate.getTime() < endDateTime) {
html += '<div class="timeslotHeader">'; html += '<div class="timeslotHeader">';
html += getDisplayTime(startDate); html += getDisplayTime(startDate);
@ -411,23 +385,19 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function getTimerIndicator(item) { function getTimerIndicator(item) {
var status; var status;
if (item.Type === 'SeriesTimer') { if (item.Type === 'SeriesTimer') {
return '<span class="material-icons programIcon seriesTimerIcon fiber_smart_record"></span>'; return '<span class="material-icons programIcon seriesTimerIcon fiber_smart_record"></span>';
} else if (item.TimerId || item.SeriesTimerId) { } else if (item.TimerId || item.SeriesTimerId) {
status = item.Status || 'Cancelled'; status = item.Status || 'Cancelled';
} else if (item.Type === 'Timer') { } else if (item.Type === 'Timer') {
status = item.Status; status = item.Status;
} else { } else {
return ''; return '';
} }
if (item.SeriesTimerId) { if (item.SeriesTimerId) {
if (status !== 'Cancelled') { if (status !== 'Cancelled') {
return '<span class="material-icons programIcon seriesTimerIcon fiber_smart_record"></span>'; return '<span class="material-icons programIcon seriesTimerIcon fiber_smart_record"></span>';
} }
@ -439,7 +409,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function getChannelProgramsHtml(context, date, channel, programs, options, listInfo) { function getChannelProgramsHtml(context, date, channel, programs, options, listInfo) {
var html = ''; var html = '';
var startMs = date.getTime(); var startMs = date.getTime();
@ -463,11 +432,9 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var now = new Date().getTime(); var now = new Date().getTime();
for (var i = listInfo.startIndex, length = programs.length; i < length; i++) { for (var i = listInfo.startIndex, length = programs.length; i < length; i++) {
var program = programs[i]; var program = programs[i];
if (program.ChannelId !== channel.Id) { if (program.ChannelId !== channel.Id) {
if (programsFound) { if (programsFound) {
break; break;
} }
@ -577,7 +544,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
html += '</div>'; html += '</div>';
if (program.IsHD && options.showHdIcon) { if (program.IsHD && options.showHdIcon) {
//html += '<span class="guideHdIcon material-icons programIcon hd"></span>';
if (layoutManager.tv) { if (layoutManager.tv) {
html += '<div class="programIcon guide-programTextIcon guide-programTextIcon-tv">HD</div>'; html += '<div class="programIcon guide-programTextIcon guide-programTextIcon-tv">HD</div>';
} else { } else {
@ -599,11 +565,9 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function renderChannelHeaders(context, channels, apiClient) { function renderChannelHeaders(context, channels, apiClient) {
var html = ''; var html = '';
for (var i = 0, length = channels.length; i < length; i++) { for (var i = 0, length = channels.length; i < length; i++) {
var channel = channels[i]; var channel = channels[i];
var hasChannelImage = channel.ImageTags.Primary; var hasChannelImage = channel.ImageTags.Primary;
@ -615,18 +579,15 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var title = []; var title = [];
if (channel.ChannelNumber) { if (channel.ChannelNumber) {
title.push(channel.ChannelNumber); title.push(channel.ChannelNumber);
} }
if (channel.Name) { if (channel.Name) {
title.push(channel.Name); title.push(channel.Name);
} }
html += '<button title="' + title.join(' ') + '" type="button" class="' + cssClass + '"' + ' data-action="link" data-isfolder="' + channel.IsFolder + '" data-id="' + channel.Id + '" data-serverid="' + channel.ServerId + '" data-type="' + channel.Type + '">'; html += '<button title="' + title.join(' ') + '" type="button" class="' + cssClass + '"' + ' data-action="link" data-isfolder="' + channel.IsFolder + '" data-id="' + channel.Id + '" data-serverid="' + channel.ServerId + '" data-type="' + channel.Type + '">';
if (hasChannelImage) { if (hasChannelImage) {
var url = apiClient.getScaledImageUrl(channel.Id, { var url = apiClient.getScaledImageUrl(channel.Id, {
maxHeight: 220, maxHeight: 220,
tag: channel.ImageTags.Primary, tag: channel.ImageTags.Primary,
@ -637,7 +598,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
if (channel.ChannelNumber) { if (channel.ChannelNumber) {
html += '<h3 class="guideChannelNumber">' + channel.ChannelNumber + '</h3>'; html += '<h3 class="guideChannelNumber">' + channel.ChannelNumber + '</h3>';
} }
@ -654,7 +614,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function renderPrograms(context, date, channels, programs, options) { function renderPrograms(context, date, channels, programs, options) {
var listInfo = { var listInfo = {
startIndex: 0 startIndex: 0
}; };
@ -662,7 +621,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var html = []; var html = [];
for (var i = 0, length = channels.length; i < length; i++) { for (var i = 0, length = channels.length; i < length; i++) {
html.push(getChannelProgramsHtml(context, date, channels[i], programs, options, listInfo)); html.push(getChannelProgramsHtml(context, date, channels[i], programs, options, listInfo));
} }
@ -674,7 +632,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function getProgramSortOrder(program, channels) { function getProgramSortOrder(program, channels) {
var channelId = program.ChannelId; var channelId = program.ChannelId;
var channelIndex = -1; var channelIndex = -1;
@ -691,7 +648,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function renderGuide(context, date, channels, programs, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) { function renderGuide(context, date, channels, programs, renderOptions, apiClient, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) {
programs.sort(function (a, b) { programs.sort(function (a, b) {
return getProgramSortOrder(a, channels) - getProgramSortOrder(b, channels); return getProgramSortOrder(a, channels) - getProgramSortOrder(b, channels);
}); });
@ -721,7 +677,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs) { function scrollProgramGridToTimeMs(context, scrollToTimeMs, startTimeOfDayMs) {
scrollToTimeMs -= startTimeOfDayMs; scrollToTimeMs -= startTimeOfDayMs;
var pct = scrollToTimeMs / msPerDay; var pct = scrollToTimeMs / msPerDay;
@ -734,7 +689,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs) { function focusProgram(context, itemId, channelRowId, focusToTimeMs, startTimeOfDayMs) {
var focusElem; var focusElem;
if (itemId) { if (itemId) {
focusElem = context.querySelector('[data-id="' + itemId + '"]'); focusElem = context.querySelector('[data-id="' + itemId + '"]');
@ -743,7 +697,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
if (focusElem) { if (focusElem) {
focusManager.focus(focusElem); focusManager.focus(focusElem);
} else { } else {
var autoFocusParent; var autoFocusParent;
if (channelRowId) { if (channelRowId) {
@ -761,7 +714,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var programCell = autoFocusParent.querySelector('.programCell'); var programCell = autoFocusParent.querySelector('.programCell');
while (programCell) { while (programCell) {
var left = (programCell.style.left || '').replace('%', ''); var left = (programCell.style.left || '').replace('%', '');
left = left ? parseFloat(left) : 0; left = left ? parseFloat(left) : 0;
var width = (programCell.style.width || '').replace('%', ''); var width = (programCell.style.width || '').replace('%', '');
@ -782,7 +734,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function nativeScrollTo(container, pos, horizontal) { function nativeScrollTo(container, pos, horizontal) {
if (container.scrollTo) { if (container.scrollTo) {
if (horizontal) { if (horizontal) {
container.scrollTo(pos, 0); container.scrollTo(pos, 0);
@ -802,7 +753,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var lastHeaderScroll = 0; var lastHeaderScroll = 0;
var scrollXPct = 0; var scrollXPct = 0;
function onProgramGridScroll(context, elem, timeslotHeaders) { function onProgramGridScroll(context, elem, timeslotHeaders) {
if ((new Date().getTime() - lastHeaderScroll) >= 1000) { if ((new Date().getTime() - lastHeaderScroll) >= 1000) {
lastGridScroll = new Date().getTime(); lastGridScroll = new Date().getTime();
@ -815,7 +765,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function onTimeslotHeadersScroll(context, elem) { function onTimeslotHeadersScroll(context, elem) {
if ((new Date().getTime() - lastGridScroll) >= 1000) { if ((new Date().getTime() - lastGridScroll) >= 1000) {
lastHeaderScroll = new Date().getTime(); lastHeaderScroll = new Date().getTime();
nativeScrollTo(programGrid, elem.scrollLeft, true); nativeScrollTo(programGrid, elem.scrollLeft, true);
@ -823,7 +772,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function changeDate(page, date, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) { function changeDate(page, date, scrollToTimeMs, focusToTimeMs, startTimeOfDayMs, focusProgramOnRender) {
var newStartDate = normalizeDateToTimeslot(date); var newStartDate = normalizeDateToTimeslot(date);
currentDate = newStartDate; currentDate = newStartDate;
@ -831,7 +779,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function getDateTabText(date, isActive, tabIndex) { function getDateTabText(date, isActive, tabIndex) {
var cssClass = isActive ? 'emby-tab-button guide-date-tab-button emby-tab-button-active' : 'emby-tab-button guide-date-tab-button'; var cssClass = isActive ? 'emby-tab-button guide-date-tab-button emby-tab-button-active' : 'emby-tab-button guide-date-tab-button';
var html = '<button is="emby-button" class="' + cssClass + '" data-index="' + tabIndex + '" data-date="' + date.getTime() + '">'; var html = '<button is="emby-button" class="' + cssClass + '" data-index="' + tabIndex + '" data-date="' + date.getTime() + '">';
@ -846,7 +793,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function setDateRange(page, guideInfo) { function setDateRange(page, guideInfo) {
var today = new Date(); var today = new Date();
var nowHours = today.getHours(); var nowHours = today.getHours();
today.setHours(nowHours, 0, 0, 0); today.setHours(nowHours, 0, 0, 0);
@ -866,6 +812,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var dateTabsHtml = ''; var dateTabsHtml = '';
var tabIndex = 0; var tabIndex = 0;
// TODO: Use date-fns
var date = new Date(); var date = new Date();
if (currentDate) { if (currentDate) {
@ -873,13 +820,11 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
date.setHours(nowHours, 0, 0, 0); date.setHours(nowHours, 0, 0, 0);
//start.setHours(0, 0, 0, 0);
var startTimeOfDayMs = (start.getHours() * 60 * 60 * 1000); var startTimeOfDayMs = (start.getHours() * 60 * 60 * 1000);
startTimeOfDayMs += start.getMinutes() * 60 * 1000; startTimeOfDayMs += start.getMinutes() * 60 * 1000;
while (start <= end) { while (start <= end) {
var isActive = date.getDate() === start.getDate() && date.getMonth() === start.getMonth() && date.getFullYear() === start.getFullYear(); var isActive = date.getDate() === start.getDate() && date.getMonth() === start.getMonth() && date.getFullYear() === start.getFullYear();
dateTabsHtml += getDateTabText(start, isActive, tabIndex); dateTabsHtml += getDateTabText(start, isActive, tabIndex);
@ -906,19 +851,16 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function reloadPage(page) { function reloadPage(page) {
showLoading(); showLoading();
var apiClient = connectionManager.getApiClient(options.serverId); var apiClient = connectionManager.getApiClient(options.serverId);
apiClient.getLiveTvGuideInfo().then(function (guideInfo) { apiClient.getLiveTvGuideInfo().then(function (guideInfo) {
setDateRange(page, guideInfo); setDateRange(page, guideInfo);
}); });
} }
function getChannelProgramsFocusableElements(container) { function getChannelProgramsFocusableElements(container) {
var elements = container.querySelectorAll('.programCell'); var elements = container.querySelectorAll('.programCell');
var list = []; var list = [];
@ -926,7 +868,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var currentScrollXPct = scrollXPct + 1; var currentScrollXPct = scrollXPct + 1;
for (var i = 0, length = elements.length; i < length; i++) { for (var i = 0, length = elements.length; i < length; i++) {
var elem = elements[i]; var elem = elements[i];
var left = (elem.style.left || '').replace('%', ''); var left = (elem.style.left || '').replace('%', '');
@ -943,7 +884,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function onInputCommand(e) { function onInputCommand(e) {
var target = e.target; var target = e.target;
var programCell = dom.parentWithClass(target, 'programCell'); var programCell = dom.parentWithClass(target, 'programCell');
var container; var container;
@ -951,10 +891,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
var focusableElements; var focusableElements;
var newRow; var newRow;
var scrollX = false;
switch (e.detail.command) { switch (e.detail.command) {
case 'up': case 'up':
if (programCell) { if (programCell) {
container = programGrid; container = programGrid;
@ -1018,7 +955,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
focusManager.moveLeft(target, { focusManager.moveLeft(target, {
container: container container: container
}); });
scrollX = true;
break; break;
case 'right': case 'right':
container = programCell ? dom.parentWithClass(programCell, 'channelPrograms') : null; container = programCell ? dom.parentWithClass(programCell, 'channelPrograms') : null;
@ -1027,7 +963,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
focusManager.moveRight(target, { focusManager.moveRight(target, {
container: container container: container
}); });
scrollX = true;
break; break;
default: default:
return; return;
@ -1038,7 +973,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function onScrollerFocus(e) { function onScrollerFocus(e) {
var target = e.target; var target = e.target;
var programCell = dom.parentWithClass(target, 'programCell'); var programCell = dom.parentWithClass(target, 'programCell');
@ -1057,22 +991,16 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
if (lastFocusDirection === 'left') { if (lastFocusDirection === 'left') {
if (programCell) { if (programCell) {
scrollHelper.toStart(programGrid, programCell, true, true); scrollHelper.toStart(programGrid, programCell, true, true);
} }
} else if (lastFocusDirection === 'right') { } else if (lastFocusDirection === 'right') {
if (programCell) { if (programCell) {
scrollHelper.toCenter(programGrid, programCell, true, true); scrollHelper.toCenter(programGrid, programCell, true, true);
} }
} else if (lastFocusDirection === 'up' || lastFocusDirection === 'down') { } else if (lastFocusDirection === 'up' || lastFocusDirection === 'down') {
var verticalScroller = dom.parentWithClass(target, 'guideVerticalScroller'); var verticalScroller = dom.parentWithClass(target, 'guideVerticalScroller');
if (verticalScroller) { if (verticalScroller) {
var focusedElement = programCell || dom.parentWithTag(target, 'BUTTON'); var focusedElement = programCell || dom.parentWithTag(target, 'BUTTON');
verticalScroller.toCenter(focusedElement, true); verticalScroller.toCenter(focusedElement, true);
} }
@ -1080,7 +1008,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function setScrollEvents(view, enabled) { function setScrollEvents(view, enabled) {
if (layoutManager.tv) { if (layoutManager.tv) {
var guideVerticalScroller = view.querySelector('.guideVerticalScroller'); var guideVerticalScroller = view.querySelector('.guideVerticalScroller');
@ -1093,7 +1020,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
function onTimerCreated(e, apiClient, data) { function onTimerCreated(e, apiClient, data) {
var programId = data.ProgramId; var programId = data.ProgramId;
// This could be null, not supported by all tv providers // This could be null, not supported by all tv providers
var newTimerId = data.Id; var newTimerId = data.Id;
@ -1146,12 +1072,11 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
require(['text!./tvguide.template.html'], function (template) { require(['text!./tvguide.template.html'], function (template) {
var context = options.element; var context = options.element;
context.classList.add('tvguide'); context.classList.add('tvguide');
context.innerHTML = globalize.translateDocument(template, 'core'); context.innerHTML = globalize.translateHtml(template, 'core');
programGrid = context.querySelector('.programGrid'); programGrid = context.querySelector('.programGrid');
var timeslotHeaders = context.querySelector('.timeslotHeaders'); var timeslotHeaders = context.querySelector('.timeslotHeaders');
@ -1203,12 +1128,10 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
}); });
context.querySelector('.guideDateTabs').addEventListener('tabchange', function (e) { context.querySelector('.guideDateTabs').addEventListener('tabchange', function (e) {
var allTabButtons = e.target.querySelectorAll('.guide-date-tab-button'); var allTabButtons = e.target.querySelectorAll('.guide-date-tab-button');
var tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex)]; var tabButton = allTabButtons[parseInt(e.detail.selectedTabIndex)];
if (tabButton) { if (tabButton) {
var previousButton = e.detail.previousIndex == null ? null : allTabButtons[parseInt(e.detail.previousIndex)]; var previousButton = e.detail.previousIndex == null ? null : allTabButtons[parseInt(e.detail.previousIndex)];
var date = new Date(); var date = new Date();
@ -1223,7 +1146,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
} }
if (previousButton) { if (previousButton) {
var previousDate = new Date(); var previousDate = new Date();
previousDate.setTime(parseInt(previousButton.getAttribute('data-date'))); previousDate.setTime(parseInt(previousButton.getAttribute('data-date')));

View file

@ -9,8 +9,8 @@
<div class="guide-headerTimeslots"> <div class="guide-headerTimeslots">
<div class="guide-channelTimeslotHeader"> <div class="guide-channelTimeslotHeader">
<button is="paper-icon-button-light" type="button" class="btnGuideViewSettings"> <button is="paper-icon-button-light" type="button" class="btnGuideViewSettings" title="${ButtonMore}">
<span class="material-icons btnGuideViewSettingsIcon more_horiz"></span> <span class="material-icons btnGuideViewSettingsIcon more_vert" aria-hidden="true"></span>
</button> </button>
</div> </div>
<div class="timeslotHeaders scrollX guideScroller"></div> <div class="timeslotHeaders scrollX guideScroller"></div>
@ -29,10 +29,10 @@
</div> </div>
<div class="guideOptions hide"> <div class="guideOptions hide">
<button is="paper-icon-button-light" type="button" class="btnPreviousPage"> <button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${LabelPrevious}">
<span class="material-icons arrow_back"></span> <span class="material-icons arrow_back" aria-hidden="true"></span>
</button> </button>
<button is="paper-icon-button-light" type="button" class="btnNextPage"> <button is="paper-icon-button-light" type="button" class="btnNextPage" title="${LabelNext}">
<span class="material-icons arrow_forward"></span> <span class="material-icons arrow_forward" aria-hidden="true"></span>
</button> </button>
</div> </div>

View file

@ -1,30 +1,38 @@
define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loading', 'connectionManager', 'homeSections', 'dom', 'events', 'listViewStyle', 'emby-select', 'emby-checkbox'], function (require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) { import layoutManager from 'layoutManager';
'use strict'; import focusManager from 'focusManager';
import globalize from 'globalize';
import loading from 'loading';
import connectionManager from 'connectionManager';
import homeSections from 'homeSections';
import dom from 'dom';
import events from 'events';
import 'listViewStyle';
import 'emby-select';
import 'emby-checkbox';
var numConfigurableSections = 7; /* eslint-disable indent */
const numConfigurableSections = 7;
function renderViews(page, user, result) { function renderViews(page, user, result) {
let folderHtml = '';
var folderHtml = '';
folderHtml += '<div class="checkboxList">'; folderHtml += '<div class="checkboxList">';
folderHtml += result.map(function (i) { folderHtml += result.map(i => {
let currentHtml = '';
var currentHtml = ''; const id = `chkGroupFolder${i.Id}`;
var id = 'chkGroupFolder' + i.Id; const isChecked = user.Configuration.GroupedFolders.includes(i.Id);
var isChecked = user.Configuration.GroupedFolders.indexOf(i.Id) !== -1; const checkedHtml = isChecked ? ' checked="checked"' : '';
var checkedHtml = isChecked ? ' checked="checked"' : '';
currentHtml += '<label>'; currentHtml += '<label>';
currentHtml += '<input type="checkbox" is="emby-checkbox" class="chkGroupFolder" data-folderid="' + i.Id + '" id="' + id + '"' + checkedHtml + '/>'; currentHtml += `<input type="checkbox" is="emby-checkbox" class="chkGroupFolder" data-folderid="${i.Id}" id="${id}"${checkedHtml}/>`;
currentHtml += '<span>' + i.Name + '</span>'; currentHtml += `<span>${i.Name}</span>`;
currentHtml += '</label>'; currentHtml += '</label>';
return currentHtml; return currentHtml;
}).join(''); }).join('');
folderHtml += '</div>'; folderHtml += '</div>';
@ -33,22 +41,22 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
function getLandingScreenOptions(type) { function getLandingScreenOptions(type) {
const list = [];
var list = [];
if (type === 'movies') { if (type === 'movies') {
list.push({ list.push({
name: globalize.translate('Movies'), name: globalize.translate('Movies'),
value: 'movies', value: 'movies',
isDefault: true isDefault: true
}); });
list.push({ list.push({
name: globalize.translate('Suggestions'), name: globalize.translate('Suggestions'),
value: 'suggestions' value: 'suggestions'
}); });
list.push({
name: globalize.translate('Genres'),
value: 'genres'
});
list.push({ list.push({
name: globalize.translate('Favorites'), name: globalize.translate('Favorites'),
value: 'favorites' value: 'favorites'
@ -58,7 +66,6 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
value: 'collections' value: 'collections'
}); });
} else if (type === 'tvshows') { } else if (type === 'tvshows') {
list.push({ list.push({
name: globalize.translate('Shows'), name: globalize.translate('Shows'),
value: 'shows', value: 'shows',
@ -68,49 +75,45 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
name: globalize.translate('Suggestions'), name: globalize.translate('Suggestions'),
value: 'suggestions' value: 'suggestions'
}); });
list.push({ list.push({
name: globalize.translate('Latest'), name: globalize.translate('Latest'),
value: 'latest' value: 'latest'
}); });
list.push({
name: globalize.translate('Genres'),
value: 'genres'
});
list.push({ list.push({
name: globalize.translate('Favorites'), name: globalize.translate('Favorites'),
value: 'favorites' value: 'favorites'
}); });
} else if (type === 'music') { } else if (type === 'music') {
list.push({ list.push({
name: globalize.translate('Suggestions'), name: globalize.translate('Suggestions'),
value: 'suggestions', value: 'suggestions',
isDefault: true isDefault: true
}); });
list.push({ list.push({
name: globalize.translate('Albums'), name: globalize.translate('Albums'),
value: 'albums' value: 'albums'
}); });
list.push({ list.push({
name: globalize.translate('HeaderAlbumArtists'), name: globalize.translate('HeaderAlbumArtists'),
value: 'albumartists' value: 'albumartists'
}); });
list.push({ list.push({
name: globalize.translate('Artists'), name: globalize.translate('Artists'),
value: 'artists' value: 'artists'
}); });
list.push({ list.push({
name: globalize.translate('Playlists'), name: globalize.translate('Playlists'),
value: 'playlists' value: 'playlists'
}); });
list.push({ list.push({
name: globalize.translate('Genres'), name: globalize.translate('Genres'),
value: 'genres' value: 'genres'
}); });
} else if (type === 'livetv') { } else if (type === 'livetv') {
list.push({ list.push({
name: globalize.translate('Suggestions'), name: globalize.translate('Suggestions'),
value: 'suggestions', value: 'suggestions',
@ -126,28 +129,22 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
function getLandingScreenOptionsHtml(type, userValue) { function getLandingScreenOptionsHtml(type, userValue) {
return getLandingScreenOptions(type).map(o => {
const selected = userValue === o.value || (o.isDefault && !userValue);
const selectedHtml = selected ? ' selected' : '';
const optionValue = o.isDefault ? '' : o.value;
return getLandingScreenOptions(type).map(function (o) { return `<option value="${optionValue}"${selectedHtml}>${o.name}</option>`;
var selected = userValue === o.value || (o.isDefault && !userValue);
var selectedHtml = selected ? ' selected' : '';
var optionValue = o.isDefault ? '' : o.value;
return '<option value="' + optionValue + '"' + selectedHtml + '>' + o.name + '</option>';
}).join(''); }).join('');
} }
function renderViewOrder(context, user, result) { function renderViewOrder(context, user, result) {
let html = '';
var html = ''; html += result.Items.map((view) => {
let currentHtml = '';
var index = 0; currentHtml += `<div class="listItem viewItem" data-viewid="${view.Id}">`;
html += result.Items.map(function (view) {
var currentHtml = '';
currentHtml += '<div class="listItem viewItem" data-viewid="' + view.Id + '">';
currentHtml += '<span class="material-icons listItemIcon folder_open"></span>'; currentHtml += '<span class="material-icons listItemIcon folder_open"></span>';
@ -159,29 +156,25 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
currentHtml += '</div>'; currentHtml += '</div>';
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemUp btnViewItemMove autoSize" title="' + globalize.translate('Up') + '"><span class="material-icons keyboard_arrow_up"></span></button>'; currentHtml += `<button type="button" is="paper-icon-button-light" class="btnViewItemUp btnViewItemMove autoSize" title="${globalize.translate('Up')}"><span class="material-icons keyboard_arrow_up"></span></button>`;
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="' + globalize.translate('Down') + '"><span class="material-icons keyboard_arrow_down"></span></button>'; currentHtml += `<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="${globalize.translate('Down')}"><span class="material-icons keyboard_arrow_down"></span></button>`;
currentHtml += '</div>'; currentHtml += '</div>';
index++;
return currentHtml; return currentHtml;
}).join(''); }).join('');
context.querySelector('.viewOrderList').innerHTML = html; context.querySelector('.viewOrderList').innerHTML = html;
} }
function updateHomeSectionValues(context, userSettings) { function updateHomeSectionValues(context, userSettings) {
for (let i = 1; i <= 7; i++) {
const select = context.querySelector(`#selectHomeSection${i}`);
const defaultValue = homeSections.getDefaultSection(i - 1);
for (var i = 1; i <= 7; i++) { const option = select.querySelector(`option[value=${defaultValue}]`) || select.querySelector('option[value=""]');
var select = context.querySelector('#selectHomeSection' + i); const userValue = userSettings.get(`homesection${i - 1}`);
var defaultValue = homeSections.getDefaultSection(i - 1);
var option = select.querySelector('option[value=' + defaultValue + ']') || select.querySelector('option[value=""]');
var userValue = userSettings.get('homesection' + (i - 1));
option.value = ''; option.value = '';
@ -196,43 +189,39 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
function getPerLibrarySettingsHtml(item, user, userSettings, apiClient) { function getPerLibrarySettingsHtml(item, user, userSettings, apiClient) {
let html = '';
var html = ''; let isChecked;
var isChecked;
if (item.Type === 'Channel' || item.CollectionType === 'boxsets' || item.CollectionType === 'playlists') { if (item.Type === 'Channel' || item.CollectionType === 'boxsets' || item.CollectionType === 'playlists') {
isChecked = (user.Configuration.MyMediaExcludes || []).indexOf(item.Id) === -1; isChecked = !(user.Configuration.MyMediaExcludes || []).includes(item.Id);
html += '<div>'; html += '<div>';
html += '<label>'; html += '<label>';
html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInMyMedia" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : '') + '/>'; html += `<input type="checkbox" is="emby-checkbox" class="chkIncludeInMyMedia" data-folderid="${item.Id}"${isChecked ? ' checked="checked"' : ''}/>`;
html += '<span>' + globalize.translate('DisplayInMyMedia') + '</span>'; html += `<span>${globalize.translate('DisplayInMyMedia')}</span>`;
html += '</label>'; html += '</label>';
html += '</div>'; html += '</div>';
} }
var excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels']; const excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels'];
if (excludeFromLatest.indexOf(item.CollectionType || '') === -1) { if (!excludeFromLatest.includes(item.CollectionType || '')) {
isChecked = !user.Configuration.LatestItemsExcludes.includes(item.Id);
isChecked = user.Configuration.LatestItemsExcludes.indexOf(item.Id) === -1;
html += '<label class="fldIncludeInLatest">'; html += '<label class="fldIncludeInLatest">';
html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : '') + '/>'; html += `<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="${item.Id}"${isChecked ? ' checked="checked"' : ''}/>`;
html += '<span>' + globalize.translate('DisplayInOtherHomeScreenSections') + '</span>'; html += `<span>${globalize.translate('DisplayInOtherHomeScreenSections')}</span>`;
html += '</label>'; html += '</label>';
} }
if (html) { if (html) {
html = `<div class="checkboxListContainer">${html}</div>`;
html = '<div class="checkboxListContainer">' + html + '</div>';
} }
if (item.CollectionType === 'movies' || item.CollectionType === 'tvshows' || item.CollectionType === 'music' || item.CollectionType === 'livetv') { if (item.CollectionType === 'movies' || item.CollectionType === 'tvshows' || item.CollectionType === 'music' || item.CollectionType === 'livetv') {
const idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id;
var idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id;
html += '<div class="selectContainer">'; html += '<div class="selectContainer">';
html += '<select is="emby-select" class="selectLanding" data-folderid="' + idForLanding + '" label="' + globalize.translate('LabelDefaultScreen') + '">'; html += `<select is="emby-select" class="selectLanding" data-folderid="${idForLanding}" label="${globalize.translate('LabelDefaultScreen')}">`;
var userValue = userSettings.get('landing-' + idForLanding); const userValue = userSettings.get(`landing-${idForLanding}`);
html += getLandingScreenOptionsHtml(item.CollectionType, userValue); html += getLandingScreenOptionsHtml(item.CollectionType, userValue);
@ -241,8 +230,7 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
if (html) { if (html) {
let prefix = '';
var prefix = '';
prefix += '<div class="verticalSection">'; prefix += '<div class="verticalSection">';
prefix += '<h2 class="sectionTitle">'; prefix += '<h2 class="sectionTitle">';
@ -257,12 +245,10 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
function renderPerLibrarySettings(context, user, userViews, userSettings, apiClient) { function renderPerLibrarySettings(context, user, userViews, userSettings, apiClient) {
const elem = context.querySelector('.perLibrarySettings');
let html = '';
var elem = context.querySelector('.perLibrarySettings'); for (let i = 0, length = userViews.length; i < length; i++) {
var html = '';
for (var i = 0, length = userViews.length; i < length; i++) {
html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient); html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient);
} }
@ -270,16 +256,14 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
function loadForm(context, user, userSettings, apiClient) { function loadForm(context, user, userSettings, apiClient) {
context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false; context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false;
updateHomeSectionValues(context, userSettings); updateHomeSectionValues(context, userSettings);
var promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id); const promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id);
var promise2 = apiClient.getJSON(apiClient.getUrl('Users/' + user.Id + '/GroupingOptions')); const promise2 = apiClient.getJSON(apiClient.getUrl(`Users/${user.Id}/GroupingOptions`));
Promise.all([promise1, promise2]).then(function (responses) {
Promise.all([promise1, promise2]).then(responses => {
renderViewOrder(context, user, responses[0]); renderViewOrder(context, user, responses[0]);
renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient); renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient);
@ -290,48 +274,23 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
}); });
} }
function getSibling(elem, type, className) {
var sibling = elem[type];
while (sibling != null) {
if (sibling.classList.contains(className)) {
break;
}
}
if (sibling != null) {
if (!sibling.classList.contains(className)) {
sibling = null;
}
}
return sibling;
}
function onSectionOrderListClick(e) { function onSectionOrderListClick(e) {
const target = dom.parentWithClass(e.target, 'btnViewItemMove');
var target = dom.parentWithClass(e.target, 'btnViewItemMove');
if (target) { if (target) {
var viewItem = dom.parentWithClass(target, 'viewItem'); const viewItem = dom.parentWithClass(target, 'viewItem');
if (viewItem) { if (viewItem) {
var ul = dom.parentWithClass(viewItem, 'paperList');
if (target.classList.contains('btnViewItemDown')) { if (target.classList.contains('btnViewItemDown')) {
const next = viewItem.nextSibling;
var next = viewItem.nextSibling;
if (next) { if (next) {
viewItem.parentNode.removeChild(viewItem); viewItem.parentNode.removeChild(viewItem);
next.parentNode.insertBefore(viewItem, next.nextSibling); next.parentNode.insertBefore(viewItem, next.nextSibling);
focusManager.focus(e.target); focusManager.focus(e.target);
} }
} else { } else {
const prev = viewItem.previousSibling;
var prev = viewItem.previousSibling;
if (prev) { if (prev) {
viewItem.parentNode.removeChild(viewItem); viewItem.parentNode.removeChild(viewItem);
@ -344,44 +303,37 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
function getCheckboxItems(selector, context, isChecked) { function getCheckboxItems(selector, context, isChecked) {
const inputs = context.querySelectorAll(selector);
const list = [];
var inputs = context.querySelectorAll(selector); for (let i = 0, length = inputs.length; i < length; i++) {
var list = [];
for (var i = 0, length = inputs.length; i < length; i++) {
if (inputs[i].checked === isChecked) { if (inputs[i].checked === isChecked) {
list.push(inputs[i]); list.push(inputs[i]);
} }
} }
return list; return list;
} }
function saveUser(context, user, userSettingsInstance, apiClient) { function saveUser(context, user, userSettingsInstance, apiClient) {
user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked; user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked;
user.Configuration.LatestItemsExcludes = getCheckboxItems('.chkIncludeInLatest', context, false).map(function (i) { user.Configuration.LatestItemsExcludes = getCheckboxItems('.chkIncludeInLatest', context, false).map(i => {
return i.getAttribute('data-folderid'); return i.getAttribute('data-folderid');
}); });
user.Configuration.MyMediaExcludes = getCheckboxItems('.chkIncludeInMyMedia', context, false).map(function (i) { user.Configuration.MyMediaExcludes = getCheckboxItems('.chkIncludeInMyMedia', context, false).map(i => {
return i.getAttribute('data-folderid'); return i.getAttribute('data-folderid');
}); });
user.Configuration.GroupedFolders = getCheckboxItems('.chkGroupFolder', context, true).map(function (i) { user.Configuration.GroupedFolders = getCheckboxItems('.chkGroupFolder', context, true).map(i => {
return i.getAttribute('data-folderid'); return i.getAttribute('data-folderid');
}); });
var viewItems = context.querySelectorAll('.viewItem'); const viewItems = context.querySelectorAll('.viewItem');
var orderedViews = []; const orderedViews = [];
var i; let i;
var length; let length;
for (i = 0, length = viewItems.length; i < length; i++) { for (i = 0, length = viewItems.length; i < length; i++) {
orderedViews.push(viewItems[i].getAttribute('data-viewid')); orderedViews.push(viewItems[i].getAttribute('data-viewid'));
} }
@ -398,48 +350,42 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
userSettingsInstance.set('homesection5', context.querySelector('#selectHomeSection6').value); userSettingsInstance.set('homesection5', context.querySelector('#selectHomeSection6').value);
userSettingsInstance.set('homesection6', context.querySelector('#selectHomeSection7').value); userSettingsInstance.set('homesection6', context.querySelector('#selectHomeSection7').value);
var selectLandings = context.querySelectorAll('.selectLanding'); const selectLandings = context.querySelectorAll('.selectLanding');
for (i = 0, length = selectLandings.length; i < length; i++) { for (i = 0, length = selectLandings.length; i < length; i++) {
var selectLanding = selectLandings[i]; const selectLanding = selectLandings[i];
userSettingsInstance.set('landing-' + selectLanding.getAttribute('data-folderid'), selectLanding.value); userSettingsInstance.set(`landing-${selectLanding.getAttribute('data-folderid')}`, selectLanding.value);
} }
return apiClient.updateUserConfiguration(user.Id, user.Configuration); return apiClient.updateUserConfiguration(user.Id, user.Configuration);
} }
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) { function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loading.show(); loading.show();
apiClient.getUser(userId).then(function (user) { apiClient.getUser(userId).then(user => {
saveUser(context, user, userSettings, apiClient).then(() => {
saveUser(context, user, userSettings, apiClient).then(function () {
loading.hide(); loading.hide();
if (enableSaveConfirmation) { if (enableSaveConfirmation) {
require(['toast'], function (toast) { import('toast').then(({default: toast}) => {
toast(globalize.translate('SettingsSaved')); toast(globalize.translate('SettingsSaved'));
}); });
} }
events.trigger(instance, 'saved'); events.trigger(instance, 'saved');
}, () => {
}, function () {
loading.hide(); loading.hide();
}); });
}); });
} }
function onSubmit(e) { function onSubmit(e) {
const self = this;
const apiClient = connectionManager.getApiClient(self.options.serverId);
const userId = self.options.userId;
const userSettings = self.options.userSettings;
var self = this; userSettings.setUserInfo(userId, apiClient).then(() => {
var apiClient = connectionManager.getApiClient(self.options.serverId); const enableSaveConfirmation = self.options.enableSaveConfirmation;
var userId = self.options.userId;
var userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(function () {
var enableSaveConfirmation = self.options.enableSaveConfirmation;
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation); save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
}); });
@ -451,14 +397,13 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
function onChange(e) { function onChange(e) {
const chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
var chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
if (!chkIncludeInMyMedia) { if (!chkIncludeInMyMedia) {
return; return;
} }
var section = dom.parentWithClass(chkIncludeInMyMedia, 'verticalSection'); const section = dom.parentWithClass(chkIncludeInMyMedia, 'verticalSection');
var fldIncludeInLatest = section.querySelector('.fldIncludeInLatest'); const fldIncludeInLatest = section.querySelector('.fldIncludeInLatest');
if (fldIncludeInLatest) { if (fldIncludeInLatest) {
if (chkIncludeInMyMedia.checked) { if (chkIncludeInMyMedia.checked) {
fldIncludeInLatest.classList.remove('hide'); fldIncludeInLatest.classList.remove('hide');
@ -469,14 +414,12 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
} }
function embed(options, self) { function embed(options, self) {
return import('text!./homeScreenSettings.template.html').then(({default: template}) => {
require(['text!./homescreensettings.template.html'], function (template) { for (let i = 1; i <= numConfigurableSections; i++) {
template = template.replace(`{section${i}label}`, globalize.translate('LabelHomeScreenSectionValue', i));
for (var i = 1; i <= numConfigurableSections; i++) {
template = template.replace('{section' + i + 'label}', globalize.translate('LabelHomeScreenSectionValue', i));
} }
options.element.innerHTML = globalize.translateDocument(template, 'core'); options.element.innerHTML = globalize.translateHtml(template, 'core');
options.element.querySelector('.viewOrderList').addEventListener('click', onSectionOrderListClick); options.element.querySelector('.viewOrderList').addEventListener('click', onSectionOrderListClick);
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self)); options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
@ -496,47 +439,44 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
}); });
} }
function HomeScreenSettings(options) { class HomeScreenSettings {
constructor(options) {
this.options = options;
embed(options, this);
}
this.options = options; loadData(autoFocus) {
const self = this;
const context = self.options.element;
embed(options, this); loading.show();
const userId = self.options.userId;
const apiClient = connectionManager.getApiClient(self.options.serverId);
const userSettings = self.options.userSettings;
apiClient.getUser(userId).then(user => {
userSettings.setUserInfo(userId, apiClient).then(() => {
self.dataLoaded = true;
loadForm(context, user, userSettings, apiClient);
if (autoFocus) {
focusManager.autoFocus(context);
}
});
});
}
submit() {
onSubmit.call(this);
}
destroy() {
this.options = null;
}
} }
HomeScreenSettings.prototype.loadData = function (autoFocus) { /* eslint-enable indent */
var self = this; export default HomeScreenSettings;
var context = self.options.element;
loading.show();
var userId = self.options.userId;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userSettings = self.options.userSettings;
apiClient.getUser(userId).then(function (user) {
userSettings.setUserInfo(userId, apiClient).then(function () {
self.dataLoaded = true;
loadForm(context, user, userSettings, apiClient);
if (autoFocus) {
focusManager.autoFocus(context);
}
});
});
};
HomeScreenSettings.prototype.submit = function () {
onSubmit.call(this);
};
HomeScreenSettings.prototype.destroy = function () {
this.options = null;
};
return HomeScreenSettings;
});

View file

@ -1,7 +1,20 @@
define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'layoutManager', 'imageLoader', 'globalize', 'itemShortcuts', 'itemHelper', 'appRouter', 'scripts/imagehelper', 'paper-icon-button-light', 'emby-itemscontainer', 'emby-scroller', 'emby-button', 'css!./homesections'], function (connectionManager, cardBuilder, appSettings, dom, appHost, layoutManager, imageLoader, globalize, itemShortcuts, itemHelper, appRouter, imageHelper) { import connectionManager from 'connectionManager';
'use strict'; import cardBuilder from 'cardBuilder';
import dom from 'dom';
import layoutManager from 'layoutManager';
import imageLoader from 'imageLoader';
import globalize from 'globalize';
import appRouter from 'appRouter';
import imageHelper from 'scripts/imagehelper';
import 'paper-icon-button-light';
import 'emby-itemscontainer';
import 'emby-scroller';
import 'emby-button';
import 'css!./homesections';
function getDefaultSection(index) { /* eslint-disable indent */
export function getDefaultSection(index) {
switch (index) { switch (index) {
case 0: case 0:
return 'smalllibrarytiles'; return 'smalllibrarytiles';
@ -23,9 +36,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function getAllSectionsToShow(userSettings, sectionCount) { function getAllSectionsToShow(userSettings, sectionCount) {
var sections = []; const sections = [];
for (var i = 0, length = sectionCount; i < length; i++) { for (let i = 0, length = sectionCount; i < length; i++) {
var section = userSettings.get('homesection' + i) || getDefaultSection(i); let section = userSettings.get('homesection' + i) || getDefaultSection(i);
if (section === 'folders') { if (section === 'folders') {
section = getDefaultSection(0); section = getDefaultSection(0);
} }
@ -36,22 +49,22 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
return sections; return sections;
} }
function loadSections(elem, apiClient, user, userSettings) { export function loadSections(elem, apiClient, user, userSettings) {
return getUserViews(apiClient, user.Id).then(function (userViews) { return getUserViews(apiClient, user.Id).then(function (userViews) {
var html = ''; let html = '';
if (userViews.length) { if (userViews.length) {
var sectionCount = 7; const sectionCount = 7;
for (var i = 0; i < sectionCount; i++) { for (let i = 0; i < sectionCount; i++) {
html += '<div class="verticalSection section' + i + '"></div>'; html += '<div class="verticalSection section' + i + '"></div>';
} }
elem.innerHTML = html; elem.innerHTML = html;
elem.classList.add('homeSectionsContainer'); elem.classList.add('homeSectionsContainer');
var promises = []; const promises = [];
var sections = getAllSectionsToShow(userSettings, sectionCount); const sections = getAllSectionsToShow(userSettings, sectionCount);
for (var i = 0; i < sections.length; i++) { for (let i = 0; i < sections.length; i++) {
promises.push(loadSection(elem, apiClient, user, userSettings, userViews, sections, i)); promises.push(loadSection(elem, apiClient, user, userSettings, userViews, sections, i));
} }
@ -62,7 +75,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
}); });
}); });
} else { } else {
var noLibDescription; let noLibDescription;
if (user['Policy'] && user['Policy']['IsAdministrator']) { if (user['Policy'] && user['Policy']['IsAdministrator']) {
noLibDescription = globalize.translate('NoCreatedLibraries', '<br><a id="button-createLibrary" class="button-link">', '</a>'); noLibDescription = globalize.translate('NoCreatedLibraries', '<br><a id="button-createLibrary" class="button-link">', '</a>');
} else { } else {
@ -75,7 +88,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
html += '</div>'; html += '</div>';
elem.innerHTML = html; elem.innerHTML = html;
var createNowLink = elem.querySelector('#button-createLibrary'); const createNowLink = elem.querySelector('#button-createLibrary');
if (createNowLink) { if (createNowLink) {
createNowLink.addEventListener('click', function () { createNowLink.addEventListener('click', function () {
Dashboard.navigate('library.html'); Dashboard.navigate('library.html');
@ -85,9 +98,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
}); });
} }
function destroySections(elem) { export function destroySections(elem) {
var elems = elem.querySelectorAll('.itemsContainer'); const elems = elem.querySelectorAll('.itemsContainer');
for (var i = 0; i < elems.length; i++) { for (let i = 0; i < elems.length; i++) {
elems[i].fetchData = null; elems[i].fetchData = null;
elems[i].parentContainer = null; elems[i].parentContainer = null;
elems[i].getItemsHtml = null; elems[i].getItemsHtml = null;
@ -96,35 +109,32 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
elem.innerHTML = ''; elem.innerHTML = '';
} }
function pause(elem) { export function pause(elem) {
var elems = elem.querySelectorAll('.itemsContainer'); const elems = elem.querySelectorAll('.itemsContainer');
for (var i = 0; i < elems.length; i++) { for (let i = 0; i < elems.length; i++) {
elems[i].pause(); elems[i].pause();
} }
} }
function resume(elem, options) { export function resume(elem, options) {
var elems = elem.querySelectorAll('.itemsContainer'); const elems = elem.querySelectorAll('.itemsContainer');
var i; const promises = [];
var length;
var promises = [];
for (i = 0, length = elems.length; i < length; i++) { for (let i = 0, length = elems.length; i < length; i++) {
promises.push(elems[i].resume(options)); promises.push(elems[i].resume(options));
} }
var promise = Promise.all(promises); const promise = Promise.all(promises);
if (!options || options.returnPromise !== false) { if (!options || options.returnPromise !== false) {
return promise; return promise;
} }
} }
function loadSection(page, apiClient, user, userSettings, userViews, allSections, index) { function loadSection(page, apiClient, user, userSettings, userViews, allSections, index) {
const section = allSections[index];
const userId = user.Id;
var section = allSections[index]; const elem = page.querySelector('.section' + index);
var userId = user.Id;
var elem = page.querySelector('.section' + index);
if (section === 'latestmedia') { if (section === 'latestmedia') {
loadRecentlyAdded(elem, apiClient, user, userViews); loadRecentlyAdded(elem, apiClient, user, userViews);
@ -168,11 +178,11 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function getPortraitShape() { function getPortraitShape() {
return enableScrollX() ? 'autooverflow' : 'auto'; return enableScrollX() ? 'overflowPortrait' : 'portrait';
} }
function getLibraryButtonsHtml(items) { function getLibraryButtonsHtml(items) {
var html = ''; let html = '';
html += '<div class="verticalSection verticalSection-extrabottompadding">'; html += '<div class="verticalSection verticalSection-extrabottompadding">';
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderMyMedia') + '</h2>'; html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderMyMedia') + '</h2>';
@ -180,9 +190,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x" data-multiselect="false">'; html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x" data-multiselect="false">';
// library card background images // library card background images
for (var i = 0, length = items.length; i < length; i++) { for (let i = 0, length = items.length; i < length; i++) {
var item = items[i]; const item = items[i];
var icon = imageHelper.getLibraryIcon(item.CollectionType); const icon = imageHelper.getLibraryIcon(item.CollectionType);
html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl(item) + '" class="raised homeLibraryButton"><span class="material-icons homeLibraryIcon ' + icon + '"></span><span class="homeLibraryText">' + item.Name + '</span></a>'; html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl(item) + '" class="raised homeLibraryButton"><span class="material-icons homeLibraryIcon ' + icon + '"></span><span class="homeLibraryText">' + item.Name + '</span></a>';
} }
@ -194,24 +204,16 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function loadlibraryButtons(elem, apiClient, user, userSettings, userViews) { function loadlibraryButtons(elem, apiClient, user, userSettings, userViews) {
elem.classList.remove('verticalSection'); elem.classList.remove('verticalSection');
var html = getLibraryButtonsHtml(userViews); const html = getLibraryButtonsHtml(userViews);
elem.innerHTML = html; elem.innerHTML = html;
imageLoader.lazyChildren(elem); imageLoader.lazyChildren(elem);
} }
/**
* Returns a random integer between min (inclusive) and max (inclusive)
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getFetchLatestItemsFn(serverId, parentId, collectionType) { function getFetchLatestItemsFn(serverId, parentId, collectionType) {
return function () { return function () {
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
var limit = 16; let limit = 16;
if (enableScrollX()) { if (enableScrollX()) {
if (collectionType === 'music') { if (collectionType === 'music') {
@ -227,9 +229,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
} }
var options = { const options = {
Limit: limit, Limit: limit,
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', Fields: 'PrimaryImageAspectRatio,BasicSyncInfo,Path',
ImageTypeLimit: 1, ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb', EnableImageTypes: 'Primary,Backdrop,Thumb',
ParentId: parentId ParentId: parentId
@ -241,8 +243,8 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function getLatestItemsHtmlFn(itemType, viewType) { function getLatestItemsHtmlFn(itemType, viewType) {
return function (items) { return function (items) {
var cardLayout = false; const cardLayout = false;
var shape; let shape;
if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books' || viewType === 'tvshows') { if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books' || viewType === 'tvshows') {
shape = getPortraitShape(); shape = getPortraitShape();
} else if (viewType === 'music' || viewType === 'homevideos') { } else if (viewType === 'music' || viewType === 'homevideos') {
@ -254,7 +256,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
return cardBuilder.getCardsHtml({ return cardBuilder.getCardsHtml({
items: items, items: items,
shape: shape, shape: shape,
preferThumb: viewType !== 'movies' && itemType !== 'Channel' && viewType !== 'music' ? 'auto' : null, preferThumb: viewType !== 'movies' && viewType !== 'tvshows' && itemType !== 'Channel' && viewType !== 'music' ? 'auto' : null,
showUnplayedIndicator: false, showUnplayedIndicator: false,
showChildCountIndicator: true, showChildCountIndicator: true,
context: 'home', context: 'home',
@ -272,7 +274,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function renderLatestSection(elem, apiClient, user, parent) { function renderLatestSection(elem, apiClient, user, parent) {
var html = ''; let html = '';
html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">'; html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">';
if (!layoutManager.tv) { if (!layoutManager.tv) {
@ -303,7 +305,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
elem.innerHTML = html; elem.innerHTML = html;
var itemsContainer = elem.querySelector('.itemsContainer'); const itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.fetchData = getFetchLatestItemsFn(apiClient.serverId(), parent.Id, parent.CollectionType); itemsContainer.fetchData = getFetchLatestItemsFn(apiClient.serverId(), parent.Id, parent.CollectionType);
itemsContainer.getItemsHtml = getLatestItemsHtmlFn(parent.Type, parent.CollectionType); itemsContainer.getItemsHtml = getLatestItemsHtmlFn(parent.Type, parent.CollectionType);
itemsContainer.parentContainer = elem; itemsContainer.parentContainer = elem;
@ -311,10 +313,10 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function loadRecentlyAdded(elem, apiClient, user, userViews) { function loadRecentlyAdded(elem, apiClient, user, userViews) {
elem.classList.remove('verticalSection'); elem.classList.remove('verticalSection');
var excludeViewTypes = ['playlists', 'livetv', 'boxsets', 'channels']; const excludeViewTypes = ['playlists', 'livetv', 'boxsets', 'channels'];
for (var i = 0, length = userViews.length; i < length; i++) { for (let i = 0, length = userViews.length; i < length; i++) {
var item = userViews[i]; const item = userViews[i];
if (user.Configuration.LatestItemsExcludes.indexOf(item.Id) !== -1) { if (user.Configuration.LatestItemsExcludes.indexOf(item.Id) !== -1) {
continue; continue;
} }
@ -323,7 +325,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
continue; continue;
} }
var frag = document.createElement('div'); const frag = document.createElement('div');
frag.classList.add('verticalSection'); frag.classList.add('verticalSection');
frag.classList.add('hide'); frag.classList.add('hide');
elem.appendChild(frag); elem.appendChild(frag);
@ -332,14 +334,8 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
} }
function getRequirePromise(deps) { export function loadLibraryTiles(elem, apiClient, user, userSettings, shape, userViews, allSections) {
return new Promise(function (resolve, reject) { let html = '';
require(deps, resolve);
});
}
function loadLibraryTiles(elem, apiClient, user, userSettings, shape, userViews, allSections) {
var html = '';
if (userViews.length) { if (userViews.length) {
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderMyMedia') + '</h2>'; html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderMyMedia') + '</h2>';
if (enableScrollX()) { if (enableScrollX()) {
@ -372,10 +368,10 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function getContinueWatchingFetchFn(serverId) { function getContinueWatchingFetchFn(serverId) {
return function () { return function () {
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
var screenWidth = dom.getWindowSize().innerWidth; const screenWidth = dom.getWindowSize().innerWidth;
var limit; let limit;
if (enableScrollX()) { if (enableScrollX()) {
limit = 12; limit = 12;
} else { } else {
@ -383,7 +379,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
limit = Math.min(limit, 5); limit = Math.min(limit, 5);
} }
var options = { const options = {
Limit: limit, Limit: limit,
Recursive: true, Recursive: true,
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
@ -398,7 +394,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function getContinueWatchingItemsHtml(items) { function getContinueWatchingItemsHtml(items) {
var cardLayout = false; const cardLayout = false;
return cardBuilder.getCardsHtml({ return cardBuilder.getCardsHtml({
items: items, items: items,
preferThumb: true, preferThumb: true,
@ -419,7 +415,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function loadResumeVideo(elem, apiClient, userId) { function loadResumeVideo(elem, apiClient, userId) {
var html = ''; let html = '';
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueWatching') + '</h2>'; html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueWatching') + '</h2>';
if (enableScrollX()) { if (enableScrollX()) {
@ -437,7 +433,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
elem.classList.add('hide'); elem.classList.add('hide');
elem.innerHTML = html; elem.innerHTML = html;
var itemsContainer = elem.querySelector('.itemsContainer'); const itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.fetchData = getContinueWatchingFetchFn(apiClient.serverId()); itemsContainer.fetchData = getContinueWatchingFetchFn(apiClient.serverId());
itemsContainer.getItemsHtml = getContinueWatchingItemsHtml; itemsContainer.getItemsHtml = getContinueWatchingItemsHtml;
itemsContainer.parentContainer = elem; itemsContainer.parentContainer = elem;
@ -445,10 +441,10 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function getContinueListeningFetchFn(serverId) { function getContinueListeningFetchFn(serverId) {
return function () { return function () {
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
var screenWidth = dom.getWindowSize().innerWidth; const screenWidth = dom.getWindowSize().innerWidth;
var limit; let limit;
if (enableScrollX()) { if (enableScrollX()) {
limit = 12; limit = 12;
} else { } else {
@ -456,7 +452,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
limit = Math.min(limit, 5); limit = Math.min(limit, 5);
} }
var options = { const options = {
Limit: limit, Limit: limit,
Recursive: true, Recursive: true,
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
@ -471,7 +467,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function getContinueListeningItemsHtml(items) { function getContinueListeningItemsHtml(items) {
var cardLayout = false; const cardLayout = false;
return cardBuilder.getCardsHtml({ return cardBuilder.getCardsHtml({
items: items, items: items,
preferThumb: true, preferThumb: true,
@ -492,7 +488,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function loadResumeAudio(elem, apiClient, userId) { function loadResumeAudio(elem, apiClient, userId) {
var html = ''; let html = '';
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueWatching') + '</h2>'; html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueWatching') + '</h2>';
if (enableScrollX()) { if (enableScrollX()) {
@ -510,7 +506,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
elem.classList.add('hide'); elem.classList.add('hide');
elem.innerHTML = html; elem.innerHTML = html;
var itemsContainer = elem.querySelector('.itemsContainer'); const itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.fetchData = getContinueListeningFetchFn(apiClient.serverId()); itemsContainer.fetchData = getContinueListeningFetchFn(apiClient.serverId());
itemsContainer.getItemsHtml = getContinueListeningItemsHtml; itemsContainer.getItemsHtml = getContinueListeningItemsHtml;
itemsContainer.parentContainer = elem; itemsContainer.parentContainer = elem;
@ -518,7 +514,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function getOnNowFetchFn(serverId) { function getOnNowFetchFn(serverId) {
return function () { return function () {
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
return apiClient.getLiveTvRecommendedPrograms({ return apiClient.getLiveTvRecommendedPrograms({
userId: apiClient.getCurrentUserId(), userId: apiClient.getCurrentUserId(),
IsAiring: true, IsAiring: true,
@ -532,7 +528,6 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function getOnNowItemsHtml(items) { function getOnNowItemsHtml(items) {
var cardLayout = false;
return cardBuilder.getCardsHtml({ return cardBuilder.getCardsHtml({
items: items, items: items,
preferThumb: 'auto', preferThumb: 'auto',
@ -559,7 +554,6 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
return Promise.resolve(); return Promise.resolve();
} }
var userId = user.Id;
return apiClient.getLiveTvRecommendedPrograms({ return apiClient.getLiveTvRecommendedPrograms({
userId: apiClient.getCurrentUserId(), userId: apiClient.getCurrentUserId(),
IsAiring: true, IsAiring: true,
@ -569,7 +563,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
EnableTotalRecordCount: false, EnableTotalRecordCount: false,
Fields: 'ChannelInfo,PrimaryImageAspectRatio' Fields: 'ChannelInfo,PrimaryImageAspectRatio'
}).then(function (result) { }).then(function (result) {
var html = ''; let html = '';
if (result.Items.length) { if (result.Items.length) {
elem.classList.remove('padded-left'); elem.classList.remove('padded-left');
elem.classList.remove('padded-right'); elem.classList.remove('padded-right');
@ -632,7 +626,6 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
html += '</h2>'; html += '</h2>';
html += '<span class="material-icons chevron_right"></span>'; html += '<span class="material-icons chevron_right"></span>';
html += '</a>'; html += '</a>';
} else { } else {
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderOnNow') + '</h2>'; html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderOnNow') + '</h2>';
} }
@ -654,7 +647,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
elem.innerHTML = html; elem.innerHTML = html;
var itemsContainer = elem.querySelector('.itemsContainer'); const itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.parentContainer = elem; itemsContainer.parentContainer = elem;
itemsContainer.fetchData = getOnNowFetchFn(apiClient.serverId()); itemsContainer.fetchData = getOnNowFetchFn(apiClient.serverId());
itemsContainer.getItemsHtml = getOnNowItemsHtml; itemsContainer.getItemsHtml = getOnNowItemsHtml;
@ -664,10 +657,10 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function getNextUpFetchFn(serverId) { function getNextUpFetchFn(serverId) {
return function () { return function () {
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
return apiClient.getNextUpEpisodes({ return apiClient.getNextUpEpisodes({
Limit: enableScrollX() ? 24 : 15, Limit: enableScrollX() ? 24 : 15,
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo', Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo,Path',
UserId: apiClient.getCurrentUserId(), UserId: apiClient.getCurrentUserId(),
ImageTypeLimit: 1, ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
@ -677,7 +670,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function getNextUpItemsHtml(items) { function getNextUpItemsHtml(items) {
var cardLayout = false; const cardLayout = false;
return cardBuilder.getCardsHtml({ return cardBuilder.getCardsHtml({
items: items, items: items,
preferThumb: true, preferThumb: true,
@ -695,7 +688,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function loadNextUp(elem, apiClient, userId) { function loadNextUp(elem, apiClient, userId) {
var html = ''; let html = '';
html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">'; html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">';
if (!layoutManager.tv) { if (!layoutManager.tv) {
@ -727,7 +720,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
elem.classList.add('hide'); elem.classList.add('hide');
elem.innerHTML = html; elem.innerHTML = html;
var itemsContainer = elem.querySelector('.itemsContainer'); const itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.fetchData = getNextUpFetchFn(apiClient.serverId()); itemsContainer.fetchData = getNextUpFetchFn(apiClient.serverId());
itemsContainer.getItemsHtml = getNextUpItemsHtml; itemsContainer.getItemsHtml = getNextUpItemsHtml;
itemsContainer.parentContainer = elem; itemsContainer.parentContainer = elem;
@ -735,7 +728,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function getLatestRecordingsFetchFn(serverId, activeRecordingsOnly) { function getLatestRecordingsFetchFn(serverId, activeRecordingsOnly) {
return function () { return function () {
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
return apiClient.getLiveTvRecordings({ return apiClient.getLiveTvRecordings({
userId: apiClient.getCurrentUserId(), userId: apiClient.getCurrentUserId(),
Limit: enableScrollX() ? 12 : 5, Limit: enableScrollX() ? 12 : 5,
@ -749,7 +742,6 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
function getLatestRecordingItemsHtml(activeRecordingsOnly) { function getLatestRecordingItemsHtml(activeRecordingsOnly) {
return function (items) { return function (items) {
var cardLayout = false;
return cardBuilder.getCardsHtml({ return cardBuilder.getCardsHtml({
items: items, items: items,
shape: enableScrollX() ? 'autooverflow' : 'auto', shape: enableScrollX() ? 'autooverflow' : 'auto',
@ -774,11 +766,11 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
} }
function loadLatestLiveTvRecordings(elem, activeRecordingsOnly, apiClient, userId) { function loadLatestLiveTvRecordings(elem, activeRecordingsOnly, apiClient, userId) {
var title = activeRecordingsOnly ? const title = activeRecordingsOnly ?
globalize.translate('HeaderActiveRecordings') : globalize.translate('HeaderActiveRecordings') :
globalize.translate('HeaderLatestRecordings'); globalize.translate('HeaderLatestRecordings');
var html = ''; let html = '';
html += '<div class="sectionTitleContainer sectionTitleContainer-cards">'; html += '<div class="sectionTitleContainer sectionTitleContainer-cards">';
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + title + '</h2>'; html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + title + '</h2>';
@ -799,18 +791,19 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
elem.classList.add('hide'); elem.classList.add('hide');
elem.innerHTML = html; elem.innerHTML = html;
var itemsContainer = elem.querySelector('.itemsContainer'); const itemsContainer = elem.querySelector('.itemsContainer');
itemsContainer.fetchData = getLatestRecordingsFetchFn(apiClient.serverId(), activeRecordingsOnly); itemsContainer.fetchData = getLatestRecordingsFetchFn(apiClient.serverId(), activeRecordingsOnly);
itemsContainer.getItemsHtml = getLatestRecordingItemsHtml(activeRecordingsOnly); itemsContainer.getItemsHtml = getLatestRecordingItemsHtml(activeRecordingsOnly);
itemsContainer.parentContainer = elem; itemsContainer.parentContainer = elem;
} }
return { export default {
loadLibraryTiles: loadLibraryTiles, loadLibraryTiles: loadLibraryTiles,
getDefaultSection: getDefaultSection, getDefaultSection: getDefaultSection,
loadSections: loadSections, loadSections: loadSections,
destroySections: destroySections, destroySections: destroySections,
pause: pause, pause: pause,
resume: resume resume: resume
}; };
});
/* eslint-enable indent */

View file

@ -1,17 +1,20 @@
define(['appSettings', 'browser', 'events'], function (appSettings, browser, events) { /* eslint-disable indent */
'use strict';
function getSavedVolume() { import appSettings from 'appSettings' ;
import browser from 'browser';
import events from 'events';
export function getSavedVolume() {
return appSettings.get('volume') || 1; return appSettings.get('volume') || 1;
} }
function saveVolume(value) { export function saveVolume(value) {
if (value) { if (value) {
appSettings.set('volume', value); appSettings.set('volume', value);
} }
} }
function getCrossOriginValue(mediaSource) { export function getCrossOriginValue(mediaSource) {
if (mediaSource.IsRemote) { if (mediaSource.IsRemote) {
return null; return null;
} }
@ -30,34 +33,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
return false; return false;
} }
function enableHlsShakaPlayer(item, mediaSource, mediaType) { export function enableHlsJsPlayer(runTimeTicks, mediaType) {
/* eslint-disable-next-line compat/compat */
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
if (canPlayNativeHls()) {
if (browser.edge && mediaType === 'Video') {
return true;
}
// simple playback should use the native support
if (mediaSource.RunTimeTicks) {
//if (!browser.edge) {
//return false;
//}
}
//return false;
}
return true;
}
return false;
}
function enableHlsJsPlayer(runTimeTicks, mediaType) {
if (window.MediaSource == null) { if (window.MediaSource == null) {
return false; return false;
} }
@ -73,7 +49,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
if (canPlayNativeHls()) { if (canPlayNativeHls()) {
// Having trouble with chrome's native support and transcoded music // Having trouble with chrome's native support and transcoded music
if (browser.android && mediaType === 'Audio') { if (browser.android && mediaType === 'Audio') {
return true; return true;
@ -98,8 +73,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
var recoverDecodingErrorDate; var recoverDecodingErrorDate;
var recoverSwapAudioCodecDate; var recoverSwapAudioCodecDate;
function handleHlsJsMediaError(instance, reject) { export function handleHlsJsMediaError(instance, reject) {
var hlsPlayer = instance._hlsPlayer; var hlsPlayer = instance._hlsPlayer;
if (!hlsPlayer) { if (!hlsPlayer) {
@ -134,8 +108,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
} }
function onErrorInternal(instance, type) { export function onErrorInternal(instance, type) {
// Needed for video // Needed for video
if (instance.destroyCustomTrack) { if (instance.destroyCustomTrack) {
instance.destroyCustomTrack(instance._mediaElement); instance.destroyCustomTrack(instance._mediaElement);
@ -148,7 +121,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
]); ]);
} }
function isValidDuration(duration) { export function isValidDuration(duration) {
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) { if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
return true; return true;
} }
@ -162,13 +135,10 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
} }
function seekOnPlaybackStart(instance, element, ticks, onMediaReady) { export function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
var seconds = (ticks || 0) / 10000000; var seconds = (ticks || 0) / 10000000;
if (seconds) { if (seconds) {
var src = (instance.currentSrc() || '').toLowerCase();
// Appending #t=xxx to the query string doesn't seem to work with HLS // Appending #t=xxx to the query string doesn't seem to work with HLS
// For plain video files, not all browsers support it either // For plain video files, not all browsers support it either
@ -194,18 +164,15 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
}; };
events.map(function (name) { events.map(function (name) {
element.addEventListener(name, onMediaChange); return element.addEventListener(name, onMediaChange);
}); });
} }
} }
} }
function applySrc(elem, src, options) { export function applySrc(elem, src, options) {
if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) { if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) { return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) {
var playlist = new Windows.Media.Playback.MediaPlaybackList(); var playlist = new Windows.Media.Playback.MediaPlaybackList();
var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file); var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file);
@ -214,9 +181,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true }); elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true });
return Promise.resolve(); return Promise.resolve();
}); });
} else { } else {
elem.src = src; elem.src = src;
} }
@ -224,18 +189,15 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
function onSuccessfulPlay(elem, onErrorFn) { function onSuccessfulPlay(elem, onErrorFn) {
elem.addEventListener('error', onErrorFn); elem.addEventListener('error', onErrorFn);
} }
function playWithPromise(elem, onErrorFn) { export function playWithPromise(elem, onErrorFn) {
try { try {
var promise = elem.play(); var promise = elem.play();
if (promise && promise.then) { if (promise && promise.then) {
// Chrome now returns a promise // Chrome now returns a promise
return promise.catch(function (e) { return promise.catch(function (e) {
var errorName = (e.name || '').toLowerCase(); var errorName = (e.name || '').toLowerCase();
// safari uses aborterror // safari uses aborterror
if (errorName === 'notallowederror' || if (errorName === 'notallowederror' ||
@ -256,8 +218,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
} }
function destroyCastPlayer(instance) { export function destroyCastPlayer(instance) {
var player = instance._castPlayer; var player = instance._castPlayer;
if (player) { if (player) {
try { try {
@ -270,20 +231,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
} }
function destroyShakaPlayer(instance) { export function destroyHlsPlayer(instance) {
var player = instance._shakaPlayer;
if (player) {
try {
player.destroy();
} catch (err) {
console.error(err);
}
instance._shakaPlayer = null;
}
}
function destroyHlsPlayer(instance) {
var player = instance._hlsPlayer; var player = instance._hlsPlayer;
if (player) { if (player) {
try { try {
@ -296,7 +244,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
} }
function destroyFlvPlayer(instance) { export function destroyFlvPlayer(instance) {
var player = instance._flvPlayer; var player = instance._flvPlayer;
if (player) { if (player) {
try { try {
@ -311,11 +259,9 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
} }
function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) { export function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
hls.on(Hls.Events.MANIFEST_PARSED, function () { hls.on(Hls.Events.MANIFEST_PARSED, function () {
playWithPromise(elem, onErrorFn).then(resolve, function () { playWithPromise(elem, onErrorFn).then(resolve, function () {
if (reject) { if (reject) {
reject(); reject();
reject = null; reject = null;
@ -324,14 +270,12 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}); });
hls.on(Hls.Events.ERROR, function (event, data) { hls.on(Hls.Events.ERROR, function (event, data) {
console.error('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false)); console.error('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false));
switch (data.type) { switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR: case Hls.ErrorTypes.NETWORK_ERROR:
// try to recover network error // try to recover network error
if (data.response && data.response.code && data.response.code >= 400) { if (data.response && data.response.code && data.response.code >= 400) {
console.debug('hls.js response error code: ' + data.response.code); console.debug('hls.js response error code: ' + data.response.code);
// Trigger failure differently depending on whether this is prior to start of playback, or after // Trigger failure differently depending on whether this is prior to start of playback, or after
@ -345,7 +289,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
} }
return; return;
} }
break; break;
@ -358,7 +301,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
case Hls.ErrorTypes.NETWORK_ERROR: case Hls.ErrorTypes.NETWORK_ERROR:
if (data.response && data.response.code === 0) { if (data.response && data.response.code === 0) {
// This could be a CORS error related to access control response headers // This could be a CORS error related to access control response headers
console.debug('hls.js response error code: ' + data.response.code); console.debug('hls.js response error code: ' + data.response.code);
@ -403,8 +345,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
}); });
} }
function onEndedInternal(instance, elem, onErrorFn) { export function onEndedInternal(instance, elem, onErrorFn) {
elem.removeEventListener('error', onErrorFn); elem.removeEventListener('error', onErrorFn);
elem.src = ''; elem.src = '';
@ -413,7 +354,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
destroyHlsPlayer(instance); destroyHlsPlayer(instance);
destroyFlvPlayer(instance); destroyFlvPlayer(instance);
destroyShakaPlayer(instance);
destroyCastPlayer(instance); destroyCastPlayer(instance);
var stopInfo = { var stopInfo = {
@ -427,8 +367,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
instance._currentPlayOptions = null; instance._currentPlayOptions = null;
} }
function getBufferedRanges(instance, elem) { export function getBufferedRanges(instance, elem) {
var ranges = []; var ranges = [];
var seekable = elem.buffered || []; var seekable = elem.buffered || [];
@ -441,7 +380,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
offset = offset || 0; offset = offset || 0;
for (var i = 0, length = seekable.length; i < length; i++) { for (var i = 0, length = seekable.length; i < length; i++) {
var start = seekable.start(i); var start = seekable.start(i);
var end = seekable.end(i); var end = seekable.end(i);
@ -462,23 +400,4 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
return ranges; return ranges;
} }
return { /* eslint-enable indent */
getSavedVolume: getSavedVolume,
saveVolume: saveVolume,
enableHlsJsPlayer: enableHlsJsPlayer,
enableHlsShakaPlayer: enableHlsShakaPlayer,
handleHlsJsMediaError: handleHlsJsMediaError,
isValidDuration: isValidDuration,
onErrorInternal: onErrorInternal,
seekOnPlaybackStart: seekOnPlaybackStart,
applySrc: applySrc,
playWithPromise: playWithPromise,
destroyHlsPlayer: destroyHlsPlayer,
destroyFlvPlayer: destroyFlvPlayer,
destroyCastPlayer: destroyCastPlayer,
bindEventsToHlsPlayer: bindEventsToHlsPlayer,
onEndedInternal: onEndedInternal,
getCrossOriginValue: getCrossOriginValue,
getBufferedRanges: getBufferedRanges
};
});

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,39 @@
define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader', 'browser', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'emby-checkbox', 'paper-icon-button-light', 'emby-button', 'formDialogStyle', 'cardStyle'], function (dom, loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) { import dom from 'dom';
'use strict'; import loading from 'loading';
import appHost from 'apphost';
import dialogHelper from 'dialogHelper';
import connectionManager from 'connectionManager';
import imageLoader from 'imageLoader';
import browser from 'browser';
import layoutManager from 'layoutManager';
import scrollHelper from 'scrollHelper';
import globalize from 'globalize';
import require from 'require';
import 'emby-checkbox';
import 'paper-icon-button-light';
import 'emby-button';
import 'formDialogStyle';
import 'cardStyle';
var enableFocusTransform = !browser.slow && !browser.edge; /* eslint-disable indent */
var currentItemId; const enableFocusTransform = !browser.slow && !browser.edge;
var currentItemType;
var currentResolve; let currentItemId;
var currentReject; let currentItemType;
var hasChanges = false; let currentResolve;
let currentReject;
let hasChanges = false;
// These images can be large and we're seeing memory problems in safari // These images can be large and we're seeing memory problems in safari
var browsableImagePageSize = browser.slow ? 6 : 30; const browsableImagePageSize = browser.slow ? 6 : 30;
var browsableImageStartIndex = 0; let browsableImageStartIndex = 0;
var browsableImageType = 'Primary'; let browsableImageType = 'Primary';
var selectedProvider; let selectedProvider;
function getBaseRemoteOptions() { function getBaseRemoteOptions() {
const options = {};
var options = {};
options.itemId = currentItemId; options.itemId = currentItemId;
@ -26,58 +41,53 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
} }
function reloadBrowsableImages(page, apiClient) { function reloadBrowsableImages(page, apiClient) {
loading.show(); loading.show();
var options = getBaseRemoteOptions(); const options = getBaseRemoteOptions();
options.type = browsableImageType; options.type = browsableImageType;
options.startIndex = browsableImageStartIndex; options.startIndex = browsableImageStartIndex;
options.limit = browsableImagePageSize; options.limit = browsableImagePageSize;
options.IncludeAllLanguages = page.querySelector('#chkAllLanguages').checked; options.IncludeAllLanguages = page.querySelector('#chkAllLanguages').checked;
var provider = selectedProvider || ''; const provider = selectedProvider || '';
if (provider) { if (provider) {
options.ProviderName = provider; options.ProviderName = provider;
} }
apiClient.getAvailableRemoteImages(options).then(function (result) { apiClient.getAvailableRemoteImages(options).then(function (result) {
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit); renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit);
page.querySelector('#selectBrowsableImageType').value = browsableImageType; page.querySelector('#selectBrowsableImageType').value = browsableImageType;
var providersHtml = result.Providers.map(function (p) { const providersHtml = result.Providers.map(function (p) {
return '<option value="' + p + '">' + p + '</option>'; return '<option value="' + p + '">' + p + '</option>';
}); });
var selectImageProvider = page.querySelector('#selectImageProvider'); const selectImageProvider = page.querySelector('#selectImageProvider');
selectImageProvider.innerHTML = '<option value="">' + globalize.translate('All') + '</option>' + providersHtml; selectImageProvider.innerHTML = '<option value="">' + globalize.translate('All') + '</option>' + providersHtml;
selectImageProvider.value = provider; selectImageProvider.value = provider;
loading.hide(); loading.hide();
}); });
} }
function renderRemoteImages(page, apiClient, imagesResult, imageType, startIndex, limit) { function renderRemoteImages(page, apiClient, imagesResult, imageType, startIndex, limit) {
page.querySelector('.availableImagesPaging').innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount); page.querySelector('.availableImagesPaging').innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
var html = ''; let html = '';
for (var i = 0, length = imagesResult.Images.length; i < length; i++) {
for (let i = 0, length = imagesResult.Images.length; i < length; i++) {
html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient); html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
} }
var availableImagesList = page.querySelector('.availableImagesList'); const availableImagesList = page.querySelector('.availableImagesList');
availableImagesList.innerHTML = html; availableImagesList.innerHTML = html;
imageLoader.lazyChildren(availableImagesList); imageLoader.lazyChildren(availableImagesList);
var btnNextPage = page.querySelector('.btnNextPage'); const btnNextPage = page.querySelector('.btnNextPage');
var btnPreviousPage = page.querySelector('.btnPreviousPage'); const btnPreviousPage = page.querySelector('.btnPreviousPage');
if (btnNextPage) { if (btnNextPage) {
btnNextPage.addEventListener('click', function () { btnNextPage.addEventListener('click', function () {
@ -92,23 +102,21 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
reloadBrowsableImages(page, apiClient); reloadBrowsableImages(page, apiClient);
}); });
} }
} }
function getPagingHtml(startIndex, limit, totalRecordCount) { function getPagingHtml(startIndex, limit, totalRecordCount) {
let html = '';
var html = ''; const recordsEnd = Math.min(startIndex + limit, totalRecordCount);
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
// 20 is the minimum page size // 20 is the minimum page size
var showControls = totalRecordCount > limit; const showControls = totalRecordCount > limit;
html += '<div class="listPaging">'; html += '<div class="listPaging">';
html += '<span style="margin-right: 10px;">'; html += '<span style="margin-right: 10px;">';
var startAtDisplay = totalRecordCount ? startIndex + 1 : 0; const startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
html += globalize.translate('ListPaging', startAtDisplay, recordsEnd, totalRecordCount); html += globalize.translate('ListPaging', startAtDisplay, recordsEnd, totalRecordCount);
html += '</span>'; html += '</span>';
@ -127,7 +135,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
} }
function downloadRemoteImage(page, apiClient, url, type, provider) { function downloadRemoteImage(page, apiClient, url, type, provider) {
var options = getBaseRemoteOptions(); const options = getBaseRemoteOptions();
options.Type = type; options.Type = type;
options.ImageUrl = url; options.ImageUrl = url;
@ -136,9 +144,8 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
loading.show(); loading.show();
apiClient.downloadRemoteImage(options).then(function () { apiClient.downloadRemoteImage(options).then(function () {
hasChanges = true; hasChanges = true;
var dlg = dom.parentWithClass(page, 'dialog'); const dlg = dom.parentWithClass(page, 'dialog');
dialogHelper.close(dlg); dialogHelper.close(dlg);
}); });
} }
@ -148,17 +155,17 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
} }
function getRemoteImageHtml(image, imageType, apiClient) { function getRemoteImageHtml(image, imageType, apiClient) {
var tagName = layoutManager.tv ? 'button' : 'div'; const tagName = layoutManager.tv ? 'button' : 'div';
var enableFooterButtons = !layoutManager.tv; const enableFooterButtons = !layoutManager.tv;
// TODO move card creation code to Card component // TODO move card creation code to Card component
var html = ''; let html = '';
var cssClass = 'card scalableCard imageEditorCard'; let cssClass = 'card scalableCard imageEditorCard';
var cardBoxCssClass = 'cardBox visualCardBox'; const cardBoxCssClass = 'cardBox visualCardBox';
var shape = 'backdrop'; let shape;
if (imageType === 'Backdrop' || imageType === 'Art' || imageType === 'Thumb' || imageType === 'Logo') { if (imageType === 'Backdrop' || imageType === 'Art' || imageType === 'Thumb' || imageType === 'Logo') {
shape = 'backdrop'; shape = 'backdrop';
} else if (imageType === 'Banner') { } else if (imageType === 'Banner') {
@ -166,7 +173,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
} else if (imageType === 'Disc') { } else if (imageType === 'Disc') {
shape = 'square'; shape = 'square';
} else { } else {
if (currentItemType === 'Episode') { if (currentItemType === 'Episode') {
shape = 'backdrop'; shape = 'backdrop';
} else if (currentItemType === 'MusicAlbum' || currentItemType === 'MusicArtist') { } else if (currentItemType === 'MusicAlbum' || currentItemType === 'MusicArtist') {
@ -203,9 +209,9 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
html += '<div class="cardContent">'; html += '<div class="cardContent">';
if (layoutManager.tv || !appHost.supports('externallinks')) { if (layoutManager.tv || !appHost.supports('externallinks')) {
html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></div>'; html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center center;background-size:contain;"></div>';
} else { } else {
html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></a>'; html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center center;background-size:contain"></a>';
} }
html += '</div>'; html += '</div>';
@ -217,19 +223,16 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
html += '<div class="cardText cardTextCentered">' + image.ProviderName + '</div>'; html += '<div class="cardText cardTextCentered">' + image.ProviderName + '</div>';
if (image.Width || image.Height || image.Language) { if (image.Width || image.Height || image.Language) {
html += '<div class="cardText cardText-secondary cardTextCentered">'; html += '<div class="cardText cardText-secondary cardTextCentered">';
if (image.Width && image.Height) { if (image.Width && image.Height) {
html += image.Width + ' x ' + image.Height; html += image.Width + ' x ' + image.Height;
if (image.Language) { if (image.Language) {
html += ' • ' + image.Language; html += ' • ' + image.Language;
} }
} else { } else {
if (image.Language) { if (image.Language) {
html += image.Language; html += image.Language;
} }
} }
@ -238,13 +241,11 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
} }
if (image.CommunityRating != null) { if (image.CommunityRating != null) {
html += '<div class="cardText cardText-secondary cardTextCentered">'; html += '<div class="cardText cardText-secondary cardTextCentered">';
if (image.RatingType === 'Likes') { if (image.RatingType === 'Likes') {
html += image.CommunityRating + (image.CommunityRating === 1 ? ' like' : ' likes'); html += image.CommunityRating + (image.CommunityRating === 1 ? ' like' : ' likes');
} else { } else {
if (image.CommunityRating) { if (image.CommunityRating) {
html += image.CommunityRating.toFixed(1); html += image.CommunityRating.toFixed(1);
@ -270,7 +271,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
// end footer // end footer
html += '</div>'; html += '</div>';
//html += '</div>';
html += '</' + tagName + '>'; html += '</' + tagName + '>';
@ -287,7 +287,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
}); });
page.querySelector('#selectImageProvider').addEventListener('change', function () { page.querySelector('#selectImageProvider').addEventListener('change', function () {
browsableImageStartIndex = 0; browsableImageStartIndex = 0;
selectedProvider = this.value; selectedProvider = this.value;
@ -295,22 +294,20 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
}); });
page.querySelector('#chkAllLanguages').addEventListener('change', function () { page.querySelector('#chkAllLanguages').addEventListener('change', function () {
browsableImageStartIndex = 0; browsableImageStartIndex = 0;
reloadBrowsableImages(page, apiClient); reloadBrowsableImages(page, apiClient);
}); });
page.addEventListener('click', function (e) { page.addEventListener('click', function (e) {
const btnDownloadRemoteImage = dom.parentWithClass(e.target, 'btnDownloadRemoteImage');
var btnDownloadRemoteImage = dom.parentWithClass(e.target, 'btnDownloadRemoteImage');
if (btnDownloadRemoteImage) { if (btnDownloadRemoteImage) {
var card = dom.parentWithClass(btnDownloadRemoteImage, 'card'); const card = dom.parentWithClass(btnDownloadRemoteImage, 'card');
downloadRemoteImage(page, apiClient, card.getAttribute('data-imageurl'), card.getAttribute('data-imagetype'), card.getAttribute('data-imageprovider')); downloadRemoteImage(page, apiClient, card.getAttribute('data-imageurl'), card.getAttribute('data-imagetype'), card.getAttribute('data-imageprovider'));
return; return;
} }
var btnImageCard = dom.parentWithClass(e.target, 'btnImageCard'); const btnImageCard = dom.parentWithClass(e.target, 'btnImageCard');
if (btnImageCard) { if (btnImageCard) {
downloadRemoteImage(page, apiClient, btnImageCard.getAttribute('data-imageurl'), btnImageCard.getAttribute('data-imagetype'), btnImageCard.getAttribute('data-imageprovider')); downloadRemoteImage(page, apiClient, btnImageCard.getAttribute('data-imageurl'), btnImageCard.getAttribute('data-imagetype'), btnImageCard.getAttribute('data-imageprovider'));
} }
@ -320,26 +317,25 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
function showEditor(itemId, serverId, itemType) { function showEditor(itemId, serverId, itemType) {
loading.show(); loading.show();
require(['text!./imagedownloader.template.html'], function (template) { require(['text!./imageDownloader.template.html'], function (template) {
const apiClient = connectionManager.getApiClient(serverId);
var apiClient = connectionManager.getApiClient(serverId);
currentItemId = itemId; currentItemId = itemId;
currentItemType = itemType; currentItemType = itemType;
var dialogOptions = { const dialogOptions = {
removeOnClose: true removeOnClose: true
}; };
if (layoutManager.tv) { if (layoutManager.tv) {
dialogOptions.size = 'fullscreen'; dialogOptions.size = 'fullscreen';
} else { } else {
dialogOptions.size = 'fullscreen-border'; dialogOptions.size = 'small';
} }
var dlg = dialogHelper.createDialog(dialogOptions); const dlg = dialogHelper.createDialog(dialogOptions);
dlg.innerHTML = globalize.translateDocument(template, 'core'); dlg.innerHTML = globalize.translateHtml(template, 'core');
if (layoutManager.tv) { if (layoutManager.tv) {
scrollHelper.centerFocus.on(dlg, false); scrollHelper.centerFocus.on(dlg, false);
@ -350,11 +346,10 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
dialogHelper.open(dlg); dialogHelper.open(dlg);
var editorContent = dlg.querySelector('.formDialogContent'); const editorContent = dlg.querySelector('.formDialogContent');
initEditor(editorContent, apiClient); initEditor(editorContent, apiClient);
dlg.querySelector('.btnCancel').addEventListener('click', function () { dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg); dialogHelper.close(dlg);
}); });
@ -363,7 +358,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
} }
function onDialogClosed() { function onDialogClosed() {
var dlg = this; const dlg = this;
if (layoutManager.tv) { if (layoutManager.tv) {
scrollHelper.centerFocus.off(dlg, false); scrollHelper.centerFocus.off(dlg, false);
@ -377,18 +372,20 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
} }
} }
return { export function show(itemId, serverId, itemType, imageType) {
show: function (itemId, serverId, itemType, imageType) { return new Promise(function (resolve, reject) {
return new Promise(function (resolve, reject) { currentResolve = resolve;
currentResolve = resolve; currentReject = reject;
currentReject = reject; hasChanges = false;
hasChanges = false; browsableImageStartIndex = 0;
browsableImageStartIndex = 0; browsableImageType = imageType || 'Primary';
browsableImageType = imageType || 'Primary'; selectedProvider = null;
selectedProvider = null; showEditor(itemId, serverId, itemType);
});
}
showEditor(itemId, serverId, itemType); export default {
}); show: show
} };
};
}); /* eslint-enable indent */

View file

@ -5,7 +5,7 @@
</h3> </h3>
</div> </div>
<div class="formDialogContent"> <div class="formDialogContent smoothScrollY">
<div class="dialogContentInner"> <div class="dialogContentInner">
<div class="flex align-items-center justify-content-center flex-wrap-wrap" style="margin: 2em 0;"> <div class="flex align-items-center justify-content-center flex-wrap-wrap" style="margin: 2em 0;">

Some files were not shown because too many files have changed in this diff Show more