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

Merge branch 'es6' into es6-migration-2

This commit is contained in:
dkanada 2020-06-28 16:50:04 +09:00 committed by GitHub
commit d04ca8469b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
166 changed files with 5798 additions and 2418 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,106 @@
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: 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'
steps:
- 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)
stable
- 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,88 +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
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: '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

@ -132,6 +132,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',

5
.gitignore vendored
View file

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

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

@ -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

View file

@ -16,6 +16,7 @@ const stream = require('webpack-stream');
const inject = require('gulp-inject'); const inject = require('gulp-inject');
const postcss = require('gulp-postcss'); const postcss = require('gulp-postcss');
const sass = require('gulp-sass'); const sass = require('gulp-sass');
const gulpif = require('gulp-if');
const lazypipe = require('lazypipe'); const lazypipe = require('lazypipe');
sass.compiler = require('node-sass'); sass.compiler = require('node-sass');
@ -67,7 +68,7 @@ function serve() {
} }
}); });
watch(options.apploader.query, apploader()); watch(options.apploader.query, apploader(true));
watch('src/bundle.js', webpack); watch('src/bundle.js', webpack);
@ -130,12 +131,18 @@ function javascript(query) {
.pipe(browserSync.stream()); .pipe(browserSync.stream());
} }
function apploader() { function apploader(standalone) {
return src(options.apploader.query, { base: './src/' }) function task() {
.pipe(concat('scripts/apploader.js')) return src(options.apploader.query, { base: './src/' })
.pipe(pipelineJavascript()) .pipe(gulpif(standalone, concat('scripts/apploader.js')))
.pipe(dest('dist/')) .pipe(pipelineJavascript())
.pipe(browserSync.stream()); .pipe(dest('dist/'))
.pipe(browserSync.stream());
}
task.displayName = 'apploader';
return task;
} }
function webpack() { function webpack() {
@ -183,5 +190,10 @@ function injectBundle() {
.pipe(browserSync.stream()); .pipe(browserSync.stream());
} }
exports.default = series(clean, parallel(javascript, apploader, webpack, css, html, images, copy), injectBundle); function build(standalone) {
exports.serve = series(exports.default, serve); return series(clean, parallel(javascript, apploader(standalone), webpack, css, html, images, copy));
}
exports.default = series(build(false), injectBundle);
exports.standalone = series(build(true), injectBundle);
exports.serve = series(exports.standalone, serve);

View file

@ -5,29 +5,29 @@
"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.10.2", "@babel/core": "^7.10.3",
"@babel/plugin-proposal-class-properties": "^7.10.1", "@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/plugin-proposal-private-methods": "^7.10.1", "@babel/plugin-proposal-private-methods": "^7.10.1",
"@babel/plugin-transform-modules-amd": "^7.9.6", "@babel/plugin-transform-modules-amd": "^7.9.6",
"@babel/polyfill": "^7.8.7", "@babel/polyfill": "^7.8.7",
"@babel/preset-env": "^7.10.2", "@babel/preset-env": "^7.10.3",
"autoprefixer": "^9.8.0", "autoprefixer": "^9.8.2",
"babel-eslint": "^11.0.0-beta.2", "babel-eslint": "^11.0.0-beta.2",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"browser-sync": "^2.26.7", "browser-sync": "^2.26.7",
"copy-webpack-plugin": "^5.1.1", "copy-webpack-plugin": "^5.1.1",
"css-loader": "^3.4.2", "css-loader": "^3.6.0",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
"del": "^5.1.0", "del": "^5.1.0",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-plugin-compat": "^3.5.1", "eslint-plugin-compat": "^3.5.1",
"eslint-plugin-eslint-comments": "^3.2.0", "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.1", "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",
@ -44,10 +44,10 @@
"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.5.0", "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.41.5",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"webpack-stream": "^5.2.1" "webpack-stream": "^5.2.1"
@ -60,26 +60,26 @@
"date-fns": "^2.14.0", "date-fns": "^2.14.0",
"document-register-element": "^1.14.3", "document-register-element": "^1.14.3",
"epubjs": "^0.3.85", "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.13.1",
"howler": "^2.2.0", "howler": "^2.2.0",
"intersection-observer": "^0.10.0", "intersection-observer": "^0.10.0",
"jellyfin-apiclient": "^1.2.0", "jellyfin-apiclient": "^1.2.2",
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto", "jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
"jquery": "^3.5.1", "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.12", "shaka-player": "^3.0.1",
"sortablejs": "^1.10.2", "sortablejs": "^1.10.2",
"swiper": "^5.4.1", "swiper": "^5.4.5",
"webcomponents.js": "^0.7.24", "webcomponents.js": "^0.7.24",
"whatwg-fetch": "^3.0.0" "whatwg-fetch": "^3.0.0"
}, },
@ -90,14 +90,22 @@
"overrides": [ "overrides": [
{ {
"test": [ "test": [
"src/components/accessSchedule/accessSchedule.js",
"src/components/actionSheet/actionSheet.js", "src/components/actionSheet/actionSheet.js",
"src/components/autoFocuser.js", "src/components/autoFocuser.js",
"src/components/cardbuilder/cardBuilder.js", "src/components/cardbuilder/cardBuilder.js",
"src/components/cardbuilder/chaptercardbuilder.js",
"src/components/cardbuilder/peoplecardbuilder.js",
"src/components/collectionEditor/collectionEditor.js",
"src/components/dialog/dialog.js",
"src/components/dialogHelper/dialogHelper.js",
"src/components/channelMapper/channelMapper.js",
"src/components/images/imageLoader.js", "src/components/images/imageLoader.js",
"src/components/indicators/indicators.js", "src/components/indicators/indicators.js",
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js", "src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
"src/components/mediaLibraryCreator/mediaLibraryCreator.js", "src/components/mediaLibraryCreator/mediaLibraryCreator.js",
"src/components/mediaLibraryEditor/mediaLibraryEditor.js", "src/components/mediaLibraryEditor/mediaLibraryEditor.js",
"src/components/listview/listview.js",
"src/components/playback/brightnessosd.js", "src/components/playback/brightnessosd.js",
"src/components/playback/mediasession.js", "src/components/playback/mediasession.js",
"src/components/playback/nowplayinghelper.js", "src/components/playback/nowplayinghelper.js",
@ -107,15 +115,19 @@
"src/components/playback/playmethodhelper.js", "src/components/playback/playmethodhelper.js",
"src/components/playback/remotecontrolautoplay.js", "src/components/playback/remotecontrolautoplay.js",
"src/components/playback/volumeosd.js", "src/components/playback/volumeosd.js",
"src/components/playlisteditor/playlisteditor.js",
"src/components/playmenu.js", "src/components/playmenu.js",
"src/components/sanatizefilename.js", "src/components/sanatizefilename.js",
"src/components/scrollManager.js", "src/components/scrollManager.js",
"src/components/syncplay/groupSelectionMenu.js", "src/components/shortcuts.js",
"src/components/syncplay/playbackPermissionManager.js", "src/components/syncPlay/groupSelectionMenu.js",
"src/components/syncplay/syncPlayManager.js", "src/components/syncPlay/playbackPermissionManager.js",
"src/components/syncplay/timeSyncManager.js", "src/components/syncPlay/syncPlayManager.js",
"src/components/syncPlay/timeSyncManager.js",
"src/controllers/dashboard/logs.js",
"src/controllers/dashboard/plugins/repositories.js",
"src/plugins/bookPlayer/plugin.js", "src/plugins/bookPlayer/plugin.js",
"src/plugins/bookPlayer/tableOfContent.js", "src/plugins/bookPlayer/tableOfContents.js",
"src/plugins/photoPlayer/plugin.js", "src/plugins/photoPlayer/plugin.js",
"src/scripts/deleteHelper.js", "src/scripts/deleteHelper.js",
"src/scripts/dfnshelper.js", "src/scripts/dfnshelper.js",
@ -124,6 +136,9 @@
"src/scripts/filesystem.js", "src/scripts/filesystem.js",
"src/scripts/imagehelper.js", "src/scripts/imagehelper.js",
"src/scripts/inputManager.js", "src/scripts/inputManager.js",
"src/plugins/backdropScreensaver/plugin.js",
"src/components/filterdialog/filterdialog.js",
"src/components/fetchhelper.js",
"src/scripts/keyboardNavigation.js", "src/scripts/keyboardNavigation.js",
"src/scripts/settings/appSettings.js", "src/scripts/settings/appSettings.js",
"src/scripts/settings/userSettings.js", "src/scripts/settings/userSettings.js",
@ -157,6 +172,7 @@
"prepare": "gulp --production", "prepare": "gulp --production",
"build:development": "gulp --development", "build:development": "gulp --development",
"build:production": "gulp --production", "build:production": "gulp --production",
"build:standalone": "gulp standalone --development",
"lint": "eslint \".\"", "lint": "eslint \".\"",
"stylelint": "stylelint \"src/**/*.css\"" "stylelint": "stylelint \"src/**/*.css\""
} }

View file

@ -1,6 +1,6 @@
<div data-role="page" class="page standalonePage"> <div data-role="page" class="page standalonePage">
<div class="padded-left padded-right padded-bottom-page"> <div class="padded-left padded-right padded-bottom-page">
<form class="addServerForm" style="margin: 0 auto;"> <form class="addServerForm" style="margin: 0 auto;" novalidate>
<h1>${HeaderConnectToServer}</h1> <h1>${HeaderConnectToServer}</h1>
<div class="inputContainer"> <div class="inputContainer">
<input is="emby-input" type="url" id="txtServerHost" required="required" label="${LabelServerHost}"/> <input is="emby-input" type="url" id="txtServerHost" required="required" label="${LabelServerHost}"/>

View file

@ -597,6 +597,7 @@
.detailImageContainer { .detailImageContainer {
position: relative; position: relative;
margin-top: -25vh; margin-top: -25vh;
margin-bottom: 10vh;
float: left; float: left;
width: 25vw; width: 25vw;
z-index: 3; z-index: 3;
@ -641,7 +642,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 {
@ -797,9 +799,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 {

View file

@ -121,6 +121,11 @@ div[data-role=page] {
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 { .force-scroll {
overflow-y: scroll; overflow-y: scroll;
} }

View file

@ -1,9 +1,20 @@
define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-button-light', 'formDialogStyle'], function (dialogHelper, datetime, globalize) { /* eslint-disable indent */
'use strict';
/**
* 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) { function getDisplayTime(hours) {
var minutes = 0; let minutes = 0;
var pct = hours % 1; const pct = hours % 1;
if (pct) { if (pct) {
minutes = parseInt(60 * pct); minutes = parseInt(60 * pct);
@ -13,25 +24,25 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt
} }
function populateHours(context) { function populateHours(context) {
var html = ''; let html = '';
for (var i = 0; i < 24; i++) { for (let i = 0; i < 24; i++) {
html += '<option value="' + i + '">' + getDisplayTime(i) + '</option>'; html += `<option value="${i}">${getDisplayTime(i)}</option>`;
} }
html += '<option value="24">' + getDisplayTime(0) + '</option>'; html += `<option value="24">${getDisplayTime(0)}</option>`;
context.querySelector('#selectStart').innerHTML = html; context.querySelector('#selectStart').innerHTML = html;
context.querySelector('#selectEnd').innerHTML = html; context.querySelector('#selectEnd').innerHTML = html;
} }
function loadSchedule(context, schedule) { function loadSchedule(context, {DayOfWeek, StartHour, EndHour}) {
context.querySelector('#selectDay').value = schedule.DayOfWeek || 'Sunday'; context.querySelector('#selectDay').value = DayOfWeek || 'Sunday';
context.querySelector('#selectStart').value = schedule.StartHour || 0; context.querySelector('#selectStart').value = StartHour || 0;
context.querySelector('#selectEnd').value = schedule.EndHour || 0; context.querySelector('#selectEnd').value = EndHour || 0;
} }
function submitSchedule(context, options) { function submitSchedule(context, options) {
var updatedSchedule = { const updatedSchedule = {
DayOfWeek: context.querySelector('#selectDay').value, DayOfWeek: context.querySelector('#selectDay').value,
StartHour: context.querySelector('#selectStart').value, StartHour: context.querySelector('#selectStart').value,
EndHour: context.querySelector('#selectEnd').value EndHour: context.querySelector('#selectEnd').value
@ -46,44 +57,42 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt
dialogHelper.close(context); dialogHelper.close(context);
} }
return { export function show(options) {
show: function (options) { return new Promise((resolve, reject) => {
return new Promise(function (resolve, reject) { // TODO: remove require
var xhr = new XMLHttpRequest(); require(['text!./components/accessSchedule/accessSchedule.template.html'], template => {
xhr.open('GET', 'components/accessSchedule/accessSchedule.template.html', true); const dlg = dialogHelper.createDialog({
removeOnClose: true,
xhr.onload = function (e) { size: 'small'
var template = this.response; });
var dlg = dialogHelper.createDialog({ dlg.classList.add('formDialog');
removeOnClose: true, let html = '';
size: 'small' html += globalize.translateDocument(template);
}); dlg.innerHTML = html;
dlg.classList.add('formDialog'); populateHours(dlg);
var html = ''; loadSchedule(dlg, options.schedule);
html += globalize.translateDocument(template); dialogHelper.open(dlg);
dlg.innerHTML = html; dlg.addEventListener('close', () => {
populateHours(dlg); if (dlg.submitted) {
loadSchedule(dlg, options.schedule); resolve(options.schedule);
dialogHelper.open(dlg); } else {
dlg.addEventListener('close', function () { reject();
if (dlg.submitted) { }
resolve(options.schedule); });
} else { dlg.querySelector('.btnCancel').addEventListener('click', () => {
reject(); dialogHelper.close(dlg);
} });
}); dlg.querySelector('form').addEventListener('submit', event => {
dlg.querySelector('.btnCancel').addEventListener('click', function () { submitSchedule(dlg, options);
dialogHelper.close(dlg); event.preventDefault();
}); return false;
dlg.querySelector('form').addEventListener('submit', function (event) { });
submitSchedule(dlg, options);
event.preventDefault();
return false;
});
};
xhr.send();
}); });
} });
}; }
});
/* eslint-enable indent */
export default {
show: show
};

View file

@ -31,7 +31,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();
} }

View file

@ -192,9 +192,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 +208,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 +221,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);
} }

View file

@ -368,9 +368,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) {
@ -541,7 +539,7 @@ import 'programStyles';
imgType = 'Backdrop'; imgType = 'Backdrop';
imgTag = item.ParentBackdropImageTags[0]; imgTag = item.ParentBackdropImageTags[0];
itemId = item.ParentBackdropItemId; itemId = item.ParentBackdropItemId;
} else if (item.ImageTags && item.ImageTags.Primary) { } else if (item.ImageTags && item.ImageTags.Primary && (item.Type !== 'Episode' || item.ChildCount !== 0)) {
imgType = 'Primary'; imgType = 'Primary';
imgTag = item.ImageTags.Primary; imgTag = item.ImageTags.Primary;
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
@ -556,7 +554,10 @@ 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'; imgType = 'Primary';
imgTag = item.PrimaryImageTag; imgTag = item.PrimaryImageTag;
@ -577,10 +578,6 @@ import 'programStyles';
imgType = 'Primary'; imgType = 'Primary';
imgTag = item.ParentPrimaryImageTag; imgTag = item.ParentPrimaryImageTag;
itemId = item.ParentPrimaryImageItemId; itemId = item.ParentPrimaryImageItemId;
} else if (item.SeriesPrimaryImageTag) {
imgType = 'Primary';
imgTag = item.SeriesPrimaryImageTag;
itemId = item.SeriesId;
} else if (item.AlbumId && item.AlbumPrimaryImageTag) { } else if (item.AlbumId && item.AlbumPrimaryImageTag) {
imgType = 'Primary'; imgType = 'Primary';
imgTag = item.AlbumPrimaryImageTag; imgTag = item.AlbumPrimaryImageTag;
@ -1370,9 +1367,6 @@ import 'programStyles';
let cardScalableClose = ''; let cardScalableClose = '';
let cardContentClass = 'cardContent'; let cardContentClass = 'cardContent';
if (!options.cardLayout) {
cardContentClass += ' cardContent-shadow';
}
let blurhashAttrib = ''; let blurhashAttrib = '';
if (blurhash && blurhash.length > 0) { if (blurhash && blurhash.length > 0) {
@ -1380,21 +1374,20 @@ import 'programStyles';
} }
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 + '" ' + blurhashAttrib + '>') : ('<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 + '" ' + blurhashAttrib + '>') : ('<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>';

View file

@ -1,13 +1,23 @@
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,12 +27,12 @@ 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) {
@ -31,24 +41,24 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
} }
} }
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,50 +72,50 @@ 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 (chapter.ImageTag) { if (ImageTag) {
return apiClient.getScaledImageUrl(item.Id, { return apiClient.getScaledImageUrl(Id, {
maxWidth: maxWidth * 2, maxWidth: maxWidth * 2,
tag: chapter.ImageTag, tag: 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) {
var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient); const imgUrl = getImgUrl(item, chapter, index, width || 400, apiClient);
var cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer'; let cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
if (options.coverImage) { if (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>'; const html = `<button type="button" class="${className}"${dataAttributes}><div class="${cardBoxCssClass}"><div class="${cardScalableClass}"><div class="cardPadder-${shape}"></div>${cardImageContainer}</div><div class="innerCardFooter">${nameHtml}</div></div></div></button>`;
return html; 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
@ -121,15 +131,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,7 +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,
@ -15,8 +21,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 smoothScrollY">'; 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,32 @@
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 appHost from 'apphost';
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);
@ -24,7 +40,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
function createCollection(apiClient, dlg) { function createCollection(apiClient, dlg) {
var url = apiClient.getUrl('Collections', { const 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,11 +52,11 @@ 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);
@ -56,7 +72,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
function addToCollection(apiClient, dlg, id) { function addToCollection(apiClient, dlg, id) {
var url = apiClient.getUrl('Collections/' + id + '/Items', { const url = apiClient.getUrl(`Collections/${id}/Items`, {
Ids: dlg.querySelector('.fldSelectedItemIds').value || '' Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
}); });
@ -65,14 +81,14 @@ 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'));
}); });
}); });
@ -86,11 +102,11 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
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 +114,16 @@ 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 => {
var html = ''; let html = '';
html += '<option value="">' + globalize.translate('OptionNew') + '</option>'; html += `<option value="">${globalize.translate('OptionNew')}</option>`;
html += result.Items.map(function (i) { html += result.Items.map(i => {
return '<option value="' + i.Id + '">' + i.Name + '</option>'; return `<option value="${i.Id}">${i.Name}</option>`;
}); });
select.innerHTML = html; select.innerHTML = html;
@ -120,7 +136,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
function getEditorHtml() { function getEditorHtml() {
var html = ''; let 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 +150,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" />';
@ -188,7 +204,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 +212,77 @@ 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;
CollectionEditor.prototype.show = function (options) { const dialogOptions = {
removeOnClose: true,
var items = options.items || {}; scrollY: false
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>';
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>`;
} }
return Promise.reject(); html += '</div>';
});
};
return CollectionEditor; 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 dialogHelper.open(dlg).then(() => {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (dlg.submitted) {
return Promise.resolve();
}
return Promise.reject();
});
}
}
/* eslint-enable indent */
export default showEditor;

View file

@ -53,7 +53,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();
} }

View file

@ -1,20 +1,31 @@
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) {
var dialogOptions = { const 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 +33,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,7 +41,7 @@ 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');
} }
@ -44,27 +55,27 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
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++) {
var item = options.buttons[i]; const item = options.buttons[i];
var autoFocus = i === 0 ? ' autofocus' : ''; const autoFocus = i === 0 ? ' autofocus' : '';
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize'; let 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 +86,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,18 +99,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 +124,9 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
}); });
} }
return function (text, title) { export async function show(text, title) {
var options; let options;
if (typeof text === 'string') { if (typeof text === 'string') {
options = { options = {
title: title, title: title,
@ -125,10 +136,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,7 +1,15 @@
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() {
@ -25,7 +33,7 @@ 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
@ -39,14 +47,14 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
function DialogHashHandler(dlg, hash, resolve) { function DialogHashHandler(dlg, hash, resolve) {
var self = this; const 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) {
var isBack = self.originalUrl === window.location.href; const isBack = self.originalUrl === window.location.href;
if (isBack || !isOpened(dlg)) { if (isBack || !isOpened(dlg)) {
window.removeEventListener('popstate', onHashChange); window.removeEventListener('popstate', onHashChange);
@ -84,7 +92,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 +105,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 +116,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 +126,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 +149,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 {
@ -151,10 +159,10 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
function addBackdropOverlay(dlg) { function addBackdropOverlay(dlg) {
var backdrop = document.createElement('div'); const 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 +170,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 +178,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,26 +192,26 @@ 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);
}); });
} }
@ -213,7 +221,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
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)) {
@ -233,7 +241,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
cancelable: false cancelable: false
})); }));
var onAnimationFinish = function () { const onAnimationFinish = () => {
focusManager.popScope(dlg); focusManager.popScope(dlg);
dlg.classList.add('hide'); dlg.classList.add('hide');
@ -249,7 +257,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
function animateDialogOpen(dlg) { function animateDialogOpen(dlg) {
var onAnimationFinish = function () { const onAnimationFinish = () => {
focusManager.pushScope(dlg); focusManager.pushScope(dlg);
if (dlg.getAttribute('data-autofocus') === 'true') { if (dlg.getAttribute('data-autofocus') === 'true') {
@ -264,7 +272,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
if (enableAnimation()) { if (enableAnimation()) {
var onFinish = function () { const onFinish = () => {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, { dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true once: true
}); });
@ -283,24 +291,24 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
if (enableAnimation()) { if (enableAnimation()) {
var animated = true; let 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,7 +326,7 @@ 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) {
@ -343,7 +351,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
function removeBackdrop(dlg) { function removeBackdrop(dlg) {
var backdrop = dlg.backdrop; const backdrop = dlg.backdrop;
if (!backdrop) { if (!backdrop) {
return; return;
@ -351,7 +359,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
dlg.backdrop = null; dlg.backdrop = null;
var onAnimationFinish = function () { const onAnimationFinish = () => {
tryRemoveElement(backdrop); tryRemoveElement(backdrop);
}; };
@ -368,20 +376,20 @@ 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 +414,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,7 +469,7 @@ 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()) {
@ -469,16 +477,16 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
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 +496,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

@ -1,21 +1,19 @@
define([], function () { /* eslint-disable indent */
'use strict'; export function getFetchPromise(request) {
function getFetchPromise(request) { const headers = request.headers || {};
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) {
@ -33,12 +31,12 @@ define([], function () {
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}`;
} }
} }
@ -51,11 +49,11 @@ 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) {
var timeout = setTimeout(reject, timeoutMs); const timeout = setTimeout(reject, timeoutMs);
options = options || {}; options = options || {};
options.credentials = 'same-origin'; options.credentials = 'same-origin';
@ -63,50 +61,47 @@ 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 +110,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
}); });
@ -380,18 +413,21 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');
dlg.classList.add('filterDialog'); dlg.classList.add('filterDialog');
dlg.innerHTML = globalize.translateDocument(template); dlg.innerHTML = globalize.translateDocument(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

@ -55,7 +55,7 @@
/* 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; align-items: flex-end;
justify-content: flex-end; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
} }

View file

@ -168,7 +168,7 @@ 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) {
@ -254,7 +254,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',

View file

@ -58,6 +58,7 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
var html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join(''); var html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
page.querySelector('#imageOutput').innerHTML = html; page.querySelector('#imageOutput').innerHTML = html;
page.querySelector('#dropImageText').classList.add('hide');
page.querySelector('#fldUpload').classList.remove('hide'); page.querySelector('#fldUpload').classList.remove('hide');
}; };
})(file); })(file);

View file

@ -20,7 +20,7 @@
</div> </div>
<div> <div>
<div class="imageEditor-dropZone fieldDescription"> <div class="imageEditor-dropZone fieldDescription">
<div>${LabelDropImageHere}</div> <div id="dropImageText">${LabelDropImageHere}</div>
<output id="imageOutput" class="flex align-items-center justify-content-center" style="position: absolute;top:0;left:0;right:0;bottom:0;width:100%;"></output> <output id="imageOutput" class="flex align-items-center justify-content-center" style="position: absolute;top:0;left:0;right:0;bottom:0;width:100%;"></output>
<input type="file" accept="image/*" id="uploadImage" name="uploadImage" style="position: absolute;top:0;left:0;right:0;bottom:0;width:100%;opacity:0;" /> <input type="file" accept="image/*" id="uploadImage" name="uploadImage" style="position: absolute;top:0;left:0;right:0;bottom:0;width:100%;opacity:0;" />
</div> </div>

View file

@ -1,11 +1,11 @@
.lazy-image-fadein { .lazy-image-fadein {
opacity: 1; opacity: 1;
transition: opacity 0.7s; transition: opacity 0.5s;
} }
.lazy-image-fadein-fast { .lazy-image-fadein-fast {
opacity: 1; opacity: 1;
transition: opacity 0.2s; transition: opacity 0.1s;
} }
.lazy-hidden { .lazy-hidden {
@ -29,4 +29,5 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
z-index: 100; z-index: 100;
pointer-events: none;
} }

View file

@ -319,7 +319,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
switch (id) { switch (id) {
case 'addtocollection': case 'addtocollection':
require(['collectionEditor'], function (collectionEditor) { require(['collectionEditor'], function (collectionEditor) {
new collectionEditor().show({ new collectionEditor.showEditor({
items: [itemId], items: [itemId],
serverId: serverId serverId: serverId
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); }).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
@ -327,7 +327,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
break; break;
case 'addtoplaylist': case 'addtoplaylist':
require(['playlistEditor'], function (playlistEditor) { require(['playlistEditor'], function (playlistEditor) {
new playlistEditor().show({ new playlistEditor.showEditor({
items: [itemId], items: [itemId],
serverId: serverId serverId: serverId
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); }).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
@ -403,7 +403,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
break; break;
case 'moremediainfo': case 'moremediainfo':
require(['itemMediaInfo'], function (itemMediaInfo) { require(['itemMediaInfo'], function (itemMediaInfo) {
itemMediaInfo.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); itemMediaInfo.show(itemId, serverId).then(getResolveFunction(resolve, id), getResolveFunction(resolve, id));
}); });
break; break;
case 'refresh': case 'refresh':

View file

@ -11,9 +11,9 @@
(entries) => { (entries) => {
entries.forEach(entry => { entries.forEach(entry => {
callback(entry); callback(entry);
}, });
{rootMargin: '50%'}); },
}); {rootMargin: '25%'});
this.observer = observer; this.observer = observer;
} }

View file

@ -1,5 +1,20 @@
define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutManager', 'globalize', 'datetime', 'apphost', 'css!./listview', 'emby-ratingbutton', 'emby-playstatebutton'], function (itemHelper, mediaInfo, indicators, connectionManager, layoutManager, globalize, datetime, appHost) { /* eslint-disable indent */
'use strict';
/**
* Module for display list view.
* @module components/listview/listview
*/
import itemHelper from 'itemHelper';
import mediaInfo from 'mediaInfo';
import indicators from 'indicators';
import connectionManager from 'connectionManager';
import layoutManager from 'layoutManager';
import globalize from 'globalize';
import datetime from 'datetime';
import 'css!./listview';
import 'emby-ratingbutton';
import 'emby-playstatebutton';
function getIndex(item, options) { function getIndex(item, options) {
@ -8,9 +23,9 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
return item.ParentIndexNumber == null ? '' : globalize.translate('ValueDiscNumber', item.ParentIndexNumber); return item.ParentIndexNumber == null ? '' : globalize.translate('ValueDiscNumber', item.ParentIndexNumber);
} }
var sortBy = (options.sortBy || '').toLowerCase(); const sortBy = (options.sortBy || '').toLowerCase();
var code; let code;
var name; let name;
if (sortBy.indexOf('sortname') === 0) { if (sortBy.indexOf('sortname') === 0) {
@ -69,10 +84,10 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
function getImageUrl(item, width) { function getImageUrl(item, width) {
var apiClient = connectionManager.getApiClient(item.ServerId); const apiClient = connectionManager.getApiClient(item.ServerId);
let itemId; let itemId;
var options = { const options = {
maxWidth: width * 2, maxWidth: width * 2,
type: 'Primary' type: 'Primary'
}; };
@ -80,9 +95,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (item.ImageTags && item.ImageTags.Primary) { if (item.ImageTags && item.ImageTags.Primary) {
options.tag = item.ImageTags.Primary; options.tag = item.ImageTags.Primary;
itemId = item.Id; itemId = item.Id;
} } else if (item.AlbumId && item.AlbumPrimaryImageTag) {
if (item.AlbumId && item.AlbumPrimaryImageTag) {
options.tag = item.AlbumPrimaryImageTag; options.tag = item.AlbumPrimaryImageTag;
itemId = item.AlbumId; itemId = item.AlbumId;
} else if (item.SeriesId && item.SeriesPrimaryImageTag) { } else if (item.SeriesId && item.SeriesPrimaryImageTag) {
@ -92,18 +105,20 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
options.tag = item.ParentPrimaryImageTag; options.tag = item.ParentPrimaryImageTag;
itemId = item.ParentPrimaryImageItemId; itemId = item.ParentPrimaryImageItemId;
} }
let blurHashes = item.ImageBlurHashes || {}; let blurHashes = item.ImageBlurHashes || {};
let blurhashstr = (blurHashes[options.type] || {})[options.tag]; let blurhashstr = (blurHashes[options.type] || {})[options.tag];
if (itemId) { if (itemId) {
return { url: apiClient.getScaledImageUrl(itemId, options), blurhash: blurhashstr }; return { url: apiClient.getScaledImageUrl(itemId, options), blurhash: blurhashstr };
} }
return null;
} }
function getChannelImageUrl(item, width) { function getChannelImageUrl(item, width) {
var apiClient = connectionManager.getApiClient(item.ServerId); const apiClient = connectionManager.getApiClient(item.ServerId);
var options = { const options = {
maxWidth: width * 2, maxWidth: width * 2,
type: 'Primary' type: 'Primary'
}; };
@ -121,13 +136,13 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
function getTextLinesHtml(textlines, isLargeStyle) { function getTextLinesHtml(textlines, isLargeStyle) {
var html = ''; let html = '';
var largeTitleTagName = layoutManager.tv ? 'h2' : 'div'; const largeTitleTagName = layoutManager.tv ? 'h2' : 'div';
for (var i = 0, length = textlines.length; i < length; i++) { for (let i = 0, length = textlines.length; i < length; i++) {
var text = textlines[i]; const text = textlines[i];
if (!text) { if (!text) {
continue; continue;
@ -135,7 +150,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (i === 0) { if (i === 0) {
if (isLargeStyle) { if (isLargeStyle) {
html += '<' + largeTitleTagName + ' class="listItemBodyText">'; html += `<${largeTitleTagName} class="listItemBodyText">`;
} else { } else {
html += '<div class="listItemBodyText">'; html += '<div class="listItemBodyText">';
} }
@ -144,7 +159,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
} }
html += (textlines[i] || '&nbsp;'); html += (textlines[i] || '&nbsp;');
if (i === 0 && isLargeStyle) { if (i === 0 && isLargeStyle) {
html += '</' + largeTitleTagName + '>'; html += `</${largeTitleTagName}>`;
} else { } else {
html += '</div>'; html += '</div>';
} }
@ -155,13 +170,13 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
function getRightButtonsHtml(options) { function getRightButtonsHtml(options) {
var html = ''; let html = '';
for (var i = 0, length = options.rightButtons.length; i < length; i++) { for (let i = 0, length = options.rightButtons.length; i < length; i++) {
var button = options.rightButtons[i]; const button = options.rightButtons[i];
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="custom" data-customaction="' + button.id + '" title="' + button.title + '"><span class="material-icons ' + button.icon + '"></span></button>'; html += `<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="custom" data-customaction="${button.id}" title="${button.title}"><span class="material-icons ${button.icon}"></span></button>`;
} }
return html; return html;
@ -171,34 +186,34 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
return item.Id; return item.Id;
} }
function getListViewHtml(options) { export function getListViewHtml(options) {
var items = options.items; const items = options.items;
var groupTitle = ''; let groupTitle = '';
var action = options.action || 'link'; const action = options.action || 'link';
var isLargeStyle = options.imageSize === 'large'; const isLargeStyle = options.imageSize === 'large';
var enableOverview = options.enableOverview; const enableOverview = options.enableOverview;
var clickEntireItem = layoutManager.tv ? true : false; const clickEntireItem = layoutManager.tv ? true : false;
var outerTagName = clickEntireItem ? 'button' : 'div'; const outerTagName = clickEntireItem ? 'button' : 'div';
var enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : true; const enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : true;
var outerHtml = ''; let outerHtml = '';
var enableContentWrapper = options.enableOverview && !layoutManager.tv; const enableContentWrapper = options.enableOverview && !layoutManager.tv;
var containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId); const containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId);
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 html = ''; let html = '';
if (options.showIndex) { if (options.showIndex) {
var itemGroupTitle = getIndex(item, options); const itemGroupTitle = getIndex(item, options);
if (itemGroupTitle !== groupTitle) { if (itemGroupTitle !== groupTitle) {
@ -220,7 +235,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
} }
} }
var cssClass = 'listItem'; let cssClass = 'listItem';
if (options.border || (options.highlight !== false && !layoutManager.tv)) { if (options.border || (options.highlight !== false && !layoutManager.tv)) {
cssClass += ' listItem-border'; cssClass += ' listItem-border';
@ -234,28 +249,28 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
cssClass += ' listItem-focusscale'; cssClass += ' listItem-focusscale';
} }
var downloadWidth = 80; let downloadWidth = 80;
if (isLargeStyle) { if (isLargeStyle) {
cssClass += ' listItem-largeImage'; cssClass += ' listItem-largeImage';
downloadWidth = 500; downloadWidth = 500;
} }
var playlistItemId = item.PlaylistItemId ? (' data-playlistitemid="' + item.PlaylistItemId + '"') : ''; const playlistItemId = item.PlaylistItemId ? (` data-playlistitemid="${item.PlaylistItemId}"`) : '';
var positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"') : ''; const positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (` data-positionticks="${item.UserData.PlaybackPositionTicks}"`) : '';
var collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : ''; const collectionIdData = options.collectionId ? (` data-collectionid="${options.collectionId}"`) : '';
var playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : ''; const playlistIdData = options.playlistId ? (` data-playlistid="${options.playlistId}"`) : '';
var mediaTypeData = item.MediaType ? (' data-mediatype="' + item.MediaType + '"') : ''; const mediaTypeData = item.MediaType ? (` data-mediatype="${item.MediaType}"`) : '';
var collectionTypeData = item.CollectionType ? (' data-collectiontype="' + item.CollectionType + '"') : ''; const collectionTypeData = item.CollectionType ? (` data-collectiontype="${item.CollectionType}"`) : '';
var channelIdData = item.ChannelId ? (' data-channelid="' + item.ChannelId + '"') : ''; const channelIdData = item.ChannelId ? (` data-channelid="${item.ChannelId}"`) : '';
if (enableContentWrapper) { if (enableContentWrapper) {
cssClass += ' listItem-withContentWrapper'; cssClass += ' listItem-withContentWrapper';
} }
html += '<' + outerTagName + ' class="' + cssClass + '"' + playlistItemId + ' data-action="' + action + '" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + '>'; html += `<${outerTagName} class="${cssClass}"${playlistItemId} data-action="${action}" data-isfolder="${item.IsFolder}" data-id="${item.Id}" data-serverid="${item.ServerId}" data-type="${item.Type}"${mediaTypeData}${collectionTypeData}${channelIdData}${positionTicksData}${collectionIdData}${playlistIdData}>`;
if (enableContentWrapper) { if (enableContentWrapper) {
@ -278,37 +293,37 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
imageClass += ' listItemImage-large-tv'; imageClass += ' listItemImage-large-tv';
} }
var playOnImageClick = options.imagePlayButton && !layoutManager.tv; const playOnImageClick = options.imagePlayButton && !layoutManager.tv;
if (!clickEntireItem) { if (!clickEntireItem) {
imageClass += ' itemAction'; imageClass += ' itemAction';
} }
var imageAction = playOnImageClick ? 'resume' : action; const imageAction = playOnImageClick ? 'resume' : action;
let blurhashAttrib = ''; let blurhashAttrib = '';
if (blurhash && blurhash.length > 0) { if (blurhash && blurhash.length > 0) {
blurhashAttrib = 'data-blurhash="' + blurhash + '"'; blurhashAttrib = `data-blurhash="${blurhash}"`;
} }
if (imgUrl) { if (imgUrl) {
html += '<div data-action="' + imageAction + '" class="' + imageClass + ' lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + ' item-icon>'; html += `<div data-action="${imageAction}" class="${imageClass} lazy" data-src="${imgUrl}" ${blurhashAttrib} item-icon>`;
} else { } else {
html += '<div class="' + imageClass + '">'; html += `<div class="${imageClass}">`;
} }
var indicatorsHtml = ''; let indicatorsHtml = '';
indicatorsHtml += indicators.getPlayedIndicatorHtml(item); indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
if (indicatorsHtml) { if (indicatorsHtml) {
html += '<div class="indicators listItemIndicators">' + indicatorsHtml + '</div>'; html += `<div class="indicators listItemIndicators">${indicatorsHtml}</div>`;
} }
if (playOnImageClick) { if (playOnImageClick) {
html += '<button is="paper-icon-button-light" class="listItemImageButton itemAction" data-action="resume"><span class="material-icons listItemImageButton-icon play_arrow"></span></button>'; html += '<button is="paper-icon-button-light" class="listItemImageButton itemAction" data-action="resume"><span class="material-icons listItemImageButton-icon play_arrow"></span></button>';
} }
var progressHtml = indicators.getProgressBarHtml(item, { const progressHtml = indicators.getProgressBarHtml(item, {
containerClass: 'listItemProgressBar' containerClass: 'listItemProgressBar'
}); });
@ -325,7 +340,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
html += '</div>'; html += '</div>';
} }
var textlines = []; const textlines = [];
if (options.showProgramDateTime) { if (options.showProgramDateTime) {
textlines.push(datetime.toLocaleString(datetime.parseISO8601Date(item.StartDate), { textlines.push(datetime.toLocaleString(datetime.parseISO8601Date(item.StartDate), {
@ -348,7 +363,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
} }
} }
var parentTitle = null; let parentTitle = null;
if (options.showParentTitle) { if (options.showParentTitle) {
if (item.Type === 'Episode') { if (item.Type === 'Episode') {
@ -358,12 +373,12 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
} }
} }
var displayName = itemHelper.getDisplayName(item, { let displayName = itemHelper.getDisplayName(item, {
includeParentInfo: options.includeParentInfoInTitle includeParentInfo: options.includeParentInfoInTitle
}); });
if (options.showIndexNumber && item.IndexNumber != null) { if (options.showIndexNumber && item.IndexNumber != null) {
displayName = item.IndexNumber + '. ' + displayName; displayName = `${item.IndexNumber}. ${displayName}`;
} }
if (options.showParentTitle && options.parentTitleWithTitle) { if (options.showParentTitle && options.parentTitleWithTitle) {
@ -394,14 +409,14 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
} }
} else { } else {
var showArtist = options.artist === true; let showArtist = options.artist === true;
var artistItems = item.ArtistItems; const artistItems = item.ArtistItems;
if (!showArtist && options.artist !== false) { if (!showArtist && options.artist !== false) {
if (!artistItems || !artistItems.length) { if (!artistItems || !artistItems.length) {
showArtist = true; showArtist = true;
} else if (artistItems.length > 1 || containerAlbumArtistIds.indexOf(artistItems[0].Id) === -1) { } else if (artistItems.length > 1 || !containerAlbumArtistIds.includes(artistItems[0].Id)) {
showArtist = true; showArtist = true;
} }
} }
@ -409,7 +424,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (showArtist) { if (showArtist) {
if (artistItems && item.Type !== 'MusicAlbum') { if (artistItems && item.Type !== 'MusicAlbum') {
textlines.push(artistItems.map(function (a) { textlines.push(artistItems.map(a => {
return a.Name; return a.Name;
}).join(', ')); }).join(', '));
} }
@ -432,7 +447,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
cssClass += ' listItemBody-noleftpadding'; cssClass += ' listItemBody-noleftpadding';
} }
html += '<div class="' + cssClass + '">'; html += `<div class="${cssClass}">`;
const moreIcon = 'more_vert'; const moreIcon = 'more_vert';
@ -441,14 +456,16 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (options.mediaInfo !== false) { if (options.mediaInfo !== false) {
if (!enableSideMediaInfo) { if (!enableSideMediaInfo) {
var mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText'; const mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText';
html += '<div class="' + mediaInfoClass + '">' + mediaInfo.getPrimaryMediaInfoHtml(item, { html += `<div class="${mediaInfoClass}">`;
html += mediaInfo.getPrimaryMediaInfoHtml(item, {
episodeTitle: false, episodeTitle: false,
originalAirDate: false, originalAirDate: false,
subtitles: false subtitles: false
}) + '</div>'; });
html += '</div>';
} }
} }
@ -462,7 +479,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (options.mediaInfo !== false) { if (options.mediaInfo !== false) {
if (enableSideMediaInfo) { if (enableSideMediaInfo) {
html += '<div class="secondary listItemMediaInfo">' + mediaInfo.getPrimaryMediaInfoHtml(item, { html += '<div class="secondary listItemMediaInfo">';
html += mediaInfo.getPrimaryMediaInfoHtml(item, {
year: false, year: false,
container: false, container: false,
@ -470,7 +488,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
criticRating: false, criticRating: false,
endsAt: false endsAt: false
}) + '</div>'; });
html += '</div>';
} }
} }
@ -487,7 +506,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
} }
if (options.moreButton !== false) { if (options.moreButton !== false) {
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="menu"><span class="material-icons ' + moreIcon + '"></span></button>'; html += `<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="menu"><span class="material-icons ${moreIcon}"></span></button>`;
} }
if (options.infoButton) { if (options.infoButton) {
@ -500,15 +519,15 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
if (options.enableUserDataButtons !== false) { if (options.enableUserDataButtons !== false) {
var userData = item.UserData || {}; const userData = item.UserData || {};
var likes = userData.Likes == null ? '' : userData.Likes; const likes = userData.Likes == null ? '' : userData.Likes;
if (itemHelper.canMarkPlayed(item)) { if (itemHelper.canMarkPlayed(item)) {
html += '<button is="emby-playstatebutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons check"></span></button>'; html += `<button is="emby-playstatebutton" type="button" class="listItemButton paper-icon-button-light" data-id="${item.Id}" data-serverid="${item.ServerId}" data-itemtype="${item.Type}" data-played="${userData.Played}"><span class="material-icons check"></span></button>`;
} }
if (itemHelper.canRate(item)) { if (itemHelper.canRate(item)) {
html += '<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons favorite"></span></button>'; html += `<button is="emby-ratingbutton" type="button" class="listItemButton paper-icon-button-light" data-id="${item.Id}" data-serverid="${item.ServerId}" data-itemtype="${item.Type}" data-likes="${likes}" data-isfavorite="${userData.IsFavorite}"><span class="material-icons favorite"></span></button>`;
} }
} }
} }
@ -524,7 +543,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
} }
} }
html += '</' + outerTagName + '>'; html += `</${outerTagName}>`;
outerHtml += html; outerHtml += html;
} }
@ -532,7 +551,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
return outerHtml; return outerHtml;
} }
return { /* eslint-enable indent */
getListViewHtml: getListViewHtml export default {
}; getListViewHtml: getListViewHtml
}); };

View file

@ -1,92 +0,0 @@
define(['loading', 'events', 'dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (loading, events, dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
'use strict';
function showDialog(instance, options, template) {
var dialogOptions = {
removeOnClose: true,
scrollY: false
};
var enableTvLayout = layoutManager.tv;
if (enableTvLayout) {
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions);
var configuredButtons = [];
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateHtml(template, 'core');
dlg.classList.add('align-items-center');
dlg.classList.add('justify-items-center');
var formDialogContent = dlg.querySelector('.formDialogContent');
formDialogContent.style['flex-grow'] = 'initial';
formDialogContent.style['max-width'] = '50%';
formDialogContent.style['max-height'] = '60%';
if (enableTvLayout) {
scrollHelper.centerFocus.on(formDialogContent, false);
dlg.querySelector('.formDialogHeader').style.marginTop = '15%';
} else {
dlg.classList.add('dialog-fullscreen-lowres');
}
//dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
// dialogHelper.close(dlg);
//});
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title;
dlg.querySelector('.text').innerHTML = options.text;
instance.dlg = dlg;
return dialogHelper.open(dlg).then(function () {
if (enableTvLayout) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
}
loading.hide();
});
}
function LoadingDialog(options) {
this.options = options;
}
LoadingDialog.prototype.show = function () {
var instance = this;
loading.show();
return new Promise(function (resolve, reject) {
require(['text!./../dialog/dialog.template.html'], function (template) {
showDialog(instance, instance.options, template);
resolve();
});
});
};
LoadingDialog.prototype.setTitle = function (title) {
};
LoadingDialog.prototype.setText = function (text) {
};
LoadingDialog.prototype.hide = function () {
if (this.dlg) {
dialogHelper.close(this.dlg);
this.dlg = null;
}
};
LoadingDialog.prototype.destroy = function () {
this.dlg = null;
this.options = null;
};
return LoadingDialog;
});

View file

@ -273,7 +273,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
} }
} }
if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && !showFolderRuntime && options.runtime !== false) { if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && item.Type !== 'Book' && !showFolderRuntime && options.runtime !== false) {
if (item.Type === 'Audio') { if (item.Type === 'Audio') {

View file

@ -308,8 +308,8 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
} }
}); });
context.removeEventListener('submit', onEditorClick); context.removeEventListener('click', onEditorClick);
context.addEventListener('submit', onEditorClick); context.addEventListener('click', onEditorClick);
var form = context.querySelector('form'); var form = context.querySelector('form');
form.removeEventListener('submit', onSubmit); form.removeEventListener('submit', onSubmit);

View file

@ -7,7 +7,6 @@
<div class="formDialogContent smoothScrollY" style="padding-top:2em;"> <div class="formDialogContent smoothScrollY" style="padding-top:2em;">
<form class="popupEditPersonForm dialogContentInner dialog-content-centered"> <form class="popupEditPersonForm dialogContentInner dialog-content-centered">
<div class="inputContainer"> <div class="inputContainer">
<input type="text" is="emby-input" class="txtPersonName" required="required" label="${LabelName}" /> <input type="text" is="emby-input" class="txtPersonName" required="required" label="${LabelName}" />
</div> </div>
@ -23,6 +22,7 @@
<option value="Writer">${Writer}</option> <option value="Writer">${Writer}</option>
</select> </select>
</div> </div>
<div class="inputContainer fldRole hide"> <div class="inputContainer fldRole hide">
<input is="emby-input" type="text" class="txtPersonRole" label="${LabelPersonRole}" /> <input is="emby-input" type="text" class="txtPersonRole" label="${LabelPersonRole}" />
<div class="fieldDescription">${LabelPersonRoleHelp}</div> <div class="fieldDescription">${LabelPersonRoleHelp}</div>
@ -33,6 +33,5 @@
<span>${Save}</span> <span>${Save}</span>
</button> </button>
</div> </div>
</form> </form>
</div> </div>

View file

@ -255,7 +255,7 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
switch (id) { switch (id) {
case 'addtocollection': case 'addtocollection':
require(['collectionEditor'], function (collectionEditor) { require(['collectionEditor'], function (collectionEditor) {
new collectionEditor().show({ new collectionEditor.showEditor({
items: items, items: items,
serverId: serverId serverId: serverId
}); });
@ -265,7 +265,7 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
break; break;
case 'playlist': case 'playlist':
require(['playlistEditor'], function (playlistEditor) { require(['playlistEditor'], function (playlistEditor) {
new playlistEditor().show({ new playlistEditor.showEditor({
items: items, items: items,
serverId: serverId serverId: serverId
}); });

View file

@ -241,6 +241,15 @@ import connectionManager from 'connectionManager';
navigator.mediaSession.setActionHandler('seekforward', function () { navigator.mediaSession.setActionHandler('seekforward', function () {
execute('fastForward'); execute('fastForward');
}); });
/* eslint-disable-next-line compat/compat */
navigator.mediaSession.setActionHandler('seekto', function (object) {
let item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem;
// Convert to ms
let duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
let wantedTime = object.seekTime * 1000;
playbackManager.seekPercent(wantedTime / duration * 100, currentPlayer);
});
} }
events.on(playbackManager, 'playerchange', function () { events.on(playbackManager, 'playerchange', function () {

View file

@ -1907,11 +1907,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
// Setting this to true may cause some incorrect sorting // Setting this to true may cause some incorrect sorting
Recursive: false, Recursive: false,
SortBy: options.shuffle ? 'Random' : 'SortName', SortBy: options.shuffle ? 'Random' : 'SortName',
MediaTypes: 'Photo,Video', MediaTypes: 'Photo,Video'
Limit: 500
}).then(function (result) { }).then(function (result) {
var items = result.Items; var items = result.Items;
var index = items.map(function (i) { var index = items.map(function (i) {

View file

@ -1,13 +1,28 @@
define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', 'connectionManager', 'userSettings', 'appRouter', 'globalize', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button'], function (dom, shell, dialogHelper, loading, layoutManager, playbackManager, connectionManager, userSettings, appRouter, globalize) { import dom from 'dom';
'use strict'; import dialogHelper from 'dialogHelper';
import loading from 'loading';
import layoutManager from 'layoutManager';
import playbackManager from 'playbackManager';
import connectionManager from 'connectionManager';
import * as userSettings from 'userSettings';
import appRouter from 'appRouter';
import globalize from 'globalize';
import 'emby-input';
import 'paper-icon-button-light';
import 'emby-select';
import 'material-icons';
import 'css!./../formdialog';
import 'emby-button';
var currentServerId; /* eslint-disable indent */
let currentServerId;
function onSubmit(e) { function onSubmit(e) {
var panel = dom.parentWithClass(this, 'dialog'); const panel = dom.parentWithClass(this, 'dialog');
var playlistId = panel.querySelector('#selectPlaylistToAddTo').value; const playlistId = panel.querySelector('#selectPlaylistToAddTo').value;
var apiClient = connectionManager.getApiClient(currentServerId); const apiClient = connectionManager.getApiClient(currentServerId);
if (playlistId) { if (playlistId) {
userSettings.set('playlisteditor-lastplaylistid', playlistId); userSettings.set('playlisteditor-lastplaylistid', playlistId);
@ -23,7 +38,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
function createPlaylist(apiClient, dlg) { function createPlaylist(apiClient, dlg) {
loading.show(); loading.show();
var url = apiClient.getUrl('Playlists', { const url = apiClient.getUrl('Playlists', {
Name: dlg.querySelector('#txtNewPlaylistName').value, Name: dlg.querySelector('#txtNewPlaylistName').value,
Ids: dlg.querySelector('.fldSelectedItemIds').value || '', Ids: dlg.querySelector('.fldSelectedItemIds').value || '',
userId: apiClient.getCurrentUserId() userId: apiClient.getCurrentUserId()
@ -34,10 +49,10 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
type: 'POST', type: 'POST',
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);
redirectToPlaylist(apiClient, id); redirectToPlaylist(apiClient, id);
@ -49,7 +64,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
} }
function addToPlaylist(apiClient, dlg, id) { function addToPlaylist(apiClient, dlg, id) {
var itemIds = dlg.querySelector('.fldSelectedItemIds').value || ''; const itemIds = dlg.querySelector('.fldSelectedItemIds').value || '';
if (id === 'queue') { if (id === 'queue') {
playbackManager.queue({ playbackManager.queue({
@ -63,7 +78,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
loading.show(); loading.show();
var url = apiClient.getUrl('Playlists/' + id + '/Items', { const url = apiClient.getUrl(`Playlists/${id}/Items`, {
Ids: itemIds, Ids: itemIds,
userId: apiClient.getCurrentUserId() userId: apiClient.getCurrentUserId()
}); });
@ -72,7 +87,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
type: 'POST', type: 'POST',
url: url url: url
}).then(function () { }).then(() => {
loading.hide(); loading.hide();
dlg.submitted = true; dlg.submitted = true;
@ -85,36 +100,36 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
} }
function populatePlaylists(editorOptions, panel) { function populatePlaylists(editorOptions, panel) {
var select = panel.querySelector('#selectPlaylistToAddTo'); const select = panel.querySelector('#selectPlaylistToAddTo');
loading.hide(); loading.hide();
panel.querySelector('.newPlaylistInfo').classList.add('hide'); panel.querySelector('.newPlaylistInfo').classList.add('hide');
var options = { const options = {
Recursive: true, Recursive: true,
IncludeItemTypes: 'Playlist', IncludeItemTypes: 'Playlist',
SortBy: 'SortName', SortBy: 'SortName',
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 => {
var html = ''; let html = '';
if (editorOptions.enableAddToPlayQueue !== false && playbackManager.isPlaying()) { if (editorOptions.enableAddToPlayQueue !== false && playbackManager.isPlaying()) {
html += '<option value="queue">' + globalize.translate('AddToPlayQueue') + '</option>'; html += `<option value="queue">${globalize.translate('AddToPlayQueue')}</option>`;
} }
html += '<option value="">' + globalize.translate('OptionNew') + '</option>'; html += `<option value="">${globalize.translate('OptionNew')}</option>`;
html += result.Items.map(function (i) { html += result.Items.map(i => {
return '<option value="' + i.Id + '">' + i.Name + '</option>'; return `<option value="${i.Id}">${i.Name}</option>`;
}); });
select.innerHTML = html; select.innerHTML = html;
var defaultValue = editorOptions.defaultValue; let defaultValue = editorOptions.defaultValue;
if (!defaultValue) { if (!defaultValue) {
defaultValue = userSettings.get('playlisteditor-lastplaylistid') || ''; defaultValue = userSettings.get('playlisteditor-lastplaylistid') || '';
} }
@ -132,29 +147,29 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
} }
function getEditorHtml(items) { function getEditorHtml(items) {
var html = ''; let 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">';
html += '<form style="margin:auto;">'; html += '<form style="margin:auto;">';
html += '<div class="fldSelectPlaylist selectContainer">'; html += '<div class="fldSelectPlaylist selectContainer">';
var autoFocus = items.length ? ' autofocus' : ''; let autoFocus = items.length ? ' autofocus' : '';
html += '<select is="emby-select" id="selectPlaylistToAddTo" label="' + globalize.translate('LabelPlaylist') + '"' + autoFocus + '></select>'; html += `<select is="emby-select" id="selectPlaylistToAddTo" label="${globalize.translate('LabelPlaylist')}"${autoFocus}></select>`;
html += '</div>'; html += '</div>';
html += '<div class="newPlaylistInfo">'; html += '<div class="newPlaylistInfo">';
html += '<div class="inputContainer">'; html += '<div class="inputContainer">';
autoFocus = items.length ? '' : ' autofocus'; autoFocus = items.length ? '' : ' autofocus';
html += '<input is="emby-input" type="text" id="txtNewPlaylistName" required="required" label="' + globalize.translate('LabelName') + '"' + autoFocus + ' />'; html += `<input is="emby-input" type="text" id="txtNewPlaylistName" required="required" label="${globalize.translate('LabelName')}"${autoFocus} />`;
html += '</div>'; html += '</div>';
// newPlaylistInfo // newPlaylistInfo
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('Add') + '</button>'; html += `<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">${globalize.translate('Add')}</button>`;
html += '</div>'; html += '</div>';
html += '<input type="hidden" class="fldSelectedItemIds" />'; html += '<input type="hidden" class="fldSelectedItemIds" />';
@ -187,7 +202,7 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
} else { } else {
content.querySelector('.fldSelectPlaylist').classList.add('hide'); content.querySelector('.fldSelectPlaylist').classList.add('hide');
var selectPlaylistToAddTo = content.querySelector('#selectPlaylistToAddTo'); const selectPlaylistToAddTo = content.querySelector('#selectPlaylistToAddTo');
selectPlaylistToAddTo.innerHTML = ''; selectPlaylistToAddTo.innerHTML = '';
selectPlaylistToAddTo.value = ''; selectPlaylistToAddTo.value = '';
triggerChange(selectPlaylistToAddTo); triggerChange(selectPlaylistToAddTo);
@ -195,72 +210,70 @@ define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackMan
} }
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 PlaylistEditor() { export class showEditor {
constructor(options) {
const items = options.items || {};
currentServerId = options.serverId;
const dialogOptions = {
removeOnClose: true,
scrollY: false
};
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
const dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
let html = '';
const title = globalize.translate('HeaderAddToPlaylist');
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(items);
dlg.innerHTML = html;
initEditor(dlg, options, items);
dlg.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
return dialogHelper.open(dlg).then(() => {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (dlg.submitted) {
return Promise.resolve();
}
return Promise.reject();
});
}
} }
PlaylistEditor.prototype.show = function (options) { /* eslint-enable indent */
var items = options.items || {}; export default showEditor;
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 = globalize.translate('HeaderAddToPlaylist');
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(items);
dlg.innerHTML = html;
initEditor(dlg, options, 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) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (dlg.submitted) {
return Promise.resolve();
}
return Promise.reject();
});
};
return PlaylistEditor;
});

View file

@ -2,12 +2,12 @@
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"> <button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1">
<span class="material-icons arrow_back"></span> <span class="material-icons arrow_back"></span>
</button> </button>
<h3 class="formDialogHeaderTitle"></h3> <h3 class="formDialogHeaderTitle"></h3>
</div> </div>
<div class="formDialogContent smoothScrollY"> <div class="formDialogContent smoothScrollY">
<div class="dialogContentInner dialog-content-centered" style="padding-top:2em;"> <div class="dialogContentInner dialog-content-centered" style="padding-top:2em;">
<form> <form>
<div class="inputContainer"> <div class="inputContainer">
<input is="emby-input" type="text" id="txtInput" label="" /> <input is="emby-input" type="text" id="txtInput" label="" />
@ -19,7 +19,6 @@
<span class="submitText"></span> <span class="submitText"></span>
</button> </button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>

View file

@ -196,7 +196,7 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
context.querySelector('.nowPlayingPageImage').classList.remove('nowPlayingPageImageAudio'); context.querySelector('.nowPlayingPageImage').classList.remove('nowPlayingPageImageAudio');
} }
} else { } else {
imgContainer.innerHTML = '<div class="nowPlayingPageImageContainerNoAlbum"><button data-action="link" class="cardContent-button cardImageContainer coveredImage ' + cardBuilder.getDefaultBackgroundClass(item.Name) + ' cardContent cardContent-shadow itemAction"><span class="cardImageIcon material-icons album"></span></button></div>'; imgContainer.innerHTML = '<div class="nowPlayingPageImageContainerNoAlbum"><button data-action="link" class="cardImageContainer coveredImage ' + cardBuilder.getDefaultBackgroundClass(item.Name) + ' cardContent cardContent-shadow itemAction"><span class="cardImageIcon material-icons album"></span></button></div>';
} }
} }
@ -589,7 +589,7 @@ define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageL
require(['playlistEditor'], function (playlistEditor) { require(['playlistEditor'], function (playlistEditor) {
getSaveablePlaylistItems().then(function (items) { getSaveablePlaylistItems().then(function (items) {
var serverId = items.length ? items[0].ServerId : ApiClient.serverId(); var serverId = items.length ? items[0].ServerId : ApiClient.serverId();
new playlistEditor().show({ new playlistEditor.showEditor({
items: items.map(function (i) { items: items.map(function (i) {
return i.Id; return i.Id;
}), }),

View file

@ -1,158 +0,0 @@
define(['loading', 'events', 'dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (loading, events, dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
'use strict';
var currentApiClient;
var currentDlg;
var currentInstance;
function reloadPageWhenServerAvailable(retryCount) {
var apiClient = currentApiClient;
if (!apiClient) {
return;
}
// Don't use apiclient method because we don't want it reporting authentication under the old version
apiClient.getJSON(apiClient.getUrl('System/Info')).then(function (info) {
// If this is back to false, the restart completed
if (!info.IsShuttingDown) {
currentInstance.restarted = true;
dialogHelper.close(currentDlg);
} else {
retryReload(retryCount);
}
}, function () {
retryReload(retryCount);
});
}
function retryReload(retryCount) {
setTimeout(function () {
retryCount = retryCount || 0;
retryCount++;
if (retryCount < 150) {
reloadPageWhenServerAvailable(retryCount);
}
}, 500);
}
function startRestart(instance, apiClient, dlg) {
currentApiClient = apiClient;
currentDlg = dlg;
currentInstance = instance;
apiClient.restartServer().then(function () {
setTimeout(reloadPageWhenServerAvailable, 250);
});
}
function showDialog(instance, options, template) {
var dialogOptions = {
removeOnClose: true,
scrollY: false
};
var enableTvLayout = layoutManager.tv;
if (enableTvLayout) {
dialogOptions.size = 'fullscreen';
}
var dlg = dialogHelper.createDialog(dialogOptions);
var configuredButtons = [];
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateHtml(template, 'core');
dlg.classList.add('align-items-center');
dlg.classList.add('justify-items-center');
var formDialogContent = dlg.querySelector('.formDialogContent');
formDialogContent.style['flex-grow'] = 'initial';
if (enableTvLayout) {
formDialogContent.style['max-width'] = '50%';
formDialogContent.style['max-height'] = '60%';
scrollHelper.centerFocus.on(formDialogContent, false);
} else {
formDialogContent.style.maxWidth = (Math.min((configuredButtons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)) + 'px';
dlg.classList.add('dialog-fullscreen-lowres');
}
dlg.querySelector('.formDialogHeaderTitle').innerHTML = globalize.translate('HeaderRestartingServer');
dlg.querySelector('.text').innerHTML = globalize.translate('RestartPleaseWaitMessage');
var i;
var length;
var html = '';
for (i = 0, length = configuredButtons.length; i < length; i++) {
var item = configuredButtons[i];
var autoFocus = i === 0 ? ' autofocus' : '';
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
if (item.type) {
buttonClass += ' button-' + item.type;
}
html += '<button is="emby-button" type="button" class="' + buttonClass + '" data-id="' + item.id + '"' + autoFocus + '>' + item.name + '</button>';
}
dlg.querySelector('.formDialogFooter').innerHTML = html;
function onButtonClick() {
dialogHelper.close(dlg);
}
var buttons = dlg.querySelectorAll('.btnOption');
for (i = 0, length = buttons.length; i < length; i++) {
buttons[i].addEventListener('click', onButtonClick);
}
var dlgPromise = dialogHelper.open(dlg);
startRestart(instance, options.apiClient, dlg);
return dlgPromise.then(function () {
if (enableTvLayout) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
}
instance.destroy();
loading.hide();
if (instance.restarted) {
events.trigger(instance, 'restarted');
}
});
}
function ServerRestartDialog(options) {
this.options = options;
}
ServerRestartDialog.prototype.show = function () {
var instance = this;
loading.show();
return new Promise(function (resolve, reject) {
require(['text!./../dialog/dialog.template.html'], function (template) {
showDialog(instance, instance.options, template).then(resolve, reject);
});
});
};
ServerRestartDialog.prototype.destroy = function () {
currentApiClient = null;
currentDlg = null;
currentInstance = null;
this.options = null;
};
return ServerRestartDialog;
});

View file

@ -1,18 +1,30 @@
define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'globalize', 'loading', 'dom', 'recordingHelper'], function (playbackManager, inputManager, connectionManager, appRouter, globalize, loading, dom, recordingHelper) { /* eslint-disable indent */
'use strict';
/**
* Module shortcuts.
* @module components/shortcuts
*/
import playbackManager from 'playbackManager';
import inputManager from 'inputManager';
import connectionManager from 'connectionManager';
import appRouter from 'appRouter';
import globalize from 'globalize';
import dom from 'dom';
import recordingHelper from 'recordingHelper';
function playAllFromHere(card, serverId, queue) { function playAllFromHere(card, serverId, queue) {
var parent = card.parentNode; const parent = card.parentNode;
var className = card.classList.length ? ('.' + card.classList[0]) : ''; const className = card.classList.length ? (`.${card.classList[0]}`) : '';
var cards = parent.querySelectorAll(className + '[data-id]'); const cards = parent.querySelectorAll(`${className}[data-id]`);
var ids = []; const ids = [];
var foundCard = false; let foundCard = false;
var startIndex; let startIndex;
for (var i = 0, length = cards.length; i < length; i++) { for (let i = 0, length = cards.length; i < length; i++) {
if (cards[i] === card) { if (cards[i] === card) {
foundCard = true; foundCard = true;
startIndex = i; startIndex = i;
@ -22,12 +34,12 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
} }
} }
var itemsContainer = dom.parentWithClass(card, 'itemsContainer'); const itemsContainer = dom.parentWithClass(card, 'itemsContainer');
if (itemsContainer && itemsContainer.fetchData) { if (itemsContainer && itemsContainer.fetchData) {
var queryOptions = queue ? { StartIndex: startIndex } : {}; const queryOptions = queue ? { StartIndex: startIndex } : {};
return itemsContainer.fetchData(queryOptions).then(function (result) { return itemsContainer.fetchData(queryOptions).then(result => {
if (queue) { if (queue) {
return playbackManager.queue({ return playbackManager.queue({
@ -64,7 +76,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function showProgramDialog(item) { function showProgramDialog(item) {
require(['recordingCreator'], function (recordingCreator) { import('recordingCreator').then(({default:recordingCreator}) => {
recordingCreator.show(item.Id, item.ServerId); recordingCreator.show(item.Id, item.ServerId);
}); });
@ -73,11 +85,11 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function getItem(button) { function getItem(button) {
button = dom.parentWithAttribute(button, 'data-id'); button = dom.parentWithAttribute(button, 'data-id');
var serverId = button.getAttribute('data-serverid'); const serverId = button.getAttribute('data-serverid');
var id = button.getAttribute('data-id'); const id = button.getAttribute('data-id');
var type = button.getAttribute('data-type'); const type = button.getAttribute('data-type');
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
if (type === 'Timer') { if (type === 'Timer') {
return apiClient.getLiveTvTimer(id); return apiClient.getLiveTvTimer(id);
@ -99,19 +111,19 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function showContextMenu(card, options) { function showContextMenu(card, options) {
getItem(card).then(function (item) { getItem(card).then(item => {
var playlistId = card.getAttribute('data-playlistid'); const playlistId = card.getAttribute('data-playlistid');
var collectionId = card.getAttribute('data-collectionid'); const collectionId = card.getAttribute('data-collectionid');
if (playlistId) { if (playlistId) {
var elem = dom.parentWithAttribute(card, 'data-playlistitemid'); const elem = dom.parentWithAttribute(card, 'data-playlistitemid');
item.PlaylistItemId = elem ? elem.getAttribute('data-playlistitemid') : null; item.PlaylistItemId = elem ? elem.getAttribute('data-playlistitemid') : null;
} }
require(['itemContextMenu'], function (itemContextMenu) { import('itemContextMenu').then(({default: itemContextMenu}) => {
connectionManager.getApiClient(item.ServerId).getCurrentUser().then(function (user) { connectionManager.getApiClient(item.ServerId).getCurrentUser().then(user => {
itemContextMenu.show(Object.assign({ itemContextMenu.show(Object.assign({
item: item, item: item,
play: true, play: true,
@ -122,9 +134,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
collectionId: collectionId, collectionId: collectionId,
user: user user: user
}, options || {})).then(function (result) { }, options || {})).then(result => {
var itemsContainer;
if (result.command === 'playallfromhere' || result.command === 'queueallfromhere') { if (result.command === 'playallfromhere' || result.command === 'queueallfromhere') {
executeAction(card, options.positionTo, result.command); executeAction(card, options.positionTo, result.command);
@ -157,9 +167,9 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function showPlayMenu(card, target) { function showPlayMenu(card, target) {
var item = getItemInfoFromCard(card); const item = getItemInfoFromCard(card);
require(['playMenu'], function (playMenu) { import('playMenu').then(({default: playMenu}) => {
playMenu.show({ playMenu.show({
@ -170,7 +180,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
} }
function sendToast(text) { function sendToast(text) {
require(['toast'], function (toast) { import('toast').then(({default: toast}) => {
toast(text); toast(text);
}); });
} }
@ -179,19 +189,19 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
target = target || card; target = target || card;
var id = card.getAttribute('data-id'); let id = card.getAttribute('data-id');
if (!id) { if (!id) {
card = dom.parentWithAttribute(card, 'data-id'); card = dom.parentWithAttribute(card, 'data-id');
id = card.getAttribute('data-id'); id = card.getAttribute('data-id');
} }
var item = getItemInfoFromCard(card); const item = getItemInfoFromCard(card);
var serverId = item.ServerId; const serverId = item.ServerId;
var type = item.Type; const type = item.Type;
var playableItemId = type === 'Program' ? item.ChannelId : item.Id; const playableItemId = type === 'Program' ? item.ChannelId : item.Id;
if (item.MediaType === 'Photo' && action === 'link') { if (item.MediaType === 'Photo' && action === 'link') {
action = 'play'; action = 'play';
@ -213,7 +223,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
}); });
} else if (action === 'play' || action === 'resume') { } else if (action === 'play' || action === 'resume') {
var startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0'); const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0');
playbackManager.play({ playbackManager.play({
ids: [playableItemId], ids: [playableItemId],
@ -244,7 +254,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
onRecordCommand(serverId, id, type, card.getAttribute('data-timerid'), card.getAttribute('data-seriestimerid')); onRecordCommand(serverId, id, type, card.getAttribute('data-timerid'), card.getAttribute('data-seriestimerid'));
} else if (action === 'menu') { } else if (action === 'menu') {
var options = target.getAttribute('data-playoptions') === 'false' ? const options = target.getAttribute('data-playoptions') === 'false' ?
{ {
shuffle: false, shuffle: false,
instantMix: false, instantMix: false,
@ -261,7 +271,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
} else if (action === 'playmenu') { } else if (action === 'playmenu') {
showPlayMenu(card, target); showPlayMenu(card, target);
} else if (action === 'edit') { } else if (action === 'edit') {
getItem(target).then(function (item) { getItem(target).then(item => {
editItem(item, serverId); editItem(item, serverId);
}); });
} else if (action === 'playtrailer') { } else if (action === 'playtrailer') {
@ -270,9 +280,9 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
getItem(target).then(addToPlaylist); getItem(target).then(addToPlaylist);
} else if (action === 'custom') { } else if (action === 'custom') {
var customAction = target.getAttribute('data-customaction'); const customAction = target.getAttribute('data-customaction');
card.dispatchEvent(new CustomEvent('action-' + customAction, { card.dispatchEvent(new CustomEvent(`action-${customAction}`, {
detail: { detail: {
playlistItemId: card.getAttribute('data-playlistitemid') playlistItemId: card.getAttribute('data-playlistitemid')
}, },
@ -283,7 +293,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
} }
function addToPlaylist(item) { function addToPlaylist(item) {
require(['playlistEditor'], function (playlistEditor) { import('playlistEditor').then(({default: playlistEditor}) => {
new playlistEditor().show({ new playlistEditor().show({
items: [item.Id], items: [item.Id],
@ -295,35 +305,35 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function playTrailer(item) { function playTrailer(item) {
var apiClient = connectionManager.getApiClient(item.ServerId); const apiClient = connectionManager.getApiClient(item.ServerId);
apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(function (trailers) { apiClient.getLocalTrailers(apiClient.getCurrentUserId(), item.Id).then(trailers => {
playbackManager.play({ items: trailers }); playbackManager.play({ items: trailers });
}); });
} }
function editItem(item, serverId) { function editItem(item, serverId) {
var apiClient = connectionManager.getApiClient(serverId); const apiClient = connectionManager.getApiClient(serverId);
return new Promise(function (resolve, reject) { return new Promise((resolve, reject) => {
var serverId = apiClient.serverInfo().Id; const serverId = apiClient.serverInfo().Id;
if (item.Type === 'Timer') { if (item.Type === 'Timer') {
if (item.ProgramId) { if (item.ProgramId) {
require(['recordingCreator'], function (recordingCreator) { import('recordingCreator').then(({default: recordingCreator}) => {
recordingCreator.show(item.ProgramId, serverId).then(resolve, reject); recordingCreator.show(item.ProgramId, serverId).then(resolve, reject);
}); });
} else { } else {
require(['recordingEditor'], function (recordingEditor) { import('recordingEditor').then(({default: recordingEditor}) => {
recordingEditor.show(item.Id, serverId).then(resolve, reject); recordingEditor.show(item.Id, serverId).then(resolve, reject);
}); });
} }
} else { } else {
require(['metadataEditor'], function (metadataEditor) { import('metadataEditor').then(({default: metadataEditor}) => {
metadataEditor.show(item.Id, serverId).then(resolve, reject); metadataEditor.show(item.Id, serverId).then(resolve, reject);
}); });
@ -335,19 +345,19 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
if (type === 'Program' || timerId || seriesTimerId) { if (type === 'Program' || timerId || seriesTimerId) {
var programId = type === 'Program' ? id : null; const programId = type === 'Program' ? id : null;
recordingHelper.toggleRecording(serverId, programId, timerId, seriesTimerId); recordingHelper.toggleRecording(serverId, programId, timerId, seriesTimerId);
} }
} }
function onClick(e) { export function onClick(e) {
var card = dom.parentWithClass(e.target, 'itemAction'); const card = dom.parentWithClass(e.target, 'itemAction');
if (card) { if (card) {
var actionElement = card; let actionElement = card;
var action = actionElement.getAttribute('data-action'); let action = actionElement.getAttribute('data-action');
if (!action) { if (!action) {
actionElement = dom.parentWithAttribute(actionElement, 'data-action'); actionElement = dom.parentWithAttribute(actionElement, 'data-action');
@ -368,12 +378,12 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
function onCommand(e) { function onCommand(e) {
var cmd = e.detail.command; const cmd = e.detail.command;
if (cmd === 'play' || cmd === 'resume' || cmd === 'record' || cmd === 'menu' || cmd === 'info') { if (cmd === 'play' || cmd === 'resume' || cmd === 'record' || cmd === 'menu' || cmd === 'info') {
var target = e.target; const target = e.target;
var card = dom.parentWithClass(target, 'itemAction') || dom.parentWithAttribute(target, 'data-id'); const card = dom.parentWithClass(target, 'itemAction') || dom.parentWithAttribute(target, 'data-id');
if (card) { if (card) {
e.preventDefault(); e.preventDefault();
@ -383,7 +393,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
} }
} }
function on(context, options) { export function on(context, options) {
options = options || {}; options = options || {};
@ -396,7 +406,7 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
} }
} }
function off(context, options) { export function off(context, options) {
options = options || {}; options = options || {};
context.removeEventListener('click', onClick); context.removeEventListener('click', onClick);
@ -406,23 +416,24 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl
} }
} }
function getShortcutAttributesHtml(item, serverId) { export function getShortcutAttributesHtml(item, serverId) {
var html = 'data-id="' + item.Id + '" data-serverid="' + (serverId || item.ServerId) + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-channelid="' + item.ChannelId + '" data-isfolder="' + item.IsFolder + '"'; let html = `data-id="${item.Id}" data-serverid="${serverId || item.ServerId}" data-type="${item.Type}" data-mediatype="${item.MediaType}" data-channelid="${item.ChannelId}" data-isfolder="${item.IsFolder}"`;
var collectionType = item.CollectionType; const collectionType = item.CollectionType;
if (collectionType) { if (collectionType) {
html += ' data-collectiontype="' + collectionType + '"'; html += ` data-collectiontype="${collectionType}"`;
} }
return html; return html;
} }
return { /* eslint-enable indent */
on: on,
off: off, export default {
onClick: onClick, on: on,
getShortcutAttributesHtml: getShortcutAttributesHtml off: off,
}; onClick: onClick,
getShortcutAttributesHtml: getShortcutAttributesHtml
};
});

View file

@ -2,9 +2,20 @@
* Image viewer component * Image viewer component
* @module components/slideshow/slideshow * @module components/slideshow/slideshow
*/ */
define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'browser', 'apphost', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (dialogHelper, inputManager, connectionManager, layoutManager, focusManager, browser, appHost) { define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'browser', 'apphost', 'dom', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (dialogHelper, inputManager, connectionManager, layoutManager, focusManager, browser, appHost, dom) {
'use strict'; 'use strict';
/**
* Name of transition event.
*/
const transitionEndEventName = dom.whichTransitionEvent();
/**
* Flag to use fake image to fix blurry zoomed image.
* At least WebKit doesn't restore quality for zoomed images.
*/
const useFakeZoomImage = browser.safari;
/** /**
* Retrieves an item's image URL from the API. * Retrieves an item's image URL from the API.
* @param {object|string} item - Item used to generate the image URL. * @param {object|string} item - Item used to generate the image URL.
@ -240,6 +251,41 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
} }
} }
/**
* Handles zoom changes.
*/
function onZoomChange(scale, imageEl, slideEl) {
const zoomImage = slideEl.querySelector('.swiper-zoom-fakeimg');
if (zoomImage) {
zoomImage.style.width = zoomImage.style.height = scale * 100 + '%';
if (scale > 1) {
if (zoomImage.classList.contains('swiper-zoom-fakeimg-hidden')) {
// Await for Swiper style changes
setTimeout(() => {
const callback = () => {
imageEl.removeEventListener(transitionEndEventName, callback);
zoomImage.classList.remove('swiper-zoom-fakeimg-hidden');
};
// Swiper set 'transition-duration: 300ms' for auto zoom
// and 'transition-duration: 0s' for touch zoom
const transitionDuration = parseFloat(imageEl.style.transitionDuration.replace(/[a-z]/i, ''));
if (transitionDuration > 0) {
imageEl.addEventListener(transitionEndEventName, callback);
} else {
callback();
}
}, 0);
}
} else {
zoomImage.classList.add('swiper-zoom-fakeimg-hidden');
}
}
}
/** /**
* Initializes the Swiper instance and binds the relevant events. * Initializes the Swiper instance and binds the relevant events.
* @param {HTMLElement} dialog - Element containing the dialog. * @param {HTMLElement} dialog - Element containing the dialog.
@ -260,8 +306,7 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
loop: false, loop: false,
zoom: { zoom: {
minRatio: 1, minRatio: 1,
toggle: true, toggle: true
containerClass: 'slider-zoom-container'
}, },
autoplay: !options.interactive, autoplay: !options.interactive,
keyboard: { keyboard: {
@ -288,6 +333,10 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
swiperInstance.on('autoplayStart', onAutoplayStart); swiperInstance.on('autoplayStart', onAutoplayStart);
swiperInstance.on('autoplayStop', onAutoplayStop); swiperInstance.on('autoplayStop', onAutoplayStop);
if (useFakeZoomImage) {
swiperInstance.on('zoomChange', onZoomChange);
}
}); });
} }
@ -328,7 +377,10 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
function getSwiperSlideHtmlFromSlide(item) { function getSwiperSlideHtmlFromSlide(item) {
var html = ''; var html = '';
html += '<div class="swiper-slide" data-original="' + item.originalImage + '" data-itemid="' + item.Id + '" data-serverid="' + item.ServerId + '">'; html += '<div class="swiper-slide" data-original="' + item.originalImage + '" data-itemid="' + item.Id + '" data-serverid="' + item.ServerId + '">';
html += '<div class="slider-zoom-container">'; html += '<div class="swiper-zoom-container">';
if (useFakeZoomImage) {
html += `<div class="swiper-zoom-fakeimg swiper-zoom-fakeimg-hidden" style="background-image: url('${item.originalImage}')"></div>`;
}
html += '<img src="' + item.originalImage + '" class="swiper-slide-img">'; html += '<img src="' + item.originalImage + '" class="swiper-slide-img">';
html += '</div>'; html += '</div>';
if (item.title || item.subtitle) { if (item.title || item.subtitle) {

View file

@ -40,16 +40,6 @@
text-shadow: 3px 3px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; text-shadow: 3px 3px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
} }
.swiper-slide-img {
max-height: 100%;
max-width: 100%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
margin: auto;
}
.slideshowButtonIcon { .slideshowButtonIcon {
color: #fff; color: #fff;
opacity: 0.7; opacity: 0.7;
@ -135,13 +125,18 @@
color: #ccc; color: #ccc;
} }
.swiper-slide { .swiper-zoom-fakeimg {
display: flex; position: absolute;
flex-direction: column; top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: contain;
z-index: 1;
pointer-events: none;
} }
.slider-zoom-container { .swiper-zoom-fakeimg-hidden {
margin: auto; display: none;
max-height: 100%;
max-width: 100%;
} }

View file

@ -1,6 +1,6 @@
/** /**
* Module that manages the SyncPlay feature. * Module that manages the SyncPlay feature.
* @module components/syncplay/syncPlayManager * @module components/syncPlay/syncPlayManager
*/ */
import events from 'events'; import events from 'events';

View file

@ -1,6 +1,6 @@
/** /**
* Module that manages time syncing with server. * Module that manages time syncing with server.
* @module components/syncplay/timeSyncManager * @module components/syncPlay/timeSyncManager
*/ */
import events from 'events'; import events from 'events';
@ -65,8 +65,6 @@ class TimeSyncManager {
this.pings = 0; // number of pings this.pings = 0; // number of pings
this.measurement = null; // current time sync this.measurement = null; // current time sync
this.measurements = []; this.measurements = [];
this.startPing();
} }
/** /**

View file

@ -43,10 +43,6 @@ define(['browser', 'dom', 'layoutManager', 'css!components/viewManager/viewConta
var newView = newViewInfo.elem; var newView = newViewInfo.elem;
var modulesToLoad = []; var modulesToLoad = [];
if (isPluginpage) {
modulesToLoad.push('legacyDashboard');
}
if (newViewInfo.hasjQuerySelect) { if (newViewInfo.hasjQuerySelect) {
modulesToLoad.push('legacySelectMenu'); modulesToLoad.push('legacySelectMenu');
} }

View file

@ -21,10 +21,11 @@ define(['viewContainer', 'focusManager', 'queryString', 'layoutManager'], functi
if (!newView.initComplete) { if (!newView.initComplete) {
newView.initComplete = true; newView.initComplete = true;
var controller;
if (typeof options.controllerFactory === 'function') { if (typeof options.controllerFactory === 'function') {
controller = new options.controllerFactory(newView, eventDetail.detail.params);
// Use controller method } else if (options.controllerFactory && typeof options.controllerFactory.default === 'function') {
var controller = new options.controllerFactory(newView, eventDetail.detail.params); controller = new options.controllerFactory.default(newView, eventDetail.detail.params);
} }
if (!options.controllerFactory || dispatchPageEvents) { if (!options.controllerFactory || dispatchPageEvents) {

View file

@ -57,7 +57,7 @@ define(['require', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'conne
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
require(['text!./viewsettings.template.html'], function (template) { require(['text!./viewSettings.template.html'], function (template) {
var dialogOptions = { var dialogOptions = {
removeOnClose: true, removeOnClose: true,

1
src/config.json Symbolic link
View file

@ -0,0 +1 @@
config.template.json

View file

@ -1,3 +1,3 @@
{ {
"multiserver": true "multiserver": false
} }

View file

@ -252,12 +252,6 @@ define(['datetime', 'events', 'itemHelper', 'serverNotifications', 'dom', 'globa
html += '</div>'; html += '</div>';
html += '</div>'; html += '</div>';
if (session.TranscodingInfo && session.TranscodingInfo.Framerate) {
html += '<div class="sessionTranscodingFramerate">' + session.TranscodingInfo.Framerate + ' fps</div>';
} else {
html += '<div class="sessionTranscodingFramerate"></div>';
}
html += '<div class="sessionNowPlayingDetails">'; html += '<div class="sessionNowPlayingDetails">';
var nowPlayingName = DashboardPage.getNowPlayingName(session); var nowPlayingName = DashboardPage.getNowPlayingName(session);
html += '<div class="sessionNowPlayingInfo" data-imgsrc="' + nowPlayingName.image + '">'; html += '<div class="sessionNowPlayingInfo" data-imgsrc="' + nowPlayingName.image + '">';
@ -573,7 +567,6 @@ define(['datetime', 'events', 'itemHelper', 'serverNotifications', 'dom', 'globa
row.querySelector('.sessionNowPlayingTime').innerHTML = DashboardPage.getSessionNowPlayingTime(session); row.querySelector('.sessionNowPlayingTime').innerHTML = DashboardPage.getSessionNowPlayingTime(session);
row.querySelector('.sessionUserName').innerHTML = DashboardPage.getUsersHtml(session); row.querySelector('.sessionUserName').innerHTML = DashboardPage.getUsersHtml(session);
row.querySelector('.sessionAppSecondaryText').innerHTML = DashboardPage.getAppSecondaryText(session); row.querySelector('.sessionAppSecondaryText').innerHTML = DashboardPage.getAppSecondaryText(session);
row.querySelector('.sessionTranscodingFramerate').innerHTML = session.TranscodingInfo && session.TranscodingInfo.Framerate ? session.TranscodingInfo.Framerate + ' fps' : '';
var nowPlayingName = DashboardPage.getNowPlayingName(session); var nowPlayingName = DashboardPage.getNowPlayingName(session);
var nowPlayingInfoElem = row.querySelector('.sessionNowPlayingInfo'); var nowPlayingInfoElem = row.querySelector('.sessionNowPlayingInfo');

View file

@ -23,8 +23,8 @@ define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-in
$('.chkMediaType', page).each(function () { $('.chkMediaType', page).each(function () {
this.checked = -1 != (profile.SupportedMediaTypes || '').split(',').indexOf(this.getAttribute('data-value')); this.checked = -1 != (profile.SupportedMediaTypes || '').split(',').indexOf(this.getAttribute('data-value'));
}); });
$('#chkEnableAlbumArtInDidl', page).checked = profile.EnableAlbumArtInDidl; $('#chkEnableAlbumArtInDidl', page).prop('checked', profile.EnableAlbumArtInDidl);
$('#chkEnableSingleImageLimit', page).checked = profile.EnableSingleAlbumArtLimit; $('#chkEnableSingleImageLimit', page).prop('checked', profile.EnableSingleAlbumArtLimit);
renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []); renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []);
var idInfo = profile.Identification || {}; var idInfo = profile.Identification || {};
renderIdentificationHeaders(page, idInfo.Headers || []); renderIdentificationHeaders(page, idInfo.Headers || []);
@ -51,11 +51,11 @@ define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-in
$('#txtAlbumArtMaxHeight', page).val(profile.MaxAlbumArtHeight || ''); $('#txtAlbumArtMaxHeight', page).val(profile.MaxAlbumArtHeight || '');
$('#txtIconMaxWidth', page).val(profile.MaxIconWidth || ''); $('#txtIconMaxWidth', page).val(profile.MaxIconWidth || '');
$('#txtIconMaxHeight', page).val(profile.MaxIconHeight || ''); $('#txtIconMaxHeight', page).val(profile.MaxIconHeight || '');
$('#chkIgnoreTranscodeByteRangeRequests', page).checked = profile.IgnoreTranscodeByteRangeRequests; $('#chkIgnoreTranscodeByteRangeRequests', page).prop('checked', profile.IgnoreTranscodeByteRangeRequests);
$('#txtMaxAllowedBitrate', page).val(profile.MaxStreamingBitrate || ''); $('#txtMaxAllowedBitrate', page).val(profile.MaxStreamingBitrate || '');
$('#txtMusicStreamingTranscodingBitrate', page).val(profile.MusicStreamingTranscodingBitrate || ''); $('#txtMusicStreamingTranscodingBitrate', page).val(profile.MusicStreamingTranscodingBitrate || '');
$('#chkRequiresPlainFolders', page).checked = profile.RequiresPlainFolders; $('#chkRequiresPlainFolders', page).prop('checked', profile.RequiresPlainFolders);
$('#chkRequiresPlainVideoItems', page).checked = profile.RequiresPlainVideoItems; $('#chkRequiresPlainVideoItems', page).prop('checked', profile.RequiresPlainVideoItems);
$('#txtProtocolInfo', page).val(profile.ProtocolInfo || ''); $('#txtProtocolInfo', page).val(profile.ProtocolInfo || '');
$('#txtXDlnaCap', page).val(profile.XDlnaCap || ''); $('#txtXDlnaCap', page).val(profile.XDlnaCap || '');
$('#txtXDlnaDoc', page).val(profile.XDlnaDoc || ''); $('#txtXDlnaDoc', page).val(profile.XDlnaDoc || '');
@ -357,9 +357,9 @@ define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-in
$('#txtTranscodingAudioCodec', popup).val(transcodingProfile.AudioCodec || ''); $('#txtTranscodingAudioCodec', popup).val(transcodingProfile.AudioCodec || '');
$('#txtTranscodingVideoCodec', popup).val(transcodingProfile.VideoCodec || ''); $('#txtTranscodingVideoCodec', popup).val(transcodingProfile.VideoCodec || '');
$('#selectTranscodingProtocol', popup).val(transcodingProfile.Protocol || 'Http'); $('#selectTranscodingProtocol', popup).val(transcodingProfile.Protocol || 'Http');
$('#chkEnableMpegtsM2TsMode', popup).checked = transcodingProfile.EnableMpegtsM2TsMode || false; $('#chkEnableMpegtsM2TsMode', popup).prop('checked', transcodingProfile.EnableMpegtsM2TsMode || false);
$('#chkEstimateContentLength', popup).checked = transcodingProfile.EstimateContentLength || false; $('#chkEstimateContentLength', popup).prop('checked', transcodingProfile.EstimateContentLength || false);
$('#chkReportByteRangeRequests', popup).checked = 'Bytes' == transcodingProfile.TranscodeSeekInfo; $('#chkReportByteRangeRequests', popup).prop('checked', 'Bytes' == transcodingProfile.TranscodeSeekInfo);
$('.radioTabButton:first', popup).trigger('click'); $('.radioTabButton:first', popup).trigger('click');
openPopup(popup[0]); openPopup(popup[0]);
} }
@ -376,9 +376,9 @@ define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-in
currentSubProfile.VideoCodec = $('#txtTranscodingVideoCodec', page).val(); currentSubProfile.VideoCodec = $('#txtTranscodingVideoCodec', page).val();
currentSubProfile.Protocol = $('#selectTranscodingProtocol', page).val(); currentSubProfile.Protocol = $('#selectTranscodingProtocol', page).val();
currentSubProfile.Context = 'Streaming'; currentSubProfile.Context = 'Streaming';
currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).checked; currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).is(':checked');
currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked; currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).is(':checked');
currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).checked ? 'Bytes' : 'Auto'; currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).is(':checked') ? 'Bytes' : 'Auto';
if (isSubProfileNew) { if (isSubProfileNew) {
currentProfile.TranscodingProfiles.push(currentSubProfile); currentProfile.TranscodingProfiles.push(currentSubProfile);
@ -647,8 +647,8 @@ define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-in
function updateProfile(page, profile) { function updateProfile(page, profile) {
profile.Name = $('#txtName', page).val(); profile.Name = $('#txtName', page).val();
profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).checked; profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).is(':checked');
profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).checked; profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).is(':checked');
profile.SupportedMediaTypes = $('.chkMediaType:checked', page).get().map(function (c) { profile.SupportedMediaTypes = $('.chkMediaType:checked', page).get().map(function (c) {
return c.getAttribute('data-value'); return c.getAttribute('data-value');
}).join(','); }).join(',');
@ -675,9 +675,9 @@ define(['jQuery', 'loading', 'globalize', 'emby-select', 'emby-button', 'emby-in
profile.MaxAlbumArtHeight = $('#txtAlbumArtMaxHeight', page).val(); profile.MaxAlbumArtHeight = $('#txtAlbumArtMaxHeight', page).val();
profile.MaxIconWidth = $('#txtIconMaxWidth', page).val(); profile.MaxIconWidth = $('#txtIconMaxWidth', page).val();
profile.MaxIconHeight = $('#txtIconMaxHeight', page).val(); profile.MaxIconHeight = $('#txtIconMaxHeight', page).val();
profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).checked; profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).is(':checked');
profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked; profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).is(':checked');
profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).checked; profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).is(':checked');
profile.MaxStreamingBitrate = $('#txtMaxAllowedBitrate', page).val(); profile.MaxStreamingBitrate = $('#txtMaxAllowedBitrate', page).val();
profile.MusicStreamingTranscodingBitrate = $('#txtMusicStreamingTranscodingBitrate', page).val(); profile.MusicStreamingTranscodingBitrate = $('#txtMusicStreamingTranscodingBitrate', page).val();
profile.ProtocolInfo = $('#txtProtocolInfo', page).val(); profile.ProtocolInfo = $('#txtProtocolInfo', page).val();

View file

@ -5,8 +5,8 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo; page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo;
page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog; page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog;
$('#txtClientDiscoveryInterval', page).val(config.ClientDiscoveryIntervalSeconds); $('#txtClientDiscoveryInterval', page).val(config.ClientDiscoveryIntervalSeconds);
$('#chkEnableServer', page).checked = config.EnableServer; $('#chkEnableServer', page).prop('checked', config.EnableServer);
$('#chkBlastAliveMessages', page).checked = config.BlastAliveMessages; $('#chkBlastAliveMessages', page).prop('checked', config.BlastAliveMessages);
$('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds); $('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds);
var usersHtml = users.map(function (u) { var usersHtml = users.map(function (u) {
return '<option value="' + u.Id + '">' + u.Name + '</option>'; return '<option value="' + u.Id + '">' + u.Name + '</option>';
@ -22,8 +22,8 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
config.EnablePlayTo = form.querySelector('#chkEnablePlayTo').checked; config.EnablePlayTo = form.querySelector('#chkEnablePlayTo').checked;
config.EnableDebugLog = form.querySelector('#chkEnableDlnaDebugLogging').checked; config.EnableDebugLog = form.querySelector('#chkEnableDlnaDebugLogging').checked;
config.ClientDiscoveryIntervalSeconds = $('#txtClientDiscoveryInterval', form).val(); config.ClientDiscoveryIntervalSeconds = $('#txtClientDiscoveryInterval', form).val();
config.EnableServer = $('#chkEnableServer', form).checked; config.EnableServer = $('#chkEnableServer', form).is(':checked');
config.BlastAliveMessages = $('#chkBlastAliveMessages', form).checked; config.BlastAliveMessages = $('#chkBlastAliveMessages', form).is(':checked');
config.BlastAliveMessageIntervalSeconds = $('#txtBlastInterval', form).val(); config.BlastAliveMessageIntervalSeconds = $('#txtBlastInterval', form).val();
config.DefaultUserId = $('#selectUser', form).val(); config.DefaultUserId = $('#selectUser', form).val();
ApiClient.updateNamedConfiguration('dlna', config).then(Dashboard.processServerConfigurationUpdateResult); ApiClient.updateNamedConfiguration('dlna', config).then(Dashboard.processServerConfigurationUpdateResult);

View file

@ -5,6 +5,8 @@ define(['jQuery', 'loading', 'globalize', 'dom', 'libraryMenu'], function ($, lo
Array.prototype.forEach.call(page.querySelectorAll('.chkDecodeCodec'), function (c) { Array.prototype.forEach.call(page.querySelectorAll('.chkDecodeCodec'), function (c) {
c.checked = -1 !== (config.HardwareDecodingCodecs || []).indexOf(c.getAttribute('data-codec')); c.checked = -1 !== (config.HardwareDecodingCodecs || []).indexOf(c.getAttribute('data-codec'));
}); });
page.querySelector('#chkDecodingColorDepth10Hevc').checked = config.EnableDecodingColorDepth10Hevc;
page.querySelector('#chkDecodingColorDepth10Vp9').checked = config.EnableDecodingColorDepth10Vp9;
page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding; page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding;
$('#selectVideoDecoder', page).val(config.HardwareAccelerationType); $('#selectVideoDecoder', page).val(config.HardwareAccelerationType);
$('#selectThreadCount', page).val(config.EncodingThreadCount); $('#selectThreadCount', page).val(config.EncodingThreadCount);
@ -67,6 +69,8 @@ define(['jQuery', 'loading', 'globalize', 'dom', 'libraryMenu'], function ($, lo
}), function (c) { }), function (c) {
return c.getAttribute('data-codec'); return c.getAttribute('data-codec');
}); });
config.EnableDecodingColorDepth10Hevc = form.querySelector('#chkDecodingColorDepth10Hevc').checked;
config.EnableDecodingColorDepth10Vp9 = form.querySelector('#chkDecodingColorDepth10Vp9').checked;
config.EnableHardwareEncoding = form.querySelector('#chkHardwareEncoding').checked; config.EnableHardwareEncoding = form.querySelector('#chkHardwareEncoding').checked;
ApiClient.updateNamedConfiguration('encoding', config).then(function () { ApiClient.updateNamedConfiguration('encoding', config).then(function () {
updateEncoder(form); updateEncoder(form);

View file

@ -1,6 +1,12 @@
define(['datetime', 'loading', 'apphost', 'listViewStyle', 'emby-button', 'flexStyles'], function(datetime, loading, appHost) { import datetime from 'datetime';
'use strict'; import loading from 'loading';
return function(view, params) { import 'emby-button';
import 'listViewStyle';
import 'flexStyles';
/* eslint-disable indent */
export default function(view, params) {
view.addEventListener('viewbeforeshow', function() { view.addEventListener('viewbeforeshow', function() {
loading.show(); loading.show();
var apiClient = ApiClient; var apiClient = ApiClient;
@ -29,5 +35,6 @@ define(['datetime', 'loading', 'apphost', 'listViewStyle', 'emby-button', 'flexS
loading.hide(); loading.hide();
}); });
}); });
}; }
});
/* eslint-enable indent */

View file

@ -50,7 +50,7 @@ define(['jQuery', 'emby-checkbox'], function ($) {
fillItems($('.monitorUsersList', page), users, 'chkMonitor', 'chkMonitor', notificationConfig.DisabledMonitorUsers); fillItems($('.monitorUsersList', page), users, 'chkMonitor', 'chkMonitor', notificationConfig.DisabledMonitorUsers);
fillItems($('.sendToUsersList', page), users, 'chkSendTo', 'chkSendTo', notificationConfig.SendToUsers, true); fillItems($('.sendToUsersList', page), users, 'chkSendTo', 'chkSendTo', notificationConfig.SendToUsers, true);
fillItems($('.servicesList', page), services, 'chkService', 'chkService', notificationConfig.DisabledServices); fillItems($('.servicesList', page), services, 'chkService', 'chkService', notificationConfig.DisabledServices);
$('#chkEnabled', page).checked = notificationConfig.Enabled || false; $('#chkEnabled', page).prop('checked', notificationConfig.Enabled || false);
$('#selectUsers', page).val(notificationConfig.SendToUserMode).trigger('change'); $('#selectUsers', page).val(notificationConfig.SendToUserMode).trigger('change');
}); });
} }
@ -73,7 +73,7 @@ define(['jQuery', 'emby-checkbox'], function ($) {
notificationOptions.Options.push(notificationConfig); notificationOptions.Options.push(notificationConfig);
} }
notificationConfig.Enabled = $('#chkEnabled', page).checked; notificationConfig.Enabled = $('#chkEnabled', page).is(':checked');
notificationConfig.SendToUserMode = $('#selectUsers', page).val(); notificationConfig.SendToUserMode = $('#selectUsers', page).val();
notificationConfig.DisabledMonitorUsers = $('.chkMonitor', page).get().filter(function (c) { notificationConfig.DisabledMonitorUsers = $('.chkMonitor', page).get().filter(function (c) {
return !c.checked; return !c.checked;

View file

@ -123,6 +123,9 @@ define(['loading', 'libraryMenu', 'globalize', 'cardStyle', 'emby-button', 'emby
}, { }, {
href: 'availableplugins.html', href: 'availableplugins.html',
name: globalize.translate('TabCatalog') name: globalize.translate('TabCatalog')
}, {
href: 'repositories.html',
name: globalize.translate('TabRepositories')
}]; }];
} }

View file

@ -37,20 +37,24 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
})[0]; })[0];
var configPageUrl = configPage ? Dashboard.getConfigurationPageUrl(configPage.Name) : null; var configPageUrl = configPage ? Dashboard.getConfigurationPageUrl(configPage.Name) : null;
var html = ''; var html = '';
html += "<div data-id='" + plugin.Id + "' data-name='" + plugin.Name + "' class='card backdropCard'>"; html += "<div data-id='" + plugin.Id + "' data-name='" + plugin.Name + "' data-removable='" + plugin.CanUninstall + "' class='card backdropCard'>";
html += '<div class="cardBox visualCardBox">'; html += '<div class="cardBox visualCardBox">';
html += '<div class="cardScalable">'; html += '<div class="cardScalable">';
html += '<div class="cardPadder cardPadder-backdrop"></div>'; html += '<div class="cardPadder cardPadder-backdrop"></div>';
html += configPageUrl ? '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + configPageUrl + '">' : '<div class="cardContent noConfigPluginCard noHoverEffect cardImageContainer">'; html += configPageUrl ? '<a class="cardContent cardImageContainer" is="emby-linkbutton" href="' + configPageUrl + '">' : '<div class="cardContent noConfigPluginCard noHoverEffect cardImageContainer emby-button">';
html += '<span class="cardImageIcon material-icons folder"></span>'; html += '<span class="cardImageIcon material-icons folder"></span>';
html += configPageUrl ? '</a>' : '</div>'; html += configPageUrl ? '</a>' : '</div>';
html += '</div>'; html += '</div>';
html += '<div class="cardFooter">'; html += '<div class="cardFooter">';
html += '<div style="text-align:right; float:right;padding-top:5px;">';
html += '<button type="button" is="paper-icon-button-light" class="btnCardMenu autoSize"><span class="material-icons more_vert"></span></button>'; if (configPage || plugin.CanUninstall) {
html += '</div>'; html += '<div style="text-align:right; float:right;padding-top:5px;">';
html += '<button type="button" is="paper-icon-button-light" class="btnCardMenu autoSize"><span class="material-icons more_vert"></span></button>';
html += '</div>';
}
html += "<div class='cardText'>"; html += "<div class='cardText'>";
html += configPage.DisplayName || plugin.Name; html += configPage && configPage.DisplayName ? configPage.DisplayName : plugin.Name;
html += '</div>'; html += '</div>';
html += "<div class='cardText cardText-secondary'>"; html += "<div class='cardText cardText-secondary'>";
html += plugin.Version; html += plugin.Version;
@ -104,6 +108,7 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
var card = dom.parentWithClass(elem, 'card'); var card = dom.parentWithClass(elem, 'card');
var id = card.getAttribute('data-id'); var id = card.getAttribute('data-id');
var name = card.getAttribute('data-name'); var name = card.getAttribute('data-name');
var removable = card.getAttribute('data-removable');
var configHref = card.querySelector('.cardContent').getAttribute('href'); var configHref = card.querySelector('.cardContent').getAttribute('href');
var menuItems = []; var menuItems = [];
@ -115,11 +120,13 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
}); });
} }
menuItems.push({ if (removable === 'true') {
name: globalize.translate('ButtonUninstall'), menuItems.push({
id: 'delete', name: globalize.translate('ButtonUninstall'),
icon: 'delete' id: 'delete',
}); icon: 'delete'
});
}
require(['actionsheet'], function (actionsheet) { require(['actionsheet'], function (actionsheet) {
actionsheet.show({ actionsheet.show({
@ -153,6 +160,9 @@ define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'
}, { }, {
href: 'availableplugins.html', href: 'availableplugins.html',
name: globalize.translate('TabCatalog') name: globalize.translate('TabCatalog')
}, {
href: 'repositories.html',
name: globalize.translate('TabRepositories')
}]; }];
} }

View file

@ -0,0 +1,153 @@
import loading from 'loading';
import libraryMenu from 'libraryMenu';
import globalize from 'globalize';
import dialogHelper from 'dialogHelper';
import 'emby-button';
import 'emby-checkbox';
import 'emby-select';
import 'formDialogStyle';
import 'listViewStyle';
let repositories = [];
function reloadList(page) {
loading.show();
ApiClient.getJSON(ApiClient.getUrl('Repositories')).then(list => {
repositories = list;
populateList({
listElement: page.querySelector('#repositories'),
noneElement: page.querySelector('#none'),
repositories: repositories
});
}).catch(error => {
console.error('error loading repositories');
page.querySelector('#none').classList.remove('hide');
loading.hide();
});
}
function saveList(page) {
loading.show();
ApiClient.ajax({
type: 'POST',
url: ApiClient.getUrl('Repositories'),
data: JSON.stringify(repositories),
contentType: 'application/json'
}).then(response => {
reloadList(page);
}).catch(error => {
console.error('error saving repositories');
loading.hide();
});
}
function populateList(options) {
var html = '';
html += '<div class="paperList">';
for (var i = 0; i < options.repositories.length; i++) {
html += getRepositoryHtml(options.repositories[i]);
}
html += '</div>';
if (!options.repositories.length) {
options.noneElement.classList.remove('hide');
}
options.listElement.innerHTML = html;
loading.hide();
}
function getRepositoryHtml(repository) {
var html = '';
html += '<div class="listItem listItem-border">';
html += `<a is="emby-linkbutton" style="margin:0;padding:0" class="clearLink listItemIconContainer" href="${repository.Url}">`;
html += '<span class="material-icons listItemIcon open_in_new"></span>';
html += '</a>';
html += '<div class="listItemBody two-line">';
html += `<h3 class="listItemBodyText">${repository.Name}</h3>`;
html += `<div class="listItemBodyText secondary">${repository.Url}</div>`;
html += '</div>';
html += `<button type="button" is="paper-icon-button-light" id="${repository.Url}" class="btnDelete" title="${globalize.translate('ButtonDelete')}"><span class="material-icons delete"></span></button>`;
html += '</div>';
return html;
}
function getTabs() {
return [{
href: 'installedplugins.html',
name: globalize.translate('TabMyPlugins')
}, {
href: 'availableplugins.html',
name: globalize.translate('TabCatalog')
}, {
href: 'repositories.html',
name: globalize.translate('TabRepositories')
}];
}
export default function(view, params) {
view.addEventListener('viewshow', function () {
libraryMenu.setTabs('plugins', 2, getTabs);
reloadList(this);
var save = this;
$('#repositories', view).on('click', '.btnDelete', function() {
var button = this;
repositories = repositories.filter(function (r) {
return r.Url !== button.id;
});
saveList(save);
});
});
view.querySelector('.btnNewRepository').addEventListener('click', () => {
let dialog = dialogHelper.createDialog({
scrollY: false,
size: 'large',
modal: false,
removeOnClose: true
});
let html = '';
html += '<div class="formDialogHeader">';
html += '<button type="button" is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
html += `<h3 class="formDialogHeaderTitle">${globalize.translate('HeaderNewRepository')}</h3>`;
html += '</div>';
html += '<form class="newPluginForm" style="margin:4em">';
html += '<div class="inputContainer">';
html += `<input is="emby-input" id="txtRepositoryName" label="${globalize.translate('LabelRepositoryName')}" type="text" required />`;
html += `<div class="fieldDescription">${globalize.translate('LabelRepositoryNameHelp')}</div>`;
html += '</div>';
html += '<div class="inputContainer">';
html += `<input is="emby-input" id="txtRepositoryUrl" label="${globalize.translate('LabelRepositoryUrl')}" type="url" required />`;
html += `<div class="fieldDescription">${globalize.translate('LabelRepositoryUrlHelp')}</div>`;
html += '</div>';
html += `<button is="emby-button" type="submit" class="raised button-submit block"><span>${globalize.translate('ButtonSave')}</span></button>`;
html += '</div>';
html += '</form>';
dialog.innerHTML = html;
dialog.querySelector('.btnCancel').addEventListener('click', () => {
dialogHelper.close(dialog);
});
dialog.querySelector('.newPluginForm').addEventListener('submit', () => {
repositories.push({
Name: dialog.querySelector('#txtRepositoryName').value,
Url: dialog.querySelector('#txtRepositoryUrl').value,
Enabled: true
});
saveList(view);
dialogHelper.close(dialog);
return false;
});
dialogHelper.open(dialog);
});
}

View file

@ -27,7 +27,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
} }
$('.deleteAccess', page).html(html).trigger('create'); $('.deleteAccess', page).html(html).trigger('create');
$('#chkEnableDeleteAllFolders', page).checked = user.Policy.EnableContentDeletion; $('#chkEnableDeleteAllFolders', page).prop('checked', user.Policy.EnableContentDeletion);
}); });
} }
@ -85,23 +85,23 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
libraryMenu.setTitle(user.Name); libraryMenu.setTitle(user.Name);
page.querySelector('.username').innerHTML = user.Name; page.querySelector('.username').innerHTML = user.Name;
$('#txtUserName', page).val(user.Name); $('#txtUserName', page).val(user.Name);
$('#chkIsAdmin', page).checked = user.Policy.IsAdministrator; $('#chkIsAdmin', page).prop('checked', user.Policy.IsAdministrator);
$('#chkDisabled', page).checked = user.Policy.IsDisabled; $('#chkDisabled', page).prop('checked', user.Policy.IsDisabled);
$('#chkIsHidden', page).checked = user.Policy.IsHidden; $('#chkIsHidden', page).prop('checked', user.Policy.IsHidden);
$('#chkRemoteControlSharedDevices', page).checked = user.Policy.EnableSharedDeviceControl; $('#chkRemoteControlSharedDevices', page).prop('checked', user.Policy.EnableSharedDeviceControl);
$('#chkEnableRemoteControlOtherUsers', page).checked = user.Policy.EnableRemoteControlOfOtherUsers; $('#chkEnableRemoteControlOtherUsers', page).prop('checked', user.Policy.EnableRemoteControlOfOtherUsers);
$('#chkEnableDownloading', page).checked = user.Policy.EnableContentDownloading; $('#chkEnableDownloading', page).prop('checked', user.Policy.EnableContentDownloading);
$('#chkManageLiveTv', page).checked = user.Policy.EnableLiveTvManagement; $('#chkManageLiveTv', page).prop('checked', user.Policy.EnableLiveTvManagement);
$('#chkEnableLiveTvAccess', page).checked = user.Policy.EnableLiveTvAccess; $('#chkEnableLiveTvAccess', page).prop('checked', user.Policy.EnableLiveTvAccess);
$('#chkEnableMediaPlayback', page).checked = user.Policy.EnableMediaPlayback; $('#chkEnableMediaPlayback', page).prop('checked', user.Policy.EnableMediaPlayback);
$('#chkEnableAudioPlaybackTranscoding', page).checked = user.Policy.EnableAudioPlaybackTranscoding; $('#chkEnableAudioPlaybackTranscoding', page).prop('checked', user.Policy.EnableAudioPlaybackTranscoding);
$('#chkEnableVideoPlaybackTranscoding', page).checked = user.Policy.EnableVideoPlaybackTranscoding; $('#chkEnableVideoPlaybackTranscoding', page).prop('checked', user.Policy.EnableVideoPlaybackTranscoding);
$('#chkEnableVideoPlaybackRemuxing', page).checked = user.Policy.EnablePlaybackRemuxing; $('#chkEnableVideoPlaybackRemuxing', page).prop('checked', user.Policy.EnablePlaybackRemuxing);
$('#chkForceRemoteSourceTranscoding', page).checked = user.Policy.ForceRemoteSourceTranscoding; $('#chkForceRemoteSourceTranscoding', page).prop('checked', user.Policy.ForceRemoteSourceTranscoding);
$('#chkRemoteAccess', page).checked = null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess; $('#chkRemoteAccess', page).prop('checked', null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess);
$('#chkEnableSyncTranscoding', page).checked = user.Policy.EnableSyncTranscoding; $('#chkEnableSyncTranscoding', page).prop('checked', user.Policy.EnableSyncTranscoding);
$('#chkEnableConversion', page).checked = user.Policy.EnableMediaConversion || false; $('#chkEnableConversion', page).prop('checked', user.Policy.EnableMediaConversion || false);
$('#chkEnableSharing', page).checked = user.Policy.EnablePublicSharing; $('#chkEnableSharing', page).prop('checked', user.Policy.EnablePublicSharing);
$('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || ''); $('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || '');
$('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0'); $('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0');
$('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess); $('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess);
@ -119,28 +119,28 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
function saveUser(user, page) { function saveUser(user, page) {
user.Name = $('#txtUserName', page).val(); user.Name = $('#txtUserName', page).val();
user.Policy.IsAdministrator = $('#chkIsAdmin', page).checked; user.Policy.IsAdministrator = $('#chkIsAdmin', page).is(':checked');
user.Policy.IsHidden = $('#chkIsHidden', page).checked; user.Policy.IsHidden = $('#chkIsHidden', page).is(':checked');
user.Policy.IsDisabled = $('#chkDisabled', page).checked; user.Policy.IsDisabled = $('#chkDisabled', page).is(':checked');
user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked; user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).is(':checked');
user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked; user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).is(':checked');
user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked; user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).is(':checked');
user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked; user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).is(':checked');
user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked; user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).is(':checked');
user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked; user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).is(':checked');
user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked; user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).is(':checked');
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked; user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).is(':checked');
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked; user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).is(':checked');
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked; user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).is(':checked');
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked; user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).is(':checked');
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked; user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).is(':checked');
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked; user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).is(':checked');
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).checked; user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).is(':checked');
user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0')); user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0'));
user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0'); user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0');
user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value; user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value;
user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value; user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value;
user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).checked; user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).is(':checked');
user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $('.chkFolder', page).get().filter(function (c) { user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $('.chkFolder', page).get().filter(function (c) {
return c.checked; return c.checked;
}).map(function (c) { }).map(function (c) {

View file

@ -47,7 +47,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
$('.channelAccessContainer', page).hide(); $('.channelAccessContainer', page).hide();
} }
$('#chkEnableAllChannels', page).checked = user.Policy.EnableAllChannels; $('#chkEnableAllChannels', page).prop('checked', user.Policy.EnableAllChannels);
} }
function loadDevices(page, user, devices) { function loadDevices(page, user, devices) {
@ -63,7 +63,7 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
html += '</div>'; html += '</div>';
$('.deviceAccess', page).show().html(html); $('.deviceAccess', page).show().html(html);
$('#chkEnableAllDevices', page).checked = user.Policy.EnableAllDevices; $('#chkEnableAllDevices', page).prop('checked', user.Policy.EnableAllDevices);
if (user.Policy.IsAdministrator) { if (user.Policy.IsAdministrator) {
page.querySelector('.deviceAccessContainer').classList.add('hide'); page.querySelector('.deviceAccessContainer').classList.add('hide');
@ -90,19 +90,19 @@ define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading,
} }
function saveUser(user, page) { function saveUser(user, page) {
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked; user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).is(':checked');
user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $('.chkFolder', page).get().filter(function (c) { user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $('.chkFolder', page).get().filter(function (c) {
return c.checked; return c.checked;
}).map(function (c) { }).map(function (c) {
return c.getAttribute('data-id'); return c.getAttribute('data-id');
}); });
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked; user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).is(':checked');
user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $('.chkChannel', page).get().filter(function (c) { user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $('.chkChannel', page).get().filter(function (c) {
return c.checked; return c.checked;
}).map(function (c) { }).map(function (c) {
return c.getAttribute('data-id'); return c.getAttribute('data-id');
}); });
user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).checked; user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).is(':checked');
user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $('.chkDevice', page).get().filter(function (c) { user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $('.chkDevice', page).get().filter(function (c) {
return c.checked; return c.checked;
}).map(function (c) { }).map(function (c) {

View file

@ -13,7 +13,7 @@ define(['jQuery', 'loading', 'globalize', 'emby-checkbox'], function ($, loading
html += '</div>'; html += '</div>';
$('.folderAccess', page).html(html).trigger('create'); $('.folderAccess', page).html(html).trigger('create');
$('#chkEnableAllFolders', page).checked = false; $('#chkEnableAllFolders', page).prop('checked', false);
} }
function loadChannels(page, channels) { function loadChannels(page, channels) {
@ -35,7 +35,7 @@ define(['jQuery', 'loading', 'globalize', 'emby-checkbox'], function ($, loading
$('.channelAccessContainer', page).hide(); $('.channelAccessContainer', page).hide();
} }
$('#chkEnableAllChannels', page).checked = false; $('#chkEnableAllChannels', page).prop('checked', false);
} }
function loadUser(page) { function loadUser(page) {
@ -58,7 +58,7 @@ define(['jQuery', 'loading', 'globalize', 'emby-checkbox'], function ($, loading
user.Name = $('#txtUsername', page).val(); user.Name = $('#txtUsername', page).val();
user.Password = $('#txtPassword', page).val(); user.Password = $('#txtPassword', page).val();
ApiClient.createUser(user).then(function (user) { ApiClient.createUser(user).then(function (user) {
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked; user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).is(':checked');
user.Policy.EnabledFolders = []; user.Policy.EnabledFolders = [];
if (!user.Policy.EnableAllFolders) { if (!user.Policy.EnableAllFolders) {
@ -69,7 +69,7 @@ define(['jQuery', 'loading', 'globalize', 'emby-checkbox'], function ($, loading
}); });
} }
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked; user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).is(':checked');
user.Policy.EnabledChannels = []; user.Policy.EnabledChannels = [];
if (!user.Policy.EnableAllChannels) { if (!user.Policy.EnableAllChannels) {

View file

@ -141,29 +141,29 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
return; return;
} }
playbackManager.getPlaybackMediaSources(item).then(function (mediaSources) { var mediaSources = item.MediaSources;
instance._currentPlaybackMediaSources = mediaSources; instance._currentPlaybackMediaSources = mediaSources;
page.querySelector('.trackSelections').classList.remove('hide'); page.querySelector('.trackSelections').classList.remove('hide');
select.setLabel(globalize.translate('LabelVersion')); select.setLabel(globalize.translate('LabelVersion'));
var currentValue = select.value; var currentValue = select.value;
var selectedId = mediaSources[0].Id; var selectedId = mediaSources[0].Id;
select.innerHTML = mediaSources.map(function (v) { select.innerHTML = mediaSources.map(function (v) {
var selected = v.Id === selectedId ? ' selected' : ''; var selected = v.Id === selectedId ? ' selected' : '';
return '<option value="' + v.Id + '"' + selected + '>' + v.Name + '</option>'; return '<option value="' + v.Id + '"' + selected + '>' + v.Name + '</option>';
}).join(''); }).join('');
if (mediaSources.length > 1) { if (mediaSources.length > 1) {
page.querySelector('.selectSourceContainer').classList.remove('hide'); page.querySelector('.selectSourceContainer').classList.remove('hide');
} else { } else {
page.querySelector('.selectSourceContainer').classList.add('hide'); page.querySelector('.selectSourceContainer').classList.add('hide');
} }
if (select.value !== currentValue || forceReload) {
renderVideoSelections(page, mediaSources);
renderAudioSelections(page, mediaSources);
renderSubtitleSelections(page, mediaSources);
}
if (select.value !== currentValue || forceReload) {
renderVideoSelections(page, mediaSources);
renderAudioSelections(page, mediaSources);
renderSubtitleSelections(page, mediaSources);
}
});
} }
function renderVideoSelections(page, mediaSources) { function renderVideoSelections(page, mediaSources) {
@ -400,6 +400,7 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
} else if (item.Album) { } else if (item.Album) {
parentNameHtml.push(item.Album); parentNameHtml.push(item.Album);
} }
// FIXME: This whole section needs some refactoring, so it becames easier to scale across all form factors. See GH #1022 // FIXME: This whole section needs some refactoring, so it becames easier to scale across all form factors. See GH #1022
var html = ''; var html = '';
var tvShowHtml = parentNameHtml[0]; var tvShowHtml = parentNameHtml[0];
@ -415,9 +416,9 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
} }
} else { } else {
if (layoutManager.mobile) { if (layoutManager.mobile) {
html = '<h1 class="parentName" style="margin: .1em 0 .25em;">' + parentNameHtml.join('</br>') + '</h1>'; html = '<h1 class="parentName" style="margin: 0.2em 0 0">' + parentNameHtml.join('</br>') + '</h1>';
} else { } else {
html = '<h1 class="parentName" style="margin: .1em 0 .25em;">' + tvShowHtml + '</h1>'; html = '<h1 class="parentName" style="margin: 0.2em 0 0">' + tvShowHtml + '</h1>';
} }
} }
} }
@ -425,20 +426,19 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
var name = itemHelper.getDisplayName(item, { var name = itemHelper.getDisplayName(item, {
includeParentInfo: false includeParentInfo: false
}); });
var offset = parentNameLast ? '.25em' : '.5em';
if (html && !parentNameLast) { if (html && !parentNameLast) {
if (!layoutManager.mobile && tvSeasonHtml) { if (!layoutManager.mobile && tvSeasonHtml) {
html += '<h3 class="itemName infoText" style="margin: .25em 0 .5em;">' + tvSeasonHtml + ' - ' + name + '</h3>'; html += '<h3 class="itemName infoText" style="margin: 0.2em 0 0">' + tvSeasonHtml + ' - ' + name + '</h3>';
} else { } else {
html += '<h3 class="itemName infoText" style="margin: .25em 0 .5em;">' + name + '</h3>'; html += '<h3 class="itemName infoText" style="margin: 0.2em 0 0">' + name + '</h3>';
} }
} else { } else {
html = '<h1 class="itemName infoText" style="margin: .1em 0 ' + offset + ';">' + name + '</h1>' + html; html = '<h1 class="itemName infoText" style="margin: 0.4em 0 0">' + name + '</h1>' + html;
} }
if (item.OriginalTitle && item.OriginalTitle != item.Name) { if (item.OriginalTitle && item.OriginalTitle != item.Name) {
html += '<h4 class="itemName infoText" style="margin: -' + offset + ' 0 0;">' + item.OriginalTitle + '</h4>'; html += '<h4 class="itemName infoText" style="margin: 0 0 0;">' + item.OriginalTitle + '</h4>';
} }
container.innerHTML = html; container.innerHTML = html;
@ -1106,10 +1106,10 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
var externalLinksElem = page.querySelector('.itemExternalLinks'); var externalLinksElem = page.querySelector('.itemExternalLinks');
renderOverview([overview], item); renderOverview([overview], item);
var i; var i;
var itemMiscInfo; var itemMiscInfo;
itemMiscInfo = page.querySelectorAll('.itemMiscInfo-primary'); itemMiscInfo = page.querySelectorAll('.itemMiscInfo-primary');
for (i = 0; i < itemMiscInfo.length; i++) { for (i = 0; i < itemMiscInfo.length; i++) {
mediaInfo.fillPrimaryMediaInfo(itemMiscInfo[i], item, { mediaInfo.fillPrimaryMediaInfo(itemMiscInfo[i], item, {
interactive: true, interactive: true,
@ -1125,7 +1125,6 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
} }
itemMiscInfo = page.querySelectorAll('.itemMiscInfo-secondary'); itemMiscInfo = page.querySelectorAll('.itemMiscInfo-secondary');
for (i = 0; i < itemMiscInfo.length; i++) { for (i = 0; i < itemMiscInfo.length; i++) {
mediaInfo.fillSecondaryMediaInfo(itemMiscInfo[i], item, { mediaInfo.fillSecondaryMediaInfo(itemMiscInfo[i], item, {
interactive: true interactive: true
@ -1840,7 +1839,8 @@ define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSetti
chaptercardbuilder.buildChapterCards(item, chapters, { chaptercardbuilder.buildChapterCards(item, chapters, {
itemsContainer: scenesContent, itemsContainer: scenesContent,
backdropShape: 'overflowBackdrop', backdropShape: 'overflowBackdrop',
squareShape: 'overflowSquare' squareShape: 'overflowSquare',
imageBlurhashes: item.ImageBlurHashes
}); });
}); });
} else { } else {

View file

@ -386,7 +386,7 @@ define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager'
var instance = this; var instance = this;
require(['playlistEditor'], function (playlistEditor) { require(['playlistEditor'], function (playlistEditor) {
new playlistEditor().show({ new playlistEditor.showEditor({
items: [], items: [],
serverId: instance.params.serverId serverId: instance.params.serverId
}); });

View file

@ -86,7 +86,7 @@ define(['cardBuilder', 'imageLoader', 'libraryBrowser', 'loading', 'events', 'us
} }
function showFilterMenu(context) { function showFilterMenu(context) {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(), query: getQuery(),
mode: 'livetvchannels', mode: 'livetvchannels',

View file

@ -155,8 +155,8 @@ define(['jQuery', 'globalize', 'scripts/taskbutton', 'dom', 'libraryMenu', 'layo
} }
function mapChannels(page, providerId) { function mapChannels(page, providerId) {
require(['components/channelMapper/channelMapper'], function (channelmapper) { require(['components/channelMapper/channelMapper'], function (channelMapper) {
new channelmapper({ new channelMapper.default({
serverId: ApiClient.serverInfo().Id, serverId: ApiClient.serverInfo().Id,
providerId: providerId providerId: providerId
}).show(); }).show();

View file

@ -171,7 +171,12 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
} }
if (!result.Items.length) { if (!result.Items.length) {
html = '<p style="text-align:center;">' + globalize.translate('MessageNoCollectionsAvailable') + '</p>'; html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoCollectionsAvailable') + '</p>';
html += '</div>';
} }
var itemsContainer = tabContent.querySelector('.itemsContainer'); var itemsContainer = tabContent.querySelector('.itemsContainer');
@ -237,7 +242,7 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
tabContent.querySelector('.btnNewCollection').addEventListener('click', function () { tabContent.querySelector('.btnNewCollection').addEventListener('click', function () {
require(['collectionEditor'], function (collectionEditor) { require(['collectionEditor'], function (collectionEditor) {
var serverId = ApiClient.serverInfo().Id; var serverId = ApiClient.serverInfo().Id;
new collectionEditor().show({ new collectionEditor.showEditor({
items: [], items: [],
serverId: serverId serverId: serverId
}); });

View file

@ -165,6 +165,15 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
html += '</div>'; html += '</div>';
} }
if (!result.Items.length) {
html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoGenresAvailable') + '</p>';
html += '</div>';
}
elem.innerHTML = html; elem.innerHTML = html;
lazyLoader.lazyChildren(elem, fillItemsContainer); lazyLoader.lazyChildren(elem, fillItemsContainer);
libraryBrowser.saveQueryValues(getSavedQueryKey(), query); libraryBrowser.saveQueryValues(getSavedQueryKey(), query);

View file

@ -270,7 +270,7 @@ define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser',
query = userSettings.loadQuerySettings(savedQueryKey, query); query = userSettings.loadQuerySettings(savedQueryKey, query);
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: query, query: query,
mode: 'movies', mode: 'movies',

View file

@ -158,7 +158,12 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
} }
if (!result.Items.length) { if (!result.Items.length) {
html = '<p style="text-align:center;">' + globalize.translate('MessageNoTrailersFound') + '</p>'; html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoTrailersFound') + '</p>';
html += '</div>';
} }
var itemsContainer = tabContent.querySelector('.itemsContainer'); var itemsContainer = tabContent.querySelector('.itemsContainer');
@ -180,7 +185,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: 'movies', mode: 'movies',

View file

@ -186,7 +186,7 @@ define(['layoutManager', 'playbackManager', 'loading', 'events', 'libraryBrowser
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(), query: getQuery(),
mode: 'albums', mode: 'albums',

View file

@ -170,7 +170,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: self.mode, mode: self.mode,

View file

@ -124,7 +124,7 @@ define(['events', 'libraryBrowser', 'imageLoader', 'listView', 'loading', 'userS
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: 'songs', mode: 'songs',

View file

@ -164,7 +164,7 @@ define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardB
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: 'episodes', mode: 'episodes',

View file

@ -161,6 +161,15 @@ define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader
html += '</div>'; html += '</div>';
} }
if (!result.Items.length) {
html = '';
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate('MessageNoGenresAvailable') + '</p>';
html += '</div>';
}
elem.innerHTML = html; elem.innerHTML = html;
lazyLoader.lazyChildren(elem, fillItemsContainer); lazyLoader.lazyChildren(elem, fillItemsContainer);
libraryBrowser.saveQueryValues(getSavedQueryKey(), query); libraryBrowser.saveQueryValues(getSavedQueryKey(), query);

View file

@ -197,7 +197,7 @@ define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', '
var isLoading = false; var isLoading = false;
self.showFilterMenu = function () { self.showFilterMenu = function () {
require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { require(['components/filterdialog/filterdialog'], function ({default: filterDialogFactory}) {
var filterDialog = new filterDialogFactory({ var filterDialog = new filterDialogFactory({
query: getQuery(tabContent), query: getQuery(tabContent),
mode: 'series', mode: 'series',

View file

@ -1,6 +1,9 @@
define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySettings, userSettings, autoFocuser) { define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySettings, userSettings, autoFocuser) {
'use strict'; 'use strict';
// Shortcuts
const UserSettings = userSettings.UserSettings;
return function (view, params) { return function (view, params) {
function onBeforeUnload(e) { function onBeforeUnload(e) {
if (hasChanges) { if (hasChanges) {
@ -11,7 +14,7 @@ define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySett
var settingsInstance; var settingsInstance;
var hasChanges; var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId(); var userId = params.userId || ApiClient.getCurrentUserId();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
view.addEventListener('viewshow', function () { view.addEventListener('viewshow', function () {
window.addEventListener('beforeunload', onBeforeUnload); window.addEventListener('beforeunload', onBeforeUnload);

View file

@ -1,6 +1,9 @@
define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (HomescreenSettings, dom, globalize, loading, userSettings, autoFocuser) { define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (HomescreenSettings, dom, globalize, loading, userSettings, autoFocuser) {
'use strict'; 'use strict';
// Shortcuts
const UserSettings = userSettings.UserSettings;
return function (view, params) { return function (view, params) {
function onBeforeUnload(e) { function onBeforeUnload(e) {
if (hasChanges) { if (hasChanges) {
@ -11,7 +14,7 @@ define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'au
var homescreenSettingsInstance; var homescreenSettingsInstance;
var hasChanges; var hasChanges;
var userId = params.userId || ApiClient.getCurrentUserId(); var userId = params.userId || ApiClient.getCurrentUserId();
var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new UserSettings();
view.addEventListener('viewshow', function () { view.addEventListener('viewshow', function () {
window.addEventListener('beforeunload', onBeforeUnload); window.addEventListener('beforeunload', onBeforeUnload);

View file

@ -43,12 +43,6 @@ define(['apphost', 'connectionManager', 'layoutManager', 'listViewStyle', 'emby-
page.querySelector('.adminSection').classList.add('hide'); page.querySelector('.adminSection').classList.add('hide');
} }
if (layoutManager.mobile) {
page.querySelector('.headerUsername').classList.add('hide');
page.querySelector('.adminSection').classList.add('hide');
page.querySelector('.userSection').classList.add('hide');
}
ApiClient.getUser(userId).then(function(user) { ApiClient.getUser(userId).then(function(user) {
page.querySelector('.headerUsername').innerHTML = user.Name; page.querySelector('.headerUsername').innerHTML = user.Name;
if (!user.Policy.IsAdministrator) { if (!user.Policy.IsAdministrator) {

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