Merge remote-tracking branch 'upstream/master' into sorted-media-sources
This commit is contained in:
@@ -235,6 +235,15 @@ div[data-role=controlgroup] a.ui-btn-active {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.localUsers .cardText-secondary {
|
||||
white-space: pre-wrap;
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.customCssContainer textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
@media all and (min-width: 70em) {
|
||||
.dashboardSections {
|
||||
-webkit-flex-wrap: wrap;
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.align-items-flex-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.justify-content-center {
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -38,6 +42,10 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.justify-content-space-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-wrap-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
html {
|
||||
font-family: "Noto Sans", sans-serif;
|
||||
font-size: 93%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
@@ -29,7 +27,9 @@ h3 {
|
||||
}
|
||||
|
||||
.layout-tv {
|
||||
font-size: 130%;
|
||||
/* Per WebOS and Tizen guidelines, fonts must be 20px minimum.
|
||||
This takes the 16px baseline and multiplies it by 1.25 to get 20px. */
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.layout-mobile {
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
html {
|
||||
font-size: 82% !important;
|
||||
}
|
||||
|
||||
.formDialogFooter {
|
||||
position: static !important;
|
||||
margin: 0 -1em !important;
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
padding-top: 7em !important;
|
||||
}
|
||||
|
||||
.layout-mobile .libraryPage {
|
||||
padding-top: 4em !important;
|
||||
}
|
||||
|
||||
.itemDetailPage {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.layout-tv .itemDetailPage {
|
||||
padding-top: 4.2em !important;
|
||||
}
|
||||
|
||||
.standalonePage {
|
||||
padding-top: 4.5em !important;
|
||||
}
|
||||
@@ -164,6 +164,13 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
contain: layout style paint;
|
||||
transition: background ease-in-out 0.5s;
|
||||
}
|
||||
|
||||
.layout-tv .skinHeader {
|
||||
/* In TV layout, it makes more sense to keep the top bar at the top of the page
|
||||
Having it follow the view only makes us lose vertical space, while not being focusable */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hiddenViewMenuBar .skinHeader {
|
||||
@@ -178,6 +185,10 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.layout-tv .sectionTabs {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
.selectedMediaFolder {
|
||||
background-color: #f2f2f2 !important;
|
||||
}
|
||||
@@ -235,12 +246,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layout-desktop .searchTabButton,
|
||||
.layout-mobile .searchTabButton,
|
||||
.layout-tv .headerSearchButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mainDrawer-scrollContainer {
|
||||
padding-bottom: 10vh;
|
||||
}
|
||||
@@ -272,7 +277,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 84em) {
|
||||
@media all and (max-width: 100em) {
|
||||
.withSectionTabs .headerTop {
|
||||
padding-bottom: 0.55em;
|
||||
}
|
||||
@@ -280,9 +285,13 @@
|
||||
.sectionTabs {
|
||||
font-size: 83.5%;
|
||||
}
|
||||
|
||||
.layout-tv .sectionTabs {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 84em) {
|
||||
@media all and (min-width: 100em) {
|
||||
.headerTop {
|
||||
padding: 0.8em 0.8em;
|
||||
}
|
||||
@@ -438,16 +447,17 @@
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-attachment: fixed;
|
||||
height: 50vh;
|
||||
height: 40vh;
|
||||
position: relative;
|
||||
animation: backdrop-fadein 800ms ease-in normal both;
|
||||
}
|
||||
|
||||
.layout-mobile .itemBackdrop {
|
||||
background-attachment: scroll;
|
||||
height: 26.5vh;
|
||||
}
|
||||
|
||||
.layout-desktop .itemBackdrop::after,
|
||||
.layout-tv .itemBackdrop::after {
|
||||
.layout-desktop .itemBackdrop::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -455,18 +465,28 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .itemBackdrop,
|
||||
.layout-tv .noBackdrop .itemBackdrop {
|
||||
.layout-tv .itemBackdrop,
|
||||
.layout-desktop .noBackdrop .itemBackdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.detailPageContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 2%;
|
||||
padding-left: 32.45vw;
|
||||
padding-right: 2%;
|
||||
}
|
||||
|
||||
.layout-mobile .detailPageContent {
|
||||
padding-left: 5%;
|
||||
padding-right: 5%;
|
||||
}
|
||||
|
||||
.layout-desktop .detailPageContent .emby-scroller,
|
||||
.layout-tv .detailPageContent .emby-scroller {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailPageContent,
|
||||
.layout-tv .noBackdrop .detailPageContent {
|
||||
margin-top: 2.5em;
|
||||
@@ -477,6 +497,10 @@
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.detailSectionContent a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.personBackdrop {
|
||||
background-size: contain;
|
||||
}
|
||||
@@ -495,7 +519,23 @@
|
||||
|
||||
.parentName {
|
||||
display: block;
|
||||
margin-bottom: 0.5em;
|
||||
margin: 0 0 0;
|
||||
}
|
||||
|
||||
.layout-mobile .parentName {
|
||||
margin: 0.6em 0 0;
|
||||
}
|
||||
|
||||
.musicParentName {
|
||||
margin: 0.15em 0 0.2em;
|
||||
}
|
||||
|
||||
.layout-mobile .musicParentName {
|
||||
margin: -0.25em 0 0.25em;
|
||||
}
|
||||
|
||||
.layout-mobile .itemExternalLinks {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mainDetailButtons {
|
||||
@@ -503,8 +543,6 @@
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
@@ -520,6 +558,35 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.itemName.originalTitle {
|
||||
margin: 0.2em 0 0.2em;
|
||||
}
|
||||
|
||||
.itemName.parentNameLast {
|
||||
margin: 0 0 0;
|
||||
}
|
||||
|
||||
.layout-mobile .itemName.parentNameLast {
|
||||
margin: 0.4em 0 0.4em;
|
||||
}
|
||||
|
||||
.layout-mobile h1.itemName,
|
||||
.layout-mobile h1.parentName {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
|
||||
.itemName.parentNameLast.withOriginalTitle {
|
||||
margin: 0 0 0;
|
||||
}
|
||||
|
||||
.layout-mobile .itemName.parentNameLast.withOriginalTitle {
|
||||
margin: 0.6em 0 0;
|
||||
}
|
||||
|
||||
.layout-mobile .itemName.originalTitle {
|
||||
margin: 0.5em 0 0.5em;
|
||||
}
|
||||
|
||||
.nameContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -546,6 +613,19 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layout-mobile .mainDetailButtons {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin: 0.15em 0 0.2em;
|
||||
}
|
||||
|
||||
.layout-mobile .subtitle {
|
||||
margin: 0.2em 0 0.2em;
|
||||
}
|
||||
|
||||
.detailPagePrimaryContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -553,10 +633,14 @@
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.layout-tv .detailPagePrimaryContainer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.layout-mobile .detailPagePrimaryContainer {
|
||||
display: block;
|
||||
position: relative;
|
||||
top: 0;
|
||||
padding: 0.5em 3.3% 0.5em;
|
||||
}
|
||||
|
||||
.layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer,
|
||||
@@ -566,13 +650,18 @@
|
||||
padding-left: 32.45vw;
|
||||
}
|
||||
|
||||
.layout-desktop .detailSticky,
|
||||
.layout-tv .detailSticky {
|
||||
.layout-desktop .detailRibbon {
|
||||
margin-top: -7.2em;
|
||||
height: 7.2em;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailSticky,
|
||||
.layout-tv .noBackdrop .detailSticky {
|
||||
.layout-tv .detailRibbon {
|
||||
margin-top: 0;
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailRibbon,
|
||||
.layout-tv .noBackdrop .detailRibbon {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@@ -584,6 +673,9 @@
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-align: left;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layout-mobile .infoText {
|
||||
@@ -594,12 +686,29 @@
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.detailImageContainer {
|
||||
position: relative;
|
||||
margin-top: -25vh;
|
||||
.layout-mobile .detailPageSecondaryContainer {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.layout-mobile .detailImageContainer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.detailImageContainer .card {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
float: left;
|
||||
width: 25vw;
|
||||
z-index: 3;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.detailImageContainer .card.backdropCard {
|
||||
top: 35%;
|
||||
}
|
||||
|
||||
.detailImageContainer .card.squareCard {
|
||||
top: 40%;
|
||||
}
|
||||
|
||||
.layout-desktop .noBackdrop .detailImageContainer,
|
||||
@@ -612,11 +721,11 @@
|
||||
}
|
||||
|
||||
.detailLogo {
|
||||
width: 30vw;
|
||||
height: 25vh;
|
||||
width: 25vw;
|
||||
height: 16vh;
|
||||
position: absolute;
|
||||
top: 10vh;
|
||||
right: 20vw;
|
||||
right: 25vw;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
@@ -641,7 +750,8 @@ div.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 {
|
||||
@@ -655,14 +765,18 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layout-desktop .detailPageWrapperContainer,
|
||||
.layout-tv .detailPageWrapperContainer {
|
||||
margin-top: 7.2em;
|
||||
.layout-desktop .itemBackdrop {
|
||||
height: 40vh;
|
||||
}
|
||||
|
||||
.layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer,
|
||||
.layout-desktop #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer {
|
||||
padding-left: 3.3%;
|
||||
.layout-desktop .detailPageWrapperContainer,
|
||||
.layout-tv .detailPageWrapperContainer {
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
|
||||
.layout-desktop .detailImageContainer .card,
|
||||
.layout-tv .detailImageContainer .card {
|
||||
top: 10%;
|
||||
}
|
||||
|
||||
.btnPlaySimple {
|
||||
@@ -677,13 +791,8 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
}
|
||||
|
||||
.emby-button.detailFloatingButton {
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0, 0.5) !important;
|
||||
z-index: 1;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -2.2em 0 0 -2.2em;
|
||||
padding: 0.4em !important;
|
||||
font-size: 1.4em;
|
||||
margin-right: 0.5em !important;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
}
|
||||
|
||||
@@ -693,16 +802,12 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
|
||||
@media all and (max-width: 62.5em) {
|
||||
.parentName {
|
||||
margin-bottom: 1em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.itemDetailPage {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.detailimg-hidemobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 31.25em) {
|
||||
@@ -750,7 +855,7 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
margin: 0 !important;
|
||||
padding: 0.5em 0.7em !important;
|
||||
padding: 0.7em 0.7em !important;
|
||||
}
|
||||
|
||||
@media all and (min-width: 29em) {
|
||||
@@ -797,9 +902,9 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
}
|
||||
|
||||
.detailImageProgressContainer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 22.786458333333332vw;
|
||||
margin-top: -0.4vw;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.detailButton-text {
|
||||
@@ -818,25 +923,7 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 62.5em) {
|
||||
.headerTop {
|
||||
padding-left: 0.8em;
|
||||
padding-right: 0.8em;
|
||||
}
|
||||
|
||||
.headerTabs {
|
||||
align-self: center;
|
||||
width: auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: -4.2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.detailFloatingButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media all and (min-width: 100em) {
|
||||
.personBackdrop {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -845,6 +932,11 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
font-size: 108%;
|
||||
margin: 1.25em 0;
|
||||
}
|
||||
|
||||
.layout-tv .mainDetailButtons {
|
||||
font-size: 108%;
|
||||
margin: 1em 0 1.25em;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 50em) {
|
||||
@@ -866,6 +958,10 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
}
|
||||
}
|
||||
|
||||
.detailVerticalSection .emby-scrollbuttons {
|
||||
padding-top: 0.4em;
|
||||
}
|
||||
|
||||
.layout-tv .detailVerticalSection {
|
||||
margin-bottom: 3.4em !important;
|
||||
}
|
||||
@@ -954,6 +1050,10 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
margin-bottom: 2.7em;
|
||||
}
|
||||
|
||||
.layout-mobile .verticalSection-extrabottompadding {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.sectionTitleButton,
|
||||
.sectionTitleIconButton {
|
||||
margin-right: 0 !important;
|
||||
@@ -979,7 +1079,13 @@ div.itemDetailGalleryLink.defaultCardBackground {
|
||||
|
||||
div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
||||
margin: 0;
|
||||
padding-top: 1.25em;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.2em;
|
||||
}
|
||||
|
||||
.layout-mobile :not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
||||
margin: 0;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
.sectionTitleButton {
|
||||
@@ -1046,13 +1152,13 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
||||
}
|
||||
|
||||
.layout-tv .padded-top-focusscale {
|
||||
padding-top: 1em;
|
||||
margin-top: -1em;
|
||||
padding-top: 1.5em;
|
||||
margin-top: -1.5em;
|
||||
}
|
||||
|
||||
.layout-tv .padded-bottom-focusscale {
|
||||
padding-bottom: 1em;
|
||||
margin-bottom: -1em;
|
||||
padding-bottom: 1.5em;
|
||||
margin-bottom: -1.5em;
|
||||
}
|
||||
|
||||
@media all and (min-height: 31.25em) {
|
||||
@@ -1132,6 +1238,12 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
||||
|
||||
.trackSelections .selectContainer .selectLabel {
|
||||
margin: 0 0.2em 0 0;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.layout-mobile .detailsGroupItem .label,
|
||||
.layout-mobile .trackSelections .selectContainer .selectLabel {
|
||||
flex-basis: 4.5em;
|
||||
}
|
||||
|
||||
.trackSelections .selectContainer .detailTrackSelect {
|
||||
@@ -1144,3 +1256,21 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards {
|
||||
margin-top: 0;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.overview-controls {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.detail-clamp-text {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 12;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
@media all and (min-width: 40em) {
|
||||
.detail-clamp-text {
|
||||
-webkit-line-clamp: 6;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
.hiddenScrollX,
|
||||
.layout-tv .scrollX {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.hiddenScrollX-forced {
|
||||
@@ -40,6 +41,7 @@
|
||||
.hiddenScrollY,
|
||||
.layout-tv .smoothScrollY {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
/* Can't do this because it not only hides the scrollbar, but also prevents scrolling */
|
||||
|
||||
|
||||
+26
-11
@@ -5,6 +5,12 @@ html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.layout-mobile,
|
||||
.layout-tv {
|
||||
-webkit-touch-callout: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.clipForScreenReader {
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
clip-path: inset(50%);
|
||||
@@ -18,7 +24,7 @@ html {
|
||||
|
||||
.material-icons {
|
||||
/* Fix font ligatures on older WebOS versions */
|
||||
-webkit-font-feature-settings: "liga";
|
||||
font-feature-settings: "liga";
|
||||
}
|
||||
|
||||
.backgroundContainer {
|
||||
@@ -34,16 +40,6 @@ html {
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.layout-mobile,
|
||||
.layout-tv {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
background-color: transparent !important;
|
||||
@@ -121,6 +117,11 @@ div[data-role=page] {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.drawerContent {
|
||||
/* make sure the bottom of the drawer is visible when music is playing */
|
||||
padding-bottom: 4em;
|
||||
}
|
||||
|
||||
.force-scroll {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
@@ -128,3 +129,17 @@ div[data-role=page] {
|
||||
.hide-scroll {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.w-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.margin-auto-x {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.margin-auto-y {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
}
|
||||
|
||||
.osdPoster img,
|
||||
.pageContainer,
|
||||
.videoOsdBottom {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -248,14 +247,7 @@
|
||||
animation: spin 4s linear infinite;
|
||||
}
|
||||
|
||||
.pageContainer {
|
||||
top: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
@media all and (max-width: 30em) {
|
||||
.btnFastForward,
|
||||
.btnRewind,
|
||||
.osdMediaInfo,
|
||||
.osdPoster {
|
||||
display: none !important;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24"><title>Microsoft Edge icon</title><path d="M21.86 17.86q.14 0 .25.12.1.13.1.25t-.11.33l-.32.46-.43.53-.44.5q-.21.25-.38.42l-.22.23q-.58.53-1.34 1.04-.76.51-1.6.91-.86.4-1.74.64t-1.67.24q-.9 0-1.69-.28-.8-.28-1.48-.78-.68-.5-1.22-1.17-.53-.66-.92-1.44-.38-.77-.58-1.6-.2-.83-.2-1.67 0-1 .32-1.96.33-.97.87-1.8.14.95.55 1.77.41.82 1.02 1.5.6.68 1.38 1.21.78.54 1.64.9.86.36 1.77.56.92.2 1.8.2 1.12 0 2.18-.24 1.06-.23 2.06-.72l.2-.1.2-.05zm-15.5-1.27q0 1.1.27 2.15.27 1.06.78 2.03.51.96 1.24 1.77.74.82 1.66 1.4-1.47-.2-2.8-.74-1.33-.55-2.48-1.37-1.15-.83-2.08-1.9-.92-1.07-1.58-2.33T.36 14.94Q0 13.54 0 12.06q0-.81.32-1.49.31-.68.83-1.23.53-.55 1.2-.96.66-.4 1.35-.66.74-.27 1.5-.39.78-.12 1.55-.12.7 0 1.42.1.72.12 1.4.35.68.23 1.32.57.63.35 1.16.83-.35 0-.7.07-.33.07-.65.23v-.02q-.63.28-1.2.74-.57.46-1.05 1.04-.48.58-.87 1.26-.38.67-.65 1.39-.27.71-.42 1.44-.15.72-.15 1.38zM11.96.06q1.7 0 3.33.39 1.63.38 3.07 1.15 1.43.77 2.62 1.93 1.18 1.16 1.98 2.7.49.94.76 1.96.28 1 .28 2.08 0 .89-.23 1.7-.24.8-.69 1.48-.45.68-1.1 1.22-.64.53-1.45.88-.54.24-1.11.36-.58.13-1.16.13-.42 0-.97-.03-.54-.03-1.1-.12-.55-.1-1.05-.28-.5-.19-.84-.5-.12-.09-.23-.24-.1-.16-.1-.33 0-.15.16-.35.16-.2.35-.5.2-.28.36-.68.16-.4.16-.95 0-1.06-.4-1.96-.4-.91-1.06-1.64-.66-.74-1.52-1.28-.86-.55-1.79-.89-.84-.3-1.72-.44-.87-.14-1.76-.14-1.55 0-3.06.45T.94 7.55q.71-1.74 1.81-3.13 1.1-1.38 2.52-2.35Q6.68 1.1 8.37.58q1.7-.52 3.58-.52Z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
+39
-39
@@ -2,165 +2,159 @@
|
||||
* require.js module definitions bundled by webpack
|
||||
*/
|
||||
// Use define from require.js not webpack's define
|
||||
var _define = window.define;
|
||||
|
||||
// document-register-element
|
||||
var docRegister = require('document-register-element');
|
||||
_define('document-register-element', function() {
|
||||
return docRegister;
|
||||
});
|
||||
const _define = window.define;
|
||||
|
||||
// fetch
|
||||
var fetch = require('whatwg-fetch');
|
||||
const fetch = require('whatwg-fetch');
|
||||
_define('fetch', function() {
|
||||
return fetch;
|
||||
});
|
||||
|
||||
// Blurhash
|
||||
const blurhash = require('blurhash');
|
||||
_define('blurhash', function() {
|
||||
return blurhash;
|
||||
});
|
||||
|
||||
// query-string
|
||||
var query = require('query-string');
|
||||
const query = require('query-string');
|
||||
_define('queryString', function() {
|
||||
return query;
|
||||
});
|
||||
|
||||
// flvjs
|
||||
var flvjs = require('flv.js/dist/flv').default;
|
||||
const flvjs = require('flv.js/dist/flv').default;
|
||||
_define('flvjs', function() {
|
||||
return flvjs;
|
||||
});
|
||||
|
||||
// jstree
|
||||
var jstree = require('jstree');
|
||||
const jstree = require('jstree');
|
||||
require('jstree/dist/themes/default/style.css');
|
||||
_define('jstree', function() {
|
||||
return jstree;
|
||||
});
|
||||
|
||||
// jquery
|
||||
var jquery = require('jquery');
|
||||
const jquery = require('jquery');
|
||||
_define('jQuery', function() {
|
||||
return jquery;
|
||||
});
|
||||
|
||||
// hlsjs
|
||||
var hlsjs = require('hls.js');
|
||||
const hlsjs = require('hls.js');
|
||||
_define('hlsjs', function() {
|
||||
return hlsjs;
|
||||
});
|
||||
|
||||
// howler
|
||||
var howler = require('howler');
|
||||
const howler = require('howler');
|
||||
_define('howler', function() {
|
||||
return howler;
|
||||
});
|
||||
|
||||
// resize-observer-polyfill
|
||||
var resize = require('resize-observer-polyfill').default;
|
||||
const resize = require('resize-observer-polyfill').default;
|
||||
_define('resize-observer-polyfill', function() {
|
||||
return resize;
|
||||
});
|
||||
|
||||
// shaka
|
||||
var shaka = require('shaka-player');
|
||||
_define('shaka', function() {
|
||||
return shaka;
|
||||
});
|
||||
|
||||
// swiper
|
||||
var swiper = require('swiper/js/swiper');
|
||||
require('swiper/css/swiper.min.css');
|
||||
const swiper = require('swiper/swiper-bundle');
|
||||
require('swiper/swiper-bundle.css');
|
||||
_define('swiper', function() {
|
||||
return swiper;
|
||||
});
|
||||
|
||||
// sortable
|
||||
var sortable = require('sortablejs').default;
|
||||
const sortable = require('sortablejs').default;
|
||||
_define('sortable', function() {
|
||||
return sortable;
|
||||
});
|
||||
|
||||
// webcomponents
|
||||
var webcomponents = require('webcomponents.js/webcomponents-lite');
|
||||
const webcomponents = require('webcomponents.js/webcomponents-lite');
|
||||
_define('webcomponents', function() {
|
||||
return webcomponents;
|
||||
});
|
||||
|
||||
// libass-wasm
|
||||
var libassWasm = require('libass-wasm');
|
||||
const libassWasm = require('libass-wasm');
|
||||
_define('JavascriptSubtitlesOctopus', function() {
|
||||
return libassWasm;
|
||||
});
|
||||
|
||||
// material-icons
|
||||
var materialIcons = require('material-design-icons-iconfont/dist/material-design-icons.css');
|
||||
const materialIcons = require('material-design-icons-iconfont/dist/material-design-icons.css');
|
||||
_define('material-icons', function() {
|
||||
return materialIcons;
|
||||
});
|
||||
|
||||
// noto font
|
||||
var noto = require('jellyfin-noto');
|
||||
const noto = require('jellyfin-noto');
|
||||
_define('jellyfin-noto', function () {
|
||||
return noto;
|
||||
});
|
||||
|
||||
var epubjs = require('epubjs');
|
||||
const epubjs = require('epubjs');
|
||||
_define('epubjs', function () {
|
||||
return epubjs;
|
||||
});
|
||||
|
||||
// page.js
|
||||
var page = require('page');
|
||||
const page = require('page');
|
||||
_define('page', function() {
|
||||
return page;
|
||||
});
|
||||
|
||||
// core-js
|
||||
var polyfill = require('@babel/polyfill/dist/polyfill');
|
||||
const polyfill = require('@babel/polyfill/dist/polyfill');
|
||||
_define('polyfill', function () {
|
||||
return polyfill;
|
||||
});
|
||||
|
||||
// domtokenlist-shim
|
||||
var classlist = require('classlist.js');
|
||||
const classlist = require('classlist.js');
|
||||
_define('classlist-polyfill', function () {
|
||||
return classlist;
|
||||
});
|
||||
|
||||
// Date-FNS
|
||||
var dateFns = require('date-fns');
|
||||
const dateFns = require('date-fns');
|
||||
_define('date-fns', function () {
|
||||
return dateFns;
|
||||
});
|
||||
|
||||
var dateFnsLocale = require('date-fns/locale');
|
||||
const dateFnsLocale = require('date-fns/locale');
|
||||
_define('date-fns/locale', function () {
|
||||
return dateFnsLocale;
|
||||
});
|
||||
|
||||
var fast_text_encoding = require('fast-text-encoding');
|
||||
const fast_text_encoding = require('fast-text-encoding');
|
||||
_define('fast-text-encoding', function () {
|
||||
return fast_text_encoding;
|
||||
});
|
||||
|
||||
// intersection-observer
|
||||
var intersection_observer = require('intersection-observer');
|
||||
const intersection_observer = require('intersection-observer');
|
||||
_define('intersection-observer', function () {
|
||||
return intersection_observer;
|
||||
});
|
||||
|
||||
// screenfull
|
||||
var screenfull = require('screenfull');
|
||||
const screenfull = require('screenfull');
|
||||
_define('screenfull', function () {
|
||||
return screenfull;
|
||||
});
|
||||
|
||||
// headroom.js
|
||||
var headroom = require('headroom.js/dist/headroom');
|
||||
const headroom = require('headroom.js/dist/headroom');
|
||||
_define('headroom', function () {
|
||||
return headroom;
|
||||
});
|
||||
|
||||
// apiclient
|
||||
var apiclient = require('jellyfin-apiclient');
|
||||
const apiclient = require('jellyfin-apiclient');
|
||||
|
||||
_define('apiclient', function () {
|
||||
return apiclient.ApiClient;
|
||||
@@ -181,3 +175,9 @@ _define('connectionManagerFactory', function () {
|
||||
_define('appStorage', function () {
|
||||
return apiclient.AppStorage;
|
||||
});
|
||||
|
||||
// libarchive.js
|
||||
var libarchive = require('libarchive.js');
|
||||
_define('libarchive', function () {
|
||||
return libarchive;
|
||||
});
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-button-light', 'formDialogStyle'], function (dialogHelper, datetime, globalize) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for controlling user parental control from.
|
||||
* @module components/accessSchedule/accessSchedule
|
||||
*/
|
||||
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import datetime from 'datetime';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-select';
|
||||
import 'paper-icon-button-light';
|
||||
import 'formDialogStyle';
|
||||
|
||||
function getDisplayTime(hours) {
|
||||
var minutes = 0;
|
||||
var pct = hours % 1;
|
||||
let minutes = 0;
|
||||
const pct = hours % 1;
|
||||
|
||||
if (pct) {
|
||||
minutes = parseInt(60 * pct);
|
||||
@@ -13,32 +24,32 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt
|
||||
}
|
||||
|
||||
function populateHours(context) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
for (var i = 0; i < 24; i++) {
|
||||
html += '<option value="' + i + '">' + getDisplayTime(i) + '</option>';
|
||||
for (let i = 0; i < 24; i++) {
|
||||
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('#selectEnd').innerHTML = html;
|
||||
}
|
||||
|
||||
function loadSchedule(context, schedule) {
|
||||
context.querySelector('#selectDay').value = schedule.DayOfWeek || 'Sunday';
|
||||
context.querySelector('#selectStart').value = schedule.StartHour || 0;
|
||||
context.querySelector('#selectEnd').value = schedule.EndHour || 0;
|
||||
function loadSchedule(context, {DayOfWeek, StartHour, EndHour}) {
|
||||
context.querySelector('#selectDay').value = DayOfWeek || 'Sunday';
|
||||
context.querySelector('#selectStart').value = StartHour || 0;
|
||||
context.querySelector('#selectEnd').value = EndHour || 0;
|
||||
}
|
||||
|
||||
function submitSchedule(context, options) {
|
||||
var updatedSchedule = {
|
||||
const updatedSchedule = {
|
||||
DayOfWeek: context.querySelector('#selectDay').value,
|
||||
StartHour: context.querySelector('#selectStart').value,
|
||||
EndHour: context.querySelector('#selectEnd').value
|
||||
};
|
||||
|
||||
if (parseFloat(updatedSchedule.StartHour) >= parseFloat(updatedSchedule.EndHour)) {
|
||||
return void alert(globalize.translate('ErrorMessageStartHourGreaterThanEnd'));
|
||||
return void alert(globalize.translate('ErrorStartHourGreaterThanEnd'));
|
||||
}
|
||||
|
||||
context.submitted = true;
|
||||
@@ -46,44 +57,41 @@ define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-butt
|
||||
dialogHelper.close(context);
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'components/accessSchedule/accessSchedule.template.html', true);
|
||||
|
||||
xhr.onload = function (e) {
|
||||
var template = this.response;
|
||||
var dlg = dialogHelper.createDialog({
|
||||
removeOnClose: true,
|
||||
size: 'small'
|
||||
});
|
||||
dlg.classList.add('formDialog');
|
||||
var html = '';
|
||||
html += globalize.translateDocument(template);
|
||||
dlg.innerHTML = html;
|
||||
populateHours(dlg);
|
||||
loadSchedule(dlg, options.schedule);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.addEventListener('close', function () {
|
||||
if (dlg.submitted) {
|
||||
resolve(options.schedule);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
dlg.querySelector('form').addEventListener('submit', function (event) {
|
||||
submitSchedule(dlg, options);
|
||||
event.preventDefault();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
export function show(options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
import('text!./accessSchedule.template.html').then(({default: template}) => {
|
||||
const dlg = dialogHelper.createDialog({
|
||||
removeOnClose: true,
|
||||
size: 'small'
|
||||
});
|
||||
dlg.classList.add('formDialog');
|
||||
let html = '';
|
||||
html += globalize.translateHtml(template);
|
||||
dlg.innerHTML = html;
|
||||
populateHours(dlg);
|
||||
loadSchedule(dlg, options.schedule);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.addEventListener('close', () => {
|
||||
if (dlg.submitted) {
|
||||
resolve(options.schedule);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
dlg.querySelector('form').addEventListener('submit', event => {
|
||||
submitSchedule(dlg, options);
|
||||
event.preventDefault();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${Previous}" tabindex="-1">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectDay" label="${LabelAccessDay}">
|
||||
<option value="Sunday">${OptionSunday}</option>
|
||||
<option value="Monday">${OptionMonday}</option>
|
||||
<option value="Tuesday">${OptionTuesday}</option>
|
||||
<option value="Wednesday">${OptionWednesday}</option>
|
||||
<option value="Thursday">${OptionThursday}</option>
|
||||
<option value="Friday">${OptionFriday}</option>
|
||||
<option value="Saturday">${OptionSaturday}</option>
|
||||
<option value="Sunday">${Sunday}</option>
|
||||
<option value="Monday">${Monday}</option>
|
||||
<option value="Tuesday">${Tuesday}</option>
|
||||
<option value="Wednesday">${Wednesday}</option>
|
||||
<option value="Thursday">${Thursday}</option>
|
||||
<option value="Friday">${Friday}</option>
|
||||
<option value="Saturday">${Saturday}</option>
|
||||
<option value="Everyday">${OptionEveryday}</option>
|
||||
<option value="Weekday">${OptionWeekdays}</option>
|
||||
<option value="Weekend">${OptionWeekends}</option>
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
<div class="formDialogFooter">
|
||||
<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">
|
||||
<span>${ButtonAdd}</span>
|
||||
<span>${Add}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -9,15 +9,14 @@ import 'scrollStyles';
|
||||
import 'listViewStyle';
|
||||
|
||||
function getOffsets(elems) {
|
||||
|
||||
let results = [];
|
||||
const results = [];
|
||||
|
||||
if (!document) {
|
||||
return results;
|
||||
}
|
||||
|
||||
for (let elem of elems) {
|
||||
let box = elem.getBoundingClientRect();
|
||||
for (const elem of elems) {
|
||||
const box = elem.getBoundingClientRect();
|
||||
|
||||
results.push({
|
||||
top: box.top,
|
||||
@@ -31,12 +30,11 @@ function getOffsets(elems) {
|
||||
}
|
||||
|
||||
function getPosition(options, dlg) {
|
||||
|
||||
const windowSize = dom.getWindowSize();
|
||||
const windowHeight = windowSize.innerHeight;
|
||||
const windowWidth = windowSize.innerWidth;
|
||||
|
||||
let pos = getOffsets([options.positionTo])[0];
|
||||
const pos = getOffsets([options.positionTo])[0];
|
||||
|
||||
if (options.positionY !== 'top') {
|
||||
pos.top += (pos.height || 0) / 2;
|
||||
@@ -73,19 +71,18 @@ function getPosition(options, dlg) {
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
import('scrollHelper').then(({default: scrollHelper}) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
export function show(options) {
|
||||
|
||||
// items
|
||||
// positionTo
|
||||
// showCancel
|
||||
// title
|
||||
let dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
enableHistory: options.enableHistory,
|
||||
scrollY: false
|
||||
@@ -98,7 +95,6 @@ export function show(options) {
|
||||
isFullscreen = true;
|
||||
dialogOptions.autoFocus = true;
|
||||
} else {
|
||||
|
||||
dialogOptions.modal = false;
|
||||
dialogOptions.entryAnimation = options.entryAnimation;
|
||||
dialogOptions.exitAnimation = options.exitAnimation;
|
||||
@@ -107,7 +103,7 @@ export function show(options) {
|
||||
dialogOptions.autoFocus = false;
|
||||
}
|
||||
|
||||
let dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
if (isFullscreen) {
|
||||
dlg.classList.add('actionsheet-fullscreen');
|
||||
@@ -133,10 +129,9 @@ export function show(options) {
|
||||
}
|
||||
|
||||
let renderIcon = false;
|
||||
let icons = [];
|
||||
const icons = [];
|
||||
let itemIcon;
|
||||
for (let item of options.items) {
|
||||
|
||||
for (const item of options.items) {
|
||||
itemIcon = item.icon || (item.selected ? 'check' : null);
|
||||
|
||||
if (itemIcon) {
|
||||
@@ -161,7 +156,6 @@ export function show(options) {
|
||||
}
|
||||
|
||||
if (options.title) {
|
||||
|
||||
html += '<h1 class="actionSheetTitle">' + options.title + '</h1>';
|
||||
}
|
||||
if (options.text) {
|
||||
@@ -197,7 +191,6 @@ export function show(options) {
|
||||
const item = options.items[i];
|
||||
|
||||
if (item.divider) {
|
||||
|
||||
html += '<div class="actionsheetDivider"></div>';
|
||||
continue;
|
||||
}
|
||||
@@ -248,15 +241,13 @@ export function show(options) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
|
||||
}
|
||||
|
||||
let btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
const btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
if (btnCloseActionSheet) {
|
||||
btnCloseActionSheet.addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
||||
// Seeing an issue in some non-chrome browsers where this is requiring a double click
|
||||
//var eventName = browser.firefox ? 'mousedown' : 'click';
|
||||
let selectedId;
|
||||
|
||||
let timeout;
|
||||
@@ -267,26 +258,20 @@ export function show(options) {
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
let isResolved;
|
||||
|
||||
dlg.addEventListener('click', function (e) {
|
||||
|
||||
const actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
|
||||
|
||||
if (actionSheetMenuItem) {
|
||||
selectedId = actionSheetMenuItem.getAttribute('data-id');
|
||||
|
||||
if (options.resolveOnClick) {
|
||||
|
||||
if (options.resolveOnClick.indexOf) {
|
||||
|
||||
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
|
||||
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
@@ -295,11 +280,9 @@ export function show(options) {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings', 'serverNotifications', 'connectionManager', 'emby-button', 'listViewStyle'], function (events, globalize, dom, datefns, dfnshelper, userSettings, serverNotifications, connectionManager) {
|
||||
'use strict';
|
||||
import events from 'events';
|
||||
import globalize from 'globalize';
|
||||
import dom from 'dom';
|
||||
import * as datefns from 'date-fns';
|
||||
import dfnshelper from 'dfnshelper';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import 'emby-button';
|
||||
import 'listViewStyle';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function getEntryHtml(entry, apiClient) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
html += '<div class="listItem listItem-border">';
|
||||
var color = '#00a4dc';
|
||||
var icon = 'notifications';
|
||||
let color = '#00a4dc';
|
||||
let icon = 'notifications';
|
||||
|
||||
if ('Error' == entry.Severity || 'Fatal' == entry.Severity || 'Warn' == entry.Severity) {
|
||||
if (entry.Severity == 'Error' || entry.Severity == 'Fatal' || entry.Severity == 'Warn') {
|
||||
color = '#cc0000';
|
||||
icon = 'notification_important';
|
||||
}
|
||||
@@ -51,14 +59,15 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
|
||||
}
|
||||
|
||||
function reloadData(instance, elem, apiClient, startIndex, limit) {
|
||||
if (null == startIndex) {
|
||||
if (startIndex == null) {
|
||||
startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0');
|
||||
}
|
||||
|
||||
limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7');
|
||||
var minDate = new Date();
|
||||
var hasUserId = 'false' !== elem.getAttribute('data-useractivity');
|
||||
const minDate = new Date();
|
||||
const hasUserId = elem.getAttribute('data-useractivity') !== 'false';
|
||||
|
||||
// TODO: Use date-fns
|
||||
if (hasUserId) {
|
||||
minDate.setTime(minDate.getTime() - 24 * 60 * 60 * 1000); // one day back
|
||||
} else {
|
||||
@@ -74,7 +83,7 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
|
||||
elem.setAttribute('data-activitystartindex', startIndex);
|
||||
elem.setAttribute('data-activitylimit', limit);
|
||||
if (!startIndex) {
|
||||
var activityContainer = dom.parentWithClass(elem, 'activityContainer');
|
||||
const activityContainer = dom.parentWithClass(elem, 'activityContainer');
|
||||
|
||||
if (activityContainer) {
|
||||
if (result.Items.length) {
|
||||
@@ -91,7 +100,7 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
|
||||
}
|
||||
|
||||
function onActivityLogUpdate(e, apiClient, data) {
|
||||
var options = this.options;
|
||||
const options = this.options;
|
||||
|
||||
if (options && options.serverId === apiClient.serverId()) {
|
||||
reloadData(this, options.element, apiClient);
|
||||
@@ -99,14 +108,14 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
|
||||
}
|
||||
|
||||
function onListClick(e) {
|
||||
var btnEntryInfo = dom.parentWithClass(e.target, 'btnEntryInfo');
|
||||
const btnEntryInfo = dom.parentWithClass(e.target, 'btnEntryInfo');
|
||||
|
||||
if (btnEntryInfo) {
|
||||
var id = btnEntryInfo.getAttribute('data-id');
|
||||
var items = this.items;
|
||||
const id = btnEntryInfo.getAttribute('data-id');
|
||||
const items = this.items;
|
||||
|
||||
if (items) {
|
||||
var item = items.filter(function (i) {
|
||||
const item = items.filter(function (i) {
|
||||
return i.Id.toString() === id;
|
||||
})[0];
|
||||
|
||||
@@ -118,35 +127,35 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
|
||||
}
|
||||
|
||||
function showItemOverview(item) {
|
||||
require(['alert'], function (alert) {
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert({
|
||||
text: item.Overview
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function ActivityLog(options) {
|
||||
class ActivityLog {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
var element = options.element;
|
||||
const element = options.element;
|
||||
element.classList.add('activityLogListWidget');
|
||||
element.addEventListener('click', onListClick.bind(this));
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
reloadData(this, element, apiClient);
|
||||
var onUpdate = onActivityLogUpdate.bind(this);
|
||||
const onUpdate = onActivityLogUpdate.bind(this);
|
||||
this.updateFn = onUpdate;
|
||||
events.on(serverNotifications, 'ActivityLogEntry', onUpdate);
|
||||
apiClient.sendMessage('ActivityLogEntryStart', '0,1500');
|
||||
}
|
||||
|
||||
ActivityLog.prototype.destroy = function () {
|
||||
var options = this.options;
|
||||
destroy() {
|
||||
const options = this.options;
|
||||
|
||||
if (options) {
|
||||
options.element.classList.remove('activityLogListWidget');
|
||||
connectionManager.getApiClient(options.serverId).sendMessage('ActivityLogEntryStop', '0,1500');
|
||||
window.connectionManager.getApiClient(options.serverId).sendMessage('ActivityLogEntryStop', '0,1500');
|
||||
}
|
||||
|
||||
var onUpdate = this.updateFn;
|
||||
const onUpdate = this.updateFn;
|
||||
|
||||
if (onUpdate) {
|
||||
events.off(serverNotifications, 'ActivityLogEntry', onUpdate);
|
||||
@@ -154,7 +163,9 @@ define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings',
|
||||
|
||||
this.items = null;
|
||||
this.options = null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return ActivityLog;
|
||||
});
|
||||
export default ActivityLog;
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
+13
-10
@@ -1,14 +1,16 @@
|
||||
define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
import dialog from 'dialog';
|
||||
import globalize from 'globalize';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var reg = new RegExp(strReplace, 'ig');
|
||||
const reg = new RegExp(strReplace, 'ig');
|
||||
return originalString.replace(reg, strWith);
|
||||
}
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
export default function (text, title) {
|
||||
let options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
@@ -21,7 +23,7 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
|
||||
if (browser.tv && window.alert) {
|
||||
alert(replaceAll(options.text || '', '<br/>', '\n'));
|
||||
} else {
|
||||
var items = [];
|
||||
const items = [];
|
||||
|
||||
items.push({
|
||||
name: globalize.translate('ButtonGotIt'),
|
||||
@@ -31,7 +33,7 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
return dialog(options).then(function (result) {
|
||||
return dialog.show(options).then(function (result) {
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -41,5 +43,6 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-button-light', 'material-icons'], function (focusManager, layoutManager, dom) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
var selectedButtonClass = 'alphaPickerButton-selected';
|
||||
/**
|
||||
* Module alphaPicker.
|
||||
* @module components/alphaPicker/alphaPicker
|
||||
*/
|
||||
|
||||
import focusManager from 'focusManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import dom from 'dom';
|
||||
import 'css!./style.css';
|
||||
import 'paper-icon-button-light';
|
||||
import 'material-icons';
|
||||
|
||||
const selectedButtonClass = 'alphaPickerButton-selected';
|
||||
|
||||
function focus() {
|
||||
var scope = this;
|
||||
var selected = scope.querySelector('.' + selectedButtonClass);
|
||||
const scope = this;
|
||||
const selected = scope.querySelector(`.${selectedButtonClass}`);
|
||||
|
||||
if (selected) {
|
||||
focusManager.focus(selected);
|
||||
@@ -15,8 +26,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
}
|
||||
|
||||
function getAlphaPickerButtonClassName(vertical) {
|
||||
|
||||
var alphaPickerButtonClassName = 'alphaPickerButton';
|
||||
let alphaPickerButtonClassName = 'alphaPickerButton';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
alphaPickerButtonClassName += ' alphaPickerButton-tv';
|
||||
@@ -30,44 +40,42 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
}
|
||||
|
||||
function getLetterButton(l, vertical) {
|
||||
return '<button data-value="' + l + '" class="' + getAlphaPickerButtonClassName(vertical) + '">' + l + '</button>';
|
||||
return `<button data-value="${l}" class="${getAlphaPickerButtonClassName(vertical)}">${l}</button>`;
|
||||
}
|
||||
|
||||
function mapLetters(letters, vertical) {
|
||||
|
||||
return letters.map(function (l) {
|
||||
return letters.map(l => {
|
||||
return getLetterButton(l, vertical);
|
||||
});
|
||||
}
|
||||
|
||||
function render(element, options) {
|
||||
|
||||
element.classList.add('alphaPicker');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
element.classList.add('alphaPicker-tv');
|
||||
}
|
||||
|
||||
var vertical = element.classList.contains('alphaPicker-vertical');
|
||||
const vertical = element.classList.contains('alphaPicker-vertical');
|
||||
|
||||
if (!vertical) {
|
||||
element.classList.add('focuscontainer-x');
|
||||
}
|
||||
|
||||
var html = '';
|
||||
var letters;
|
||||
let html = '';
|
||||
let letters;
|
||||
|
||||
var alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical);
|
||||
const alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical);
|
||||
|
||||
var rowClassName = 'alphaPickerRow';
|
||||
let rowClassName = 'alphaPickerRow';
|
||||
|
||||
if (vertical) {
|
||||
rowClassName += ' alphaPickerRow-vertical';
|
||||
}
|
||||
|
||||
html += '<div class="' + rowClassName + '">';
|
||||
html += `<div class="${rowClassName}">`;
|
||||
if (options.mode === 'keyboard') {
|
||||
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><span class="material-icons alphaPickerButtonIcon space_bar"></span></button>';
|
||||
html += `<button data-value=" " is="paper-icon-button-light" class="${alphaPickerButtonClassName}"><span class="material-icons alphaPickerButtonIcon space_bar"></span></button>`;
|
||||
} else {
|
||||
letters = ['#'];
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
@@ -77,11 +85,11 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
|
||||
if (options.mode === 'keyboard') {
|
||||
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><span class="material-icons alphaPickerButtonIcon backspace"></span></button>';
|
||||
html += `<button data-value="backspace" is="paper-icon-button-light" class="${alphaPickerButtonClassName}"><span class="material-icons alphaPickerButtonIcon backspace"></span></button>`;
|
||||
html += '</div>';
|
||||
|
||||
letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
html += '<div class="' + rowClassName + '">';
|
||||
html += `<div class="${rowClassName}">`;
|
||||
html += '<br/>';
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
html += '</div>';
|
||||
@@ -95,227 +103,211 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
element.focus = focus;
|
||||
}
|
||||
|
||||
function AlphaPicker(options) {
|
||||
export class AlphaPicker {
|
||||
constructor(options) {
|
||||
const self = this;
|
||||
|
||||
var self = this;
|
||||
this.options = options;
|
||||
this.options = options;
|
||||
|
||||
var element = options.element;
|
||||
var itemsContainer = options.itemsContainer;
|
||||
var itemClass = options.itemClass;
|
||||
const element = options.element;
|
||||
const itemsContainer = options.itemsContainer;
|
||||
const itemClass = options.itemClass;
|
||||
|
||||
var itemFocusValue;
|
||||
var itemFocusTimeout;
|
||||
let itemFocusValue;
|
||||
let itemFocusTimeout;
|
||||
|
||||
function onItemFocusTimeout() {
|
||||
itemFocusTimeout = null;
|
||||
self.value(itemFocusValue);
|
||||
}
|
||||
|
||||
var alphaFocusedElement;
|
||||
var alphaFocusTimeout;
|
||||
|
||||
function onAlphaFocusTimeout() {
|
||||
|
||||
alphaFocusTimeout = null;
|
||||
|
||||
if (document.activeElement === alphaFocusedElement) {
|
||||
var value = alphaFocusedElement.getAttribute('data-value');
|
||||
self.value(value, true);
|
||||
function onItemFocusTimeout() {
|
||||
itemFocusTimeout = null;
|
||||
self.value(itemFocusValue);
|
||||
}
|
||||
}
|
||||
|
||||
function onAlphaPickerInKeyboardModeClick(e) {
|
||||
let alphaFocusedElement;
|
||||
let alphaFocusTimeout;
|
||||
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
function onAlphaFocusTimeout() {
|
||||
alphaFocusTimeout = null;
|
||||
|
||||
if (alphaPickerButton) {
|
||||
var value = alphaPickerButton.getAttribute('data-value');
|
||||
|
||||
element.dispatchEvent(new CustomEvent('alphavalueclicked', {
|
||||
cancelable: false,
|
||||
detail: {
|
||||
value: value
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function onAlphaPickerClick(e) {
|
||||
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
var value = alphaPickerButton.getAttribute('data-value');
|
||||
if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
|
||||
self.value(null, true);
|
||||
} else {
|
||||
if (document.activeElement === alphaFocusedElement) {
|
||||
const value = alphaFocusedElement.getAttribute('data-value');
|
||||
self.value(value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onAlphaPickerFocusIn(e) {
|
||||
function onAlphaPickerInKeyboardModeClick(e) {
|
||||
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaFocusTimeout) {
|
||||
clearTimeout(alphaFocusTimeout);
|
||||
alphaFocusTimeout = null;
|
||||
if (alphaPickerButton) {
|
||||
const value = alphaPickerButton.getAttribute('data-value');
|
||||
|
||||
element.dispatchEvent(new CustomEvent('alphavalueclicked', {
|
||||
cancelable: false,
|
||||
detail: {
|
||||
value
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
function onAlphaPickerClick(e) {
|
||||
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (alphaPickerButton) {
|
||||
alphaFocusedElement = alphaPickerButton;
|
||||
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
|
||||
}
|
||||
}
|
||||
|
||||
function onItemsFocusIn(e) {
|
||||
|
||||
var item = dom.parentWithClass(e.target, itemClass);
|
||||
|
||||
if (item) {
|
||||
var prefix = item.getAttribute('data-prefix');
|
||||
if (prefix && prefix.length) {
|
||||
|
||||
itemFocusValue = prefix[0];
|
||||
if (itemFocusTimeout) {
|
||||
clearTimeout(itemFocusTimeout);
|
||||
if (alphaPickerButton) {
|
||||
const value = alphaPickerButton.getAttribute('data-value');
|
||||
if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
|
||||
this.value(null, true);
|
||||
} else {
|
||||
this.value(value, true);
|
||||
}
|
||||
itemFocusTimeout = setTimeout(onItemFocusTimeout, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.enabled = function (enabled) {
|
||||
|
||||
if (enabled) {
|
||||
|
||||
if (itemsContainer) {
|
||||
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
|
||||
function onAlphaPickerFocusIn(e) {
|
||||
if (alphaFocusTimeout) {
|
||||
clearTimeout(alphaFocusTimeout);
|
||||
alphaFocusTimeout = null;
|
||||
}
|
||||
|
||||
if (options.mode === 'keyboard') {
|
||||
element.addEventListener('click', onAlphaPickerInKeyboardModeClick);
|
||||
}
|
||||
const alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
|
||||
|
||||
if (options.valueChangeEvent !== 'click') {
|
||||
element.addEventListener('focus', onAlphaPickerFocusIn, true);
|
||||
if (alphaPickerButton) {
|
||||
alphaFocusedElement = alphaPickerButton;
|
||||
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
|
||||
}
|
||||
}
|
||||
|
||||
function onItemsFocusIn(e) {
|
||||
const item = dom.parentWithClass(e.target, itemClass);
|
||||
|
||||
if (item) {
|
||||
const prefix = item.getAttribute('data-prefix');
|
||||
if (prefix && prefix.length) {
|
||||
itemFocusValue = prefix[0];
|
||||
if (itemFocusTimeout) {
|
||||
clearTimeout(itemFocusTimeout);
|
||||
}
|
||||
itemFocusTimeout = setTimeout(onItemFocusTimeout, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.enabled = function (enabled) {
|
||||
if (enabled) {
|
||||
if (itemsContainer) {
|
||||
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
|
||||
if (options.mode === 'keyboard') {
|
||||
element.addEventListener('click', onAlphaPickerInKeyboardModeClick);
|
||||
}
|
||||
|
||||
if (options.valueChangeEvent !== 'click') {
|
||||
element.addEventListener('focus', onAlphaPickerFocusIn, true);
|
||||
} else {
|
||||
element.addEventListener('click', onAlphaPickerClick.bind(this));
|
||||
}
|
||||
} else {
|
||||
element.addEventListener('click', onAlphaPickerClick.bind(this));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (itemsContainer) {
|
||||
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
|
||||
element.removeEventListener('click', onAlphaPickerInKeyboardModeClick);
|
||||
element.removeEventListener('focus', onAlphaPickerFocusIn, true);
|
||||
element.removeEventListener('click', onAlphaPickerClick.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
render(element, options);
|
||||
|
||||
this.enabled(true);
|
||||
this.visible(true);
|
||||
}
|
||||
|
||||
AlphaPicker.prototype.value = function (value, applyValue) {
|
||||
|
||||
var element = this.options.element;
|
||||
var btn;
|
||||
var selected;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (value != null) {
|
||||
|
||||
value = value.toUpperCase();
|
||||
this._currentValue = value;
|
||||
|
||||
if (this.options.mode !== 'keyboard') {
|
||||
selected = element.querySelector('.' + selectedButtonClass);
|
||||
|
||||
try {
|
||||
btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']');
|
||||
} catch (err) {
|
||||
console.error('error in querySelector: ' + err);
|
||||
if (itemsContainer) {
|
||||
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
|
||||
}
|
||||
|
||||
if (btn && btn !== selected) {
|
||||
btn.classList.add(selectedButtonClass);
|
||||
element.removeEventListener('click', onAlphaPickerInKeyboardModeClick);
|
||||
element.removeEventListener('focus', onAlphaPickerFocusIn, true);
|
||||
element.removeEventListener('click', onAlphaPickerClick.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
render(element, options);
|
||||
|
||||
this.enabled(true);
|
||||
this.visible(true);
|
||||
}
|
||||
|
||||
value(value, applyValue) {
|
||||
const element = this.options.element;
|
||||
let btn;
|
||||
let selected;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (value != null) {
|
||||
value = value.toUpperCase();
|
||||
this._currentValue = value;
|
||||
|
||||
if (this.options.mode !== 'keyboard') {
|
||||
selected = element.querySelector(`.${selectedButtonClass}`);
|
||||
|
||||
try {
|
||||
btn = element.querySelector(`.alphaPickerButton[data-value='${value}']`);
|
||||
} catch (err) {
|
||||
console.error('error in querySelector:', err);
|
||||
}
|
||||
|
||||
if (btn && btn !== selected) {
|
||||
btn.classList.add(selectedButtonClass);
|
||||
}
|
||||
if (selected && selected !== btn) {
|
||||
selected.classList.remove(selectedButtonClass);
|
||||
}
|
||||
}
|
||||
if (selected && selected !== btn) {
|
||||
} else {
|
||||
this._currentValue = value;
|
||||
|
||||
selected = element.querySelector(`.${selectedButtonClass}`);
|
||||
if (selected) {
|
||||
selected.classList.remove(selectedButtonClass);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this._currentValue = value;
|
||||
|
||||
selected = element.querySelector('.' + selectedButtonClass);
|
||||
if (selected) {
|
||||
selected.classList.remove(selectedButtonClass);
|
||||
}
|
||||
}
|
||||
|
||||
if (applyValue) {
|
||||
element.dispatchEvent(new CustomEvent('alphavaluechanged', {
|
||||
cancelable: false,
|
||||
detail: {
|
||||
value
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
return this._currentValue;
|
||||
}
|
||||
|
||||
if (applyValue) {
|
||||
element.dispatchEvent(new CustomEvent('alphavaluechanged', {
|
||||
cancelable: false,
|
||||
detail: {
|
||||
value: value
|
||||
}
|
||||
}));
|
||||
on(name, fn) {
|
||||
const element = this.options.element;
|
||||
element.addEventListener(name, fn);
|
||||
}
|
||||
|
||||
return this._currentValue;
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.on = function (name, fn) {
|
||||
var element = this.options.element;
|
||||
element.addEventListener(name, fn);
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.off = function (name, fn) {
|
||||
var element = this.options.element;
|
||||
element.removeEventListener(name, fn);
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.visible = function (visible) {
|
||||
|
||||
var element = this.options.element;
|
||||
element.style.visibility = visible ? 'visible' : 'hidden';
|
||||
};
|
||||
|
||||
AlphaPicker.prototype.values = function () {
|
||||
|
||||
var element = this.options.element;
|
||||
var elems = element.querySelectorAll('.alphaPickerButton');
|
||||
var values = [];
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
values.push(elems[i].getAttribute('data-value'));
|
||||
|
||||
off(name, fn) {
|
||||
const element = this.options.element;
|
||||
element.removeEventListener(name, fn);
|
||||
}
|
||||
|
||||
return values;
|
||||
};
|
||||
visible(visible) {
|
||||
const element = this.options.element;
|
||||
element.style.visibility = visible ? 'visible' : 'hidden';
|
||||
}
|
||||
|
||||
AlphaPicker.prototype.focus = function () {
|
||||
values() {
|
||||
const element = this.options.element;
|
||||
const elems = element.querySelectorAll('.alphaPickerButton');
|
||||
const values = [];
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
values.push(elems[i].getAttribute('data-value'));
|
||||
}
|
||||
|
||||
var element = this.options.element;
|
||||
focusManager.autoFocus(element, true);
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
AlphaPicker.prototype.destroy = function () {
|
||||
focus() {
|
||||
const element = this.options.element;
|
||||
focusManager.autoFocus(element, true);
|
||||
}
|
||||
|
||||
var element = this.options.element;
|
||||
this.enabled(false);
|
||||
element.classList.remove('focuscontainer-x');
|
||||
this.options = null;
|
||||
};
|
||||
destroy() {
|
||||
const element = this.options.element;
|
||||
this.enabled(false);
|
||||
element.classList.remove('focuscontainer-x');
|
||||
this.options = null;
|
||||
}
|
||||
}
|
||||
|
||||
return AlphaPicker;
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
export default AlphaPicker;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
define(['browser', 'css!./appFooter'], function (browser) {
|
||||
'use strict';
|
||||
import 'css!./appFooter';
|
||||
|
||||
function render(options) {
|
||||
var elem = document.createElement('div');
|
||||
elem.classList.add('appfooter');
|
||||
function render(options) {
|
||||
const elem = document.createElement('div');
|
||||
elem.classList.add('appfooter');
|
||||
|
||||
document.body.appendChild(elem);
|
||||
document.body.appendChild(elem);
|
||||
|
||||
return elem;
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
function appFooter(options) {
|
||||
var self = this;
|
||||
class appFooter {
|
||||
constructor(options) {
|
||||
const self = this;
|
||||
|
||||
self.element = render(options);
|
||||
self.add = function (elem) {
|
||||
@@ -26,12 +26,11 @@ define(['browser', 'css!./appFooter'], function (browser) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
appFooter.prototype.destroy = function () {
|
||||
destroy() {
|
||||
var self = this;
|
||||
|
||||
self.element = null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return appFooter;
|
||||
});
|
||||
export default appFooter;
|
||||
|
||||
+560
-449
File diff suppressed because it is too large
Load Diff
+361
-405
@@ -1,456 +1,412 @@
|
||||
define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'globalize'], function (appSettings, browser, events, htmlMediaHelper, webSettings, globalize) {
|
||||
'use strict';
|
||||
import appSettings from 'appSettings';
|
||||
import browser from 'browser';
|
||||
import events from 'events';
|
||||
import * as htmlMediaHelper from 'htmlMediaHelper';
|
||||
import * as webSettings from 'webSettings';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function getBaseProfileOptions(item) {
|
||||
var disableHlsVideoAudioCodecs = [];
|
||||
function getBaseProfileOptions(item) {
|
||||
const disableHlsVideoAudioCodecs = [];
|
||||
|
||||
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||
if (browser.edge) {
|
||||
disableHlsVideoAudioCodecs.push('mp3');
|
||||
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
|
||||
if (browser.edge) {
|
||||
disableHlsVideoAudioCodecs.push('mp3');
|
||||
}
|
||||
|
||||
disableHlsVideoAudioCodecs.push('ac3');
|
||||
disableHlsVideoAudioCodecs.push('eac3');
|
||||
disableHlsVideoAudioCodecs.push('opus');
|
||||
}
|
||||
|
||||
return {
|
||||
enableMkvProgressive: false,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
};
|
||||
}
|
||||
|
||||
function getDeviceProfile(item, options = {}) {
|
||||
return new Promise(function (resolve) {
|
||||
import('browserdeviceprofile').then(({default: profileBuilder}) => {
|
||||
let profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
|
||||
} else {
|
||||
const builderOpts = getBaseProfileOptions(item);
|
||||
builderOpts.enableSsaRender = (item && !options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats');
|
||||
profile = profileBuilder(builderOpts);
|
||||
}
|
||||
|
||||
disableHlsVideoAudioCodecs.push('ac3');
|
||||
disableHlsVideoAudioCodecs.push('eac3');
|
||||
disableHlsVideoAudioCodecs.push('opus');
|
||||
}
|
||||
|
||||
return {
|
||||
enableMkvProgressive: false,
|
||||
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
|
||||
};
|
||||
}
|
||||
|
||||
function getDeviceProfileForWindowsUwp(item) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['browserdeviceprofile', 'environments/windows-uwp/mediacaps'], function (profileBuilder, uwpMediaCaps) {
|
||||
var profileOptions = getBaseProfileOptions(item);
|
||||
profileOptions.supportsDts = uwpMediaCaps.supportsDTS();
|
||||
profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby();
|
||||
profileOptions.audioChannels = uwpMediaCaps.getAudioChannels();
|
||||
resolve(profileBuilder(profileOptions));
|
||||
});
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1');
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
const strReplace2 = escapeRegExp(strReplace);
|
||||
const reg = new RegExp(strReplace2, 'ig');
|
||||
return originalString.replace(reg, strWith);
|
||||
}
|
||||
|
||||
function generateDeviceId() {
|
||||
const keys = [];
|
||||
|
||||
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), window.btoa) {
|
||||
const result = replaceAll(btoa(keys.join('|')), '=', '1');
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
function getDeviceProfile(item, options) {
|
||||
options = options || {};
|
||||
return Promise.resolve(new Date().getTime());
|
||||
}
|
||||
|
||||
if (self.Windows) {
|
||||
return getDeviceProfileForWindowsUwp(item);
|
||||
}
|
||||
function getDeviceId() {
|
||||
const key = '_deviceId2';
|
||||
const deviceId = appSettings.get(key);
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
require(['browserdeviceprofile'], function (profileBuilder) {
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
|
||||
} else {
|
||||
var builderOpts = getBaseProfileOptions(item);
|
||||
builderOpts.enableSsaRender = (item && !options.isRetry && 'allcomplexformats' !== appSettings.get('subtitleburnin'));
|
||||
profile = profileBuilder(builderOpts);
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
if (deviceId) {
|
||||
return Promise.resolve(deviceId);
|
||||
}
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
|
||||
return generateDeviceId().then(function (deviceId) {
|
||||
appSettings.set(key, deviceId);
|
||||
return deviceId;
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceName() {
|
||||
var deviceName;
|
||||
if (browser.tizen) {
|
||||
deviceName = 'Samsung Smart TV';
|
||||
} else if (browser.web0s) {
|
||||
deviceName = 'LG Smart TV';
|
||||
} else if (browser.operaTv) {
|
||||
deviceName = 'Opera TV';
|
||||
} else if (browser.xboxOne) {
|
||||
deviceName = 'Xbox One';
|
||||
} else if (browser.ps4) {
|
||||
deviceName = 'Sony PS4';
|
||||
} else if (browser.chrome) {
|
||||
deviceName = 'Chrome';
|
||||
} else if (browser.edgeChromium) {
|
||||
deviceName = 'Edge Chromium';
|
||||
} else if (browser.edge) {
|
||||
deviceName = 'Edge';
|
||||
} else if (browser.firefox) {
|
||||
deviceName = 'Firefox';
|
||||
} else if (browser.opera) {
|
||||
deviceName = 'Opera';
|
||||
} else if (browser.safari) {
|
||||
deviceName = 'Safari';
|
||||
} else {
|
||||
deviceName = 'Web Browser';
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var strReplace2 = escapeRegExp(strReplace);
|
||||
var reg = new RegExp(strReplace2, 'ig');
|
||||
return originalString.replace(reg, strWith);
|
||||
if (browser.ipad) {
|
||||
deviceName += ' iPad';
|
||||
} else if (browser.iphone) {
|
||||
deviceName += ' iPhone';
|
||||
} else if (browser.android) {
|
||||
deviceName += ' Android';
|
||||
}
|
||||
|
||||
function generateDeviceId() {
|
||||
var keys = [];
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), self.btoa) {
|
||||
var result = replaceAll(btoa(keys.join('|')), '=', '1');
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
return Promise.resolve(new Date().getTime());
|
||||
function supportsVoiceInput() {
|
||||
if (!browser.tv) {
|
||||
return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition;
|
||||
}
|
||||
|
||||
function getDeviceId() {
|
||||
var key = '_deviceId2';
|
||||
var deviceId = appSettings.get(key);
|
||||
|
||||
if (deviceId) {
|
||||
return Promise.resolve(deviceId);
|
||||
}
|
||||
|
||||
return generateDeviceId().then(function (deviceId) {
|
||||
appSettings.set(key, deviceId);
|
||||
return deviceId;
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceName() {
|
||||
var deviceName;
|
||||
if (browser.tizen) {
|
||||
deviceName = 'Samsung Smart TV';
|
||||
} else if (browser.web0s) {
|
||||
deviceName = 'LG Smart TV';
|
||||
} else if (browser.operaTv) {
|
||||
deviceName = 'Opera TV';
|
||||
} else if (browser.xboxOne) {
|
||||
deviceName = 'Xbox One';
|
||||
} else if (browser.ps4) {
|
||||
deviceName = 'Sony PS4';
|
||||
} else if (browser.chrome) {
|
||||
deviceName = 'Chrome';
|
||||
} else if (browser.edge) {
|
||||
deviceName = 'Edge';
|
||||
} else if (browser.firefox) {
|
||||
deviceName = 'Firefox';
|
||||
} else if (browser.opera) {
|
||||
deviceName = 'Opera';
|
||||
} else if (browser.safari) {
|
||||
deviceName = 'Safari';
|
||||
} else {
|
||||
deviceName = 'Web Browser';
|
||||
}
|
||||
|
||||
if (browser.ipad) {
|
||||
deviceName += ' iPad';
|
||||
} else if (browser.iphone) {
|
||||
deviceName += ' iPhone';
|
||||
} else if (browser.android) {
|
||||
deviceName += ' Android';
|
||||
}
|
||||
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
function supportsVoiceInput() {
|
||||
if (!browser.tv) {
|
||||
return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function supportsFullscreen() {
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function supportsFullscreen() {
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
const element = document.documentElement;
|
||||
return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement('video').webkitEnterFullscreen;
|
||||
}
|
||||
|
||||
var element = document.documentElement;
|
||||
return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement('video').webkitEnterFullscreen;
|
||||
}
|
||||
|
||||
function getSyncProfile() {
|
||||
return new Promise(function (resolve) {
|
||||
require(['browserdeviceprofile', 'appSettings'], function (profileBuilder, appSettings) {
|
||||
var profile;
|
||||
|
||||
if (window.NativeShell) {
|
||||
profile = window.NativeShell.AppHost.getSyncProfile(profileBuilder, appSettings);
|
||||
} else {
|
||||
profile = profileBuilder();
|
||||
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate();
|
||||
}
|
||||
|
||||
resolve(profile);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDefaultLayout() {
|
||||
return 'desktop';
|
||||
}
|
||||
|
||||
function supportsHtmlMediaAutoplay() {
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browser.mobile) {
|
||||
return false;
|
||||
}
|
||||
function getDefaultLayout() {
|
||||
return 'desktop';
|
||||
}
|
||||
|
||||
function supportsHtmlMediaAutoplay() {
|
||||
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function supportsCue() {
|
||||
try {
|
||||
var video = document.createElement('video');
|
||||
var style = document.createElement('style');
|
||||
|
||||
style.textContent = 'video::cue {background: inherit}';
|
||||
document.body.appendChild(style);
|
||||
document.body.appendChild(video);
|
||||
|
||||
var cue = window.getComputedStyle(video, '::cue').background;
|
||||
document.body.removeChild(style);
|
||||
document.body.removeChild(video);
|
||||
|
||||
return !!cue.length;
|
||||
} catch (err) {
|
||||
console.error('error detecting cue support: ' + err);
|
||||
return false;
|
||||
}
|
||||
if (browser.mobile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function onAppVisible() {
|
||||
if (isHidden) {
|
||||
isHidden = false;
|
||||
console.debug('triggering app resume event');
|
||||
events.trigger(appHost, 'resume');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function supportsCue() {
|
||||
try {
|
||||
const video = document.createElement('video');
|
||||
const style = document.createElement('style');
|
||||
|
||||
style.textContent = 'video::cue {background: inherit}';
|
||||
document.body.appendChild(style);
|
||||
document.body.appendChild(video);
|
||||
|
||||
const cue = window.getComputedStyle(video, '::cue').background;
|
||||
document.body.removeChild(style);
|
||||
document.body.removeChild(video);
|
||||
|
||||
return !!cue.length;
|
||||
} catch (err) {
|
||||
console.error('error detecting cue support: ' + err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function onAppVisible() {
|
||||
if (isHidden) {
|
||||
isHidden = false;
|
||||
console.debug('triggering app resume event');
|
||||
events.trigger(appHost, 'resume');
|
||||
}
|
||||
}
|
||||
|
||||
function onAppHidden() {
|
||||
if (!isHidden) {
|
||||
isHidden = true;
|
||||
console.debug('app is hidden');
|
||||
}
|
||||
}
|
||||
|
||||
const supportedFeatures = function () {
|
||||
const features = [];
|
||||
|
||||
if (navigator.share) {
|
||||
features.push('sharing');
|
||||
}
|
||||
|
||||
function onAppHidden() {
|
||||
if (!isHidden) {
|
||||
isHidden = true;
|
||||
console.debug('app is hidden');
|
||||
}
|
||||
if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push('filedownload');
|
||||
}
|
||||
|
||||
var supportedFeatures = function () {
|
||||
var features = [];
|
||||
if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) {
|
||||
features.push('exit');
|
||||
} else {
|
||||
features.push('exitmenu');
|
||||
features.push('plugins');
|
||||
}
|
||||
|
||||
if (navigator.share) {
|
||||
features.push('sharing');
|
||||
}
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.ps4) {
|
||||
features.push('externallinks');
|
||||
features.push('externalpremium');
|
||||
}
|
||||
|
||||
if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push('filedownload');
|
||||
}
|
||||
if (!browser.operaTv) {
|
||||
features.push('externallinkdisplay');
|
||||
}
|
||||
|
||||
if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) {
|
||||
features.push('exit');
|
||||
if (supportsVoiceInput()) {
|
||||
features.push('voiceinput');
|
||||
}
|
||||
|
||||
if (supportsHtmlMediaAutoplay()) {
|
||||
features.push('htmlaudioautoplay');
|
||||
features.push('htmlvideoautoplay');
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
features.push('sync');
|
||||
}
|
||||
|
||||
if (supportsFullscreen()) {
|
||||
features.push('fullscreenchange');
|
||||
}
|
||||
|
||||
if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
|
||||
features.push('physicalvolumecontrol');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push('remotecontrol');
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.edgeUwp) {
|
||||
features.push('remotevideo');
|
||||
}
|
||||
|
||||
features.push('displaylanguage');
|
||||
features.push('otherapppromotions');
|
||||
features.push('displaymode');
|
||||
features.push('targetblank');
|
||||
features.push('screensaver');
|
||||
|
||||
webSettings.getMultiServer().then(enabled => {
|
||||
if (enabled) features.push('multiserver');
|
||||
});
|
||||
|
||||
if (!browser.orsay && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
|
||||
features.push('subtitleappearancesettings');
|
||||
}
|
||||
|
||||
if (!browser.orsay) {
|
||||
features.push('subtitleburnsettings');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.ps4 && !browser.xboxOne) {
|
||||
features.push('fileinput');
|
||||
}
|
||||
|
||||
if (browser.chrome || browser.edgeChromium) {
|
||||
features.push('chromecast');
|
||||
}
|
||||
|
||||
return features;
|
||||
}();
|
||||
|
||||
/**
|
||||
* Do exit according to platform
|
||||
*/
|
||||
function doExit() {
|
||||
try {
|
||||
if (window.NativeShell) {
|
||||
window.NativeShell.AppHost.exit();
|
||||
} else if (browser.tizen) {
|
||||
tizen.application.getCurrentApplication().exit();
|
||||
} else if (browser.web0s) {
|
||||
webOS.platformBack();
|
||||
} else {
|
||||
features.push('exitmenu');
|
||||
features.push('plugins');
|
||||
window.close();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('error closing application: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.ps4) {
|
||||
features.push('externallinks');
|
||||
features.push('externalpremium');
|
||||
}
|
||||
let exitPromise;
|
||||
|
||||
if (!browser.operaTv) {
|
||||
features.push('externallinkdisplay');
|
||||
}
|
||||
|
||||
if (supportsVoiceInput()) {
|
||||
features.push('voiceinput');
|
||||
}
|
||||
|
||||
if (supportsHtmlMediaAutoplay()) {
|
||||
features.push('htmlaudioautoplay');
|
||||
features.push('htmlvideoautoplay');
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
features.push('sync');
|
||||
}
|
||||
|
||||
if (supportsFullscreen()) {
|
||||
features.push('fullscreenchange');
|
||||
}
|
||||
|
||||
if (browser.chrome || browser.edge && !browser.slow) {
|
||||
if (!browser.noAnimation && !browser.edgeUwp && !browser.xboxOne) {
|
||||
features.push('imageanalysis');
|
||||
}
|
||||
}
|
||||
|
||||
if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
|
||||
features.push('physicalvolumecontrol');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
|
||||
features.push('remotecontrol');
|
||||
}
|
||||
|
||||
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.edgeUwp) {
|
||||
features.push('remotevideo');
|
||||
}
|
||||
|
||||
features.push('displaylanguage');
|
||||
features.push('otherapppromotions');
|
||||
features.push('displaymode');
|
||||
features.push('targetblank');
|
||||
features.push('screensaver');
|
||||
|
||||
webSettings.enableMultiServer().then(enabled => {
|
||||
if (enabled) features.push('multiserver');
|
||||
});
|
||||
|
||||
if (!browser.orsay && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
|
||||
features.push('subtitleappearancesettings');
|
||||
}
|
||||
|
||||
if (!browser.orsay) {
|
||||
features.push('subtitleburnsettings');
|
||||
}
|
||||
|
||||
if (!browser.tv && !browser.ps4 && !browser.xboxOne) {
|
||||
features.push('fileinput');
|
||||
}
|
||||
|
||||
if (browser.chrome) {
|
||||
features.push('chromecast');
|
||||
}
|
||||
|
||||
return features;
|
||||
}();
|
||||
|
||||
/**
|
||||
* Do exit according to platform
|
||||
*/
|
||||
function doExit() {
|
||||
try {
|
||||
if (window.NativeShell) {
|
||||
window.NativeShell.AppHost.exit();
|
||||
} else if (browser.tizen) {
|
||||
tizen.application.getCurrentApplication().exit();
|
||||
} else if (browser.web0s) {
|
||||
webOS.platformBack();
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('error closing application: ' + err);
|
||||
}
|
||||
/**
|
||||
* Ask user for exit
|
||||
*/
|
||||
function askForExit() {
|
||||
if (exitPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
var exitPromise;
|
||||
|
||||
/**
|
||||
* Ask user for exit
|
||||
*/
|
||||
function askForExit() {
|
||||
if (exitPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
exitPromise = actionsheet.show({
|
||||
title: globalize.translate('MessageConfirmAppExit'),
|
||||
items: [
|
||||
{id: 'yes', name: globalize.translate('Yes')},
|
||||
{id: 'no', name: globalize.translate('No')}
|
||||
]
|
||||
}).then(function (value) {
|
||||
if (value === 'yes') {
|
||||
doExit();
|
||||
}
|
||||
}).finally(function () {
|
||||
exitPromise = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var deviceId;
|
||||
var deviceName;
|
||||
var appName = 'Jellyfin Web';
|
||||
var appVersion = '10.6.0';
|
||||
|
||||
var appHost = {
|
||||
getWindowState: function () {
|
||||
return document.windowState || 'Normal';
|
||||
},
|
||||
setWindowState: function (state) {
|
||||
alert('setWindowState is not supported and should not be called');
|
||||
},
|
||||
exit: function () {
|
||||
if (!!window.appMode && browser.tizen) {
|
||||
askForExit();
|
||||
} else {
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
exitPromise = actionsheet.show({
|
||||
title: globalize.translate('MessageConfirmAppExit'),
|
||||
items: [
|
||||
{id: 'yes', name: globalize.translate('Yes')},
|
||||
{id: 'no', name: globalize.translate('No')}
|
||||
]
|
||||
}).then(function (value) {
|
||||
if (value === 'yes') {
|
||||
doExit();
|
||||
}
|
||||
},
|
||||
supports: function (command) {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.supports(command);
|
||||
}
|
||||
}).finally(function () {
|
||||
exitPromise = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return -1 !== supportedFeatures.indexOf(command.toLowerCase());
|
||||
},
|
||||
preferVisualCards: browser.android || browser.chrome,
|
||||
getSyncProfile: getSyncProfile,
|
||||
getDefaultLayout: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.getDefaultLayout();
|
||||
}
|
||||
let deviceId;
|
||||
let deviceName;
|
||||
const appName = 'Jellyfin Web';
|
||||
const appVersion = '10.7.0';
|
||||
|
||||
return getDefaultLayout();
|
||||
},
|
||||
getDeviceProfile: getDeviceProfile,
|
||||
init: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.init();
|
||||
}
|
||||
|
||||
deviceName = getDeviceName();
|
||||
getDeviceId().then(function (id) {
|
||||
deviceId = id;
|
||||
});
|
||||
},
|
||||
deviceName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceName() : deviceName;
|
||||
},
|
||||
deviceId: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceId() : deviceId;
|
||||
},
|
||||
appName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appName() : appName;
|
||||
},
|
||||
appVersion: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appVersion() : appVersion;
|
||||
},
|
||||
getPushTokenInfo: function () {
|
||||
return {};
|
||||
},
|
||||
setThemeColor: function (color) {
|
||||
var metaThemeColor = document.querySelector('meta[name=theme-color]');
|
||||
|
||||
if (metaThemeColor) {
|
||||
metaThemeColor.setAttribute('content', color);
|
||||
}
|
||||
},
|
||||
setUserScalable: function (scalable) {
|
||||
if (!browser.tv) {
|
||||
var att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no';
|
||||
document.querySelector('meta[name=viewport]').setAttribute('content', att);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var isHidden = false;
|
||||
var hidden;
|
||||
var visibilityChange;
|
||||
|
||||
if (typeof document.hidden !== 'undefined') { /* eslint-disable-line compat/compat */
|
||||
hidden = 'hidden';
|
||||
visibilityChange = 'visibilitychange';
|
||||
} else if (typeof document.webkitHidden !== 'undefined') {
|
||||
hidden = 'webkitHidden';
|
||||
visibilityChange = 'webkitvisibilitychange';
|
||||
}
|
||||
|
||||
document.addEventListener(visibilityChange, function () {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (document[hidden]) {
|
||||
onAppHidden();
|
||||
const appHost = {
|
||||
getWindowState: function () {
|
||||
return document.windowState || 'Normal';
|
||||
},
|
||||
setWindowState: function () {
|
||||
alert('setWindowState is not supported and should not be called');
|
||||
},
|
||||
exit: function () {
|
||||
if (!!window.appMode && browser.tizen) {
|
||||
askForExit();
|
||||
} else {
|
||||
onAppVisible();
|
||||
doExit();
|
||||
}
|
||||
},
|
||||
supports: function (command) {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.supports(command);
|
||||
}
|
||||
}, false);
|
||||
|
||||
if (self.addEventListener) {
|
||||
self.addEventListener('focus', onAppVisible);
|
||||
self.addEventListener('blur', onAppHidden);
|
||||
return supportedFeatures.indexOf(command.toLowerCase()) !== -1;
|
||||
},
|
||||
preferVisualCards: browser.android || browser.chrome,
|
||||
getDefaultLayout: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.getDefaultLayout();
|
||||
}
|
||||
|
||||
return getDefaultLayout();
|
||||
},
|
||||
getDeviceProfile: getDeviceProfile,
|
||||
init: function () {
|
||||
if (window.NativeShell) {
|
||||
return window.NativeShell.AppHost.init();
|
||||
}
|
||||
|
||||
deviceName = getDeviceName();
|
||||
getDeviceId().then(function (id) {
|
||||
deviceId = id;
|
||||
});
|
||||
},
|
||||
deviceName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceName() : deviceName;
|
||||
},
|
||||
deviceId: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.deviceId() : deviceId;
|
||||
},
|
||||
appName: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appName() : appName;
|
||||
},
|
||||
appVersion: function () {
|
||||
return window.NativeShell ? window.NativeShell.AppHost.appVersion() : appVersion;
|
||||
},
|
||||
getPushTokenInfo: function () {
|
||||
return {};
|
||||
},
|
||||
setUserScalable: function (scalable) {
|
||||
if (!browser.tv) {
|
||||
const att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no';
|
||||
document.querySelector('meta[name=viewport]').setAttribute('content', att);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return appHost;
|
||||
});
|
||||
let isHidden = false;
|
||||
let hidden;
|
||||
let visibilityChange;
|
||||
|
||||
if (typeof document.hidden !== 'undefined') { /* eslint-disable-line compat/compat */
|
||||
hidden = 'hidden';
|
||||
visibilityChange = 'visibilitychange';
|
||||
} else if (typeof document.webkitHidden !== 'undefined') {
|
||||
hidden = 'webkitHidden';
|
||||
visibilityChange = 'webkitvisibilitychange';
|
||||
}
|
||||
|
||||
document.addEventListener(visibilityChange, function () {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (document[hidden]) {
|
||||
onAppHidden();
|
||||
} else {
|
||||
onAppVisible();
|
||||
}
|
||||
}, false);
|
||||
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('focus', onAppVisible);
|
||||
window.addEventListener('blur', onAppHidden);
|
||||
}
|
||||
|
||||
export default appHost;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings', 'css!./backdrop'], function (browser, connectionManager, playbackManager, dom, userSettings) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
import playbackManager from 'playbackManager';
|
||||
import dom from 'dom';
|
||||
import * as userSettings from 'userSettings';
|
||||
import 'css!./backdrop';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function enableAnimation(elem) {
|
||||
if (browser.slow) {
|
||||
@@ -22,71 +27,70 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
return true;
|
||||
}
|
||||
|
||||
function Backdrop() {
|
||||
}
|
||||
class Backdrop {
|
||||
load(url, parent, existingBackdropImage) {
|
||||
const img = new Image();
|
||||
const self = this;
|
||||
|
||||
Backdrop.prototype.load = function (url, parent, existingBackdropImage) {
|
||||
var img = new Image();
|
||||
var self = this;
|
||||
|
||||
img.onload = function () {
|
||||
if (self.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
var backdropImage = document.createElement('div');
|
||||
backdropImage.classList.add('backdropImage');
|
||||
backdropImage.classList.add('displayingBackdropImage');
|
||||
backdropImage.style.backgroundImage = "url('" + url + "')";
|
||||
backdropImage.setAttribute('data-url', url);
|
||||
|
||||
backdropImage.classList.add('backdropImageFadeIn');
|
||||
parent.appendChild(backdropImage);
|
||||
|
||||
if (!enableAnimation(backdropImage)) {
|
||||
if (existingBackdropImage && existingBackdropImage.parentNode) {
|
||||
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
|
||||
img.onload = () => {
|
||||
if (self.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
internalBackdrop(true);
|
||||
return;
|
||||
}
|
||||
|
||||
var onAnimationComplete = function () {
|
||||
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
const backdropImage = document.createElement('div');
|
||||
backdropImage.classList.add('backdropImage');
|
||||
backdropImage.classList.add('displayingBackdropImage');
|
||||
backdropImage.style.backgroundImage = `url('${url}')`;
|
||||
backdropImage.setAttribute('data-url', url);
|
||||
|
||||
backdropImage.classList.add('backdropImageFadeIn');
|
||||
parent.appendChild(backdropImage);
|
||||
|
||||
if (!enableAnimation(backdropImage)) {
|
||||
if (existingBackdropImage && existingBackdropImage.parentNode) {
|
||||
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
|
||||
}
|
||||
internalBackdrop(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const onAnimationComplete = () => {
|
||||
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
if (backdropImage === self.currentAnimatingElement) {
|
||||
self.currentAnimatingElement = null;
|
||||
}
|
||||
if (existingBackdropImage && existingBackdropImage.parentNode) {
|
||||
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
|
||||
}
|
||||
};
|
||||
|
||||
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
if (backdropImage === self.currentAnimatingElement) {
|
||||
self.currentAnimatingElement = null;
|
||||
}
|
||||
if (existingBackdropImage && existingBackdropImage.parentNode) {
|
||||
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
|
||||
}
|
||||
|
||||
internalBackdrop(true);
|
||||
};
|
||||
|
||||
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
|
||||
internalBackdrop(true);
|
||||
};
|
||||
|
||||
img.src = url;
|
||||
};
|
||||
|
||||
Backdrop.prototype.cancelAnimation = function () {
|
||||
var elem = this.currentAnimatingElement;
|
||||
if (elem) {
|
||||
elem.classList.remove('backdropImageFadeIn');
|
||||
this.currentAnimatingElement = null;
|
||||
img.src = url;
|
||||
}
|
||||
};
|
||||
|
||||
Backdrop.prototype.destroy = function () {
|
||||
this.isDestroyed = true;
|
||||
this.cancelAnimation();
|
||||
};
|
||||
cancelAnimation() {
|
||||
const elem = this.currentAnimatingElement;
|
||||
if (elem) {
|
||||
elem.classList.remove('backdropImageFadeIn');
|
||||
this.currentAnimatingElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
var backdropContainer;
|
||||
destroy() {
|
||||
this.isDestroyed = true;
|
||||
this.cancelAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
let backdropContainer;
|
||||
function getBackdropContainer() {
|
||||
if (!backdropContainer) {
|
||||
backdropContainer = document.querySelector('.backdropContainer');
|
||||
@@ -101,7 +105,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
return backdropContainer;
|
||||
}
|
||||
|
||||
function clearBackdrop(clearAll) {
|
||||
export function clearBackdrop(clearAll) {
|
||||
clearRotation();
|
||||
|
||||
if (currentLoadingBackdrop) {
|
||||
@@ -109,7 +113,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
currentLoadingBackdrop = null;
|
||||
}
|
||||
|
||||
var elem = getBackdropContainer();
|
||||
const elem = getBackdropContainer();
|
||||
elem.innerHTML = '';
|
||||
|
||||
if (clearAll) {
|
||||
@@ -119,7 +123,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
internalBackdrop(false);
|
||||
}
|
||||
|
||||
var backgroundContainer;
|
||||
let backgroundContainer;
|
||||
function getBackgroundContainer() {
|
||||
if (!backgroundContainer) {
|
||||
backgroundContainer = document.querySelector('.backgroundContainer');
|
||||
@@ -135,31 +139,27 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
}
|
||||
}
|
||||
|
||||
var hasInternalBackdrop;
|
||||
let hasInternalBackdrop;
|
||||
function internalBackdrop(enabled) {
|
||||
hasInternalBackdrop = enabled;
|
||||
setBackgroundContainerBackgroundEnabled();
|
||||
}
|
||||
|
||||
var hasExternalBackdrop;
|
||||
function externalBackdrop(enabled) {
|
||||
let hasExternalBackdrop;
|
||||
export function externalBackdrop(enabled) {
|
||||
hasExternalBackdrop = enabled;
|
||||
setBackgroundContainerBackgroundEnabled();
|
||||
}
|
||||
|
||||
function getRandom(min, max) {
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
}
|
||||
|
||||
var currentLoadingBackdrop;
|
||||
let currentLoadingBackdrop;
|
||||
function setBackdropImage(url) {
|
||||
if (currentLoadingBackdrop) {
|
||||
currentLoadingBackdrop.destroy();
|
||||
currentLoadingBackdrop = null;
|
||||
}
|
||||
|
||||
var elem = getBackdropContainer();
|
||||
var existingBackdropImage = elem.querySelector('.displayingBackdropImage');
|
||||
const elem = getBackdropContainer();
|
||||
const existingBackdropImage = elem.querySelector('.displayingBackdropImage');
|
||||
|
||||
if (existingBackdropImage && existingBackdropImage.getAttribute('data-url') === url) {
|
||||
if (existingBackdropImage.getAttribute('data-url') === url) {
|
||||
@@ -168,7 +168,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
existingBackdropImage.classList.remove('displayingBackdropImage');
|
||||
}
|
||||
|
||||
var instance = new Backdrop();
|
||||
const instance = new Backdrop();
|
||||
instance.load(url, elem, existingBackdropImage);
|
||||
currentLoadingBackdrop = instance;
|
||||
}
|
||||
@@ -176,9 +176,9 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
function getItemImageUrls(item, imageOptions) {
|
||||
imageOptions = imageOptions || {};
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
if (item.BackdropImageTags && item.BackdropImageTags.length > 0) {
|
||||
return item.BackdropImageTags.map(function (imgTag, index) {
|
||||
return item.BackdropImageTags.map((imgTag, index) => {
|
||||
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
|
||||
type: 'Backdrop',
|
||||
tag: imgTag,
|
||||
@@ -189,7 +189,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
}
|
||||
|
||||
if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
|
||||
return item.ParentBackdropImageTags.map(function (imgTag, index) {
|
||||
return item.ParentBackdropImageTags.map((imgTag, index) => {
|
||||
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
|
||||
type: 'Backdrop',
|
||||
tag: imgTag,
|
||||
@@ -203,13 +203,13 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
}
|
||||
|
||||
function getImageUrls(items, imageOptions) {
|
||||
var list = [];
|
||||
var onImg = function (img) {
|
||||
const list = [];
|
||||
const onImg = img => {
|
||||
list.push(img);
|
||||
};
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
var itemImages = getItemImageUrls(items[i], imageOptions);
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
const itemImages = getItemImageUrls(items[i], imageOptions);
|
||||
itemImages.forEach(onImg);
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
|
||||
// If you don't care about the order of the elements inside
|
||||
// the array, you should sort both arrays here.
|
||||
for (var i = 0; i < a.length; ++i) {
|
||||
for (let i = 0; i < a.length; ++i) {
|
||||
if (a[i] !== b[i]) {
|
||||
return false;
|
||||
}
|
||||
@@ -242,12 +242,12 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
return userSettings.enableBackdrops();
|
||||
}
|
||||
|
||||
var rotationInterval;
|
||||
var currentRotatingImages = [];
|
||||
var currentRotationIndex = -1;
|
||||
function setBackdrops(items, imageOptions, enableImageRotation) {
|
||||
let rotationInterval;
|
||||
let currentRotatingImages = [];
|
||||
let currentRotationIndex = -1;
|
||||
export function setBackdrops(items, imageOptions, enableImageRotation) {
|
||||
if (enabled()) {
|
||||
var images = getImageUrls(items, imageOptions);
|
||||
const images = getImageUrls(items, imageOptions);
|
||||
|
||||
if (images.length) {
|
||||
startRotation(images, enableImageRotation);
|
||||
@@ -279,7 +279,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
return;
|
||||
}
|
||||
|
||||
var newIndex = currentRotationIndex + 1;
|
||||
let newIndex = currentRotationIndex + 1;
|
||||
if (newIndex >= currentRotatingImages.length) {
|
||||
newIndex = 0;
|
||||
}
|
||||
@@ -289,7 +289,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
}
|
||||
|
||||
function clearRotation() {
|
||||
var interval = rotationInterval;
|
||||
const interval = rotationInterval;
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
@@ -299,7 +299,7 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
currentRotationIndex = -1;
|
||||
}
|
||||
|
||||
function setBackdrop(url, imageOptions) {
|
||||
export function setBackdrop(url, imageOptions) {
|
||||
if (url && typeof url !== 'string') {
|
||||
url = getImageUrls([url], imageOptions)[0];
|
||||
}
|
||||
@@ -312,10 +312,11 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
setBackdrops: setBackdrops,
|
||||
setBackdrop: setBackdrop,
|
||||
clear: clearBackdrop,
|
||||
externalBackdrop: externalBackdrop
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
setBackdrops: setBackdrops,
|
||||
setBackdrop: setBackdrop,
|
||||
clearBackdrop: clearBackdrop,
|
||||
externalBackdrop: externalBackdrop
|
||||
};
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
define(['connectionManager'], function (connectionManager) {
|
||||
|
||||
return function () {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.name = 'Backdrop ScreenSaver';
|
||||
self.type = 'screensaver';
|
||||
self.id = 'backdropscreensaver';
|
||||
self.supportsAnonymous = false;
|
||||
|
||||
var currentSlideshow;
|
||||
|
||||
self.show = function () {
|
||||
|
||||
var query = {
|
||||
ImageTypes: 'Backdrop',
|
||||
EnableImageTypes: 'Backdrop',
|
||||
IncludeItemTypes: 'Movie,Series,MusicArtist',
|
||||
SortBy: 'Random',
|
||||
Recursive: true,
|
||||
Fields: 'Taglines',
|
||||
ImageTypeLimit: 1,
|
||||
StartIndex: 0,
|
||||
Limit: 200
|
||||
};
|
||||
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), query).then(function (result) {
|
||||
|
||||
if (result.Items.length) {
|
||||
|
||||
require(['slideshow'], function (slideshow) {
|
||||
|
||||
var newSlideShow = new slideshow({
|
||||
showTitle: true,
|
||||
cover: true,
|
||||
items: result.Items
|
||||
});
|
||||
|
||||
newSlideShow.show();
|
||||
currentSlideshow = newSlideShow;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.hide = function () {
|
||||
|
||||
if (currentSlideshow) {
|
||||
currentSlideshow.hide();
|
||||
currentSlideshow = null;
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
@@ -167,8 +167,9 @@ button::-moz-focus-inner {
|
||||
position: relative;
|
||||
background-clip: content-box !important;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* This is only needed for scalable cards */
|
||||
.cardScalable .cardImageContainer {
|
||||
height: 100%;
|
||||
contain: strict;
|
||||
}
|
||||
@@ -192,9 +193,14 @@ button::-moz-focus-inner {
|
||||
|
||||
/* Needed in case this is a button */
|
||||
display: block;
|
||||
|
||||
/* Needed in case this is a button */
|
||||
margin: 0 !important;
|
||||
border: 0 !important;
|
||||
padding: 0 !important;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
width: 100%;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
|
||||
/* Needed in safari */
|
||||
height: 100%;
|
||||
@@ -203,27 +209,25 @@ button::-moz-focus-inner {
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.cardContent-button {
|
||||
border: 0 !important;
|
||||
padding: 0 !important;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
.defaultCardBackground {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.cardContent-button:not(.defaultCardBackground) {
|
||||
.cardContent:not(.defaultCardBackground) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.cardBox:not(.visualCardBox) .cardPadder {
|
||||
background-color: #242424;
|
||||
}
|
||||
|
||||
.visualCardBox .cardContent {
|
||||
border-bottom-left-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);
|
||||
}
|
||||
|
||||
@@ -239,33 +243,13 @@ button::-moz-focus-inner {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.cardImage-img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
|
||||
/* This is simply for lazy image purposes, to ensure the image is visible sooner when scrolling */
|
||||
min-height: 70%;
|
||||
min-width: 70%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.coveredImage-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.coveredImage-noscale-img {
|
||||
max-height: none;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.coveredImage {
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.coveredImage-noScale {
|
||||
background-size: cover;
|
||||
.coveredImage.coveredImage-contain {
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.cardFooter {
|
||||
@@ -372,6 +356,8 @@ button::-moz-focus-inner {
|
||||
.cardDefaultText {
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cardImageContainer .cardImageIcon {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
import datetime from 'datetime';
|
||||
import imageLoader from 'imageLoader';
|
||||
import connectionManager from 'connectionManager';
|
||||
import itemHelper from 'itemHelper';
|
||||
import focusManager from 'focusManager';
|
||||
import indicators from 'indicators';
|
||||
@@ -277,7 +276,7 @@ import 'programStyles';
|
||||
*/
|
||||
function getImageWidth(shape, screenWidth, isOrientationLandscape) {
|
||||
const imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape);
|
||||
return Math.round(screenWidth / imagesPerRow) * 2;
|
||||
return Math.round(screenWidth / imagesPerRow);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,12 +290,10 @@ import 'programStyles';
|
||||
const primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items);
|
||||
|
||||
if (['auto', 'autohome', 'autooverflow', 'autoVertical'].includes(options.shape)) {
|
||||
|
||||
const requestedShape = options.shape;
|
||||
options.shape = null;
|
||||
|
||||
if (primaryImageAspectRatio) {
|
||||
|
||||
if (primaryImageAspectRatio >= 3) {
|
||||
options.shape = 'banner';
|
||||
options.coverImage = true;
|
||||
@@ -364,18 +361,16 @@ import 'programStyles';
|
||||
let hasOpenRow;
|
||||
let hasOpenSection;
|
||||
|
||||
let sectionTitleTagName = options.sectionTitleTagName || 'div';
|
||||
const sectionTitleTagName = options.sectionTitleTagName || 'div';
|
||||
let apiClient;
|
||||
let lastServerId;
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
|
||||
let item = items[i];
|
||||
let serverId = item.ServerId || options.serverId;
|
||||
for (const [i, item] of items.entries()) {
|
||||
const serverId = item.ServerId || options.serverId;
|
||||
|
||||
if (serverId !== lastServerId) {
|
||||
lastServerId = serverId;
|
||||
apiClient = connectionManager.getApiClient(lastServerId);
|
||||
apiClient = window.connectionManager.getApiClient(lastServerId);
|
||||
}
|
||||
|
||||
if (options.indexBy) {
|
||||
@@ -396,7 +391,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (newIndexValue !== currentIndexValue) {
|
||||
|
||||
if (hasOpenRow) {
|
||||
html += '</div>';
|
||||
hasOpenRow = false;
|
||||
@@ -404,7 +398,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (hasOpenSection) {
|
||||
|
||||
html += '</div>';
|
||||
|
||||
if (isVertical) {
|
||||
@@ -428,7 +421,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.rows && itemsInRow === 0) {
|
||||
|
||||
if (hasOpenRow) {
|
||||
html += '</div>';
|
||||
hasOpenRow = false;
|
||||
@@ -503,94 +495,49 @@ import 'programStyles';
|
||||
const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
|
||||
let forceName = false;
|
||||
let imgUrl = null;
|
||||
let imgTag = null;
|
||||
let coverImage = false;
|
||||
let uiAspect = null;
|
||||
let imgType = null;
|
||||
let itemId = null;
|
||||
|
||||
if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ImageTags.Thumb;
|
||||
} else if ((options.preferBanner || shape === 'banner') && item.ImageTags && item.ImageTags.Banner) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Banner',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Banner
|
||||
});
|
||||
|
||||
imgType = 'Banner';
|
||||
imgTag = item.ImageTags.Banner;
|
||||
} else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Disc',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Disc
|
||||
});
|
||||
|
||||
imgType = 'Disc';
|
||||
imgTag = item.ImageTags.Disc;
|
||||
} else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Logo',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Logo
|
||||
});
|
||||
|
||||
imgType = 'Logo';
|
||||
imgTag = item.ImageTags.Logo;
|
||||
} else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, {
|
||||
type: 'Logo',
|
||||
maxWidth: width,
|
||||
tag: item.ParentLogoImageTag
|
||||
});
|
||||
|
||||
imgType = 'Logo';
|
||||
imgTag = item.ParentLogoImageTag;
|
||||
itemId = item.ParentLogoItemId;
|
||||
} else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.SeriesThumbImageTag
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.SeriesThumbImageTag;
|
||||
itemId = item.SeriesId;
|
||||
} else if (options.preferThumb && item.ParentThumbItemId && options.inheritThumb !== false && item.MediaType !== 'Photo') {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ParentThumbImageTag
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ParentThumbImageTag;
|
||||
itemId = item.ParentThumbItemId;
|
||||
} else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: width,
|
||||
tag: item.BackdropImageTags[0]
|
||||
});
|
||||
|
||||
imgType = 'Backdrop';
|
||||
imgTag = item.BackdropImageTags[0];
|
||||
forceName = true;
|
||||
|
||||
} else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: width,
|
||||
tag: item.ParentBackdropImageTags[0]
|
||||
});
|
||||
|
||||
} else if (item.ImageTags && item.ImageTags.Primary) {
|
||||
|
||||
imgType = 'Backdrop';
|
||||
imgTag = item.ParentBackdropImageTags[0];
|
||||
itemId = item.ParentBackdropItemId;
|
||||
} else if (item.ImageTags && item.ImageTags.Primary && (item.Type !== 'Episode' || item.ChildCount !== 0)) {
|
||||
imgType = 'Primary';
|
||||
imgTag = item.ImageTags.Primary;
|
||||
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Primary',
|
||||
maxHeight: height,
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Primary
|
||||
});
|
||||
|
||||
if (options.preferThumb && options.showTitle !== false) {
|
||||
forceName = true;
|
||||
}
|
||||
@@ -601,18 +548,16 @@ import 'programStyles';
|
||||
coverImage = (Math.abs(primaryImageAspectRatio - uiAspect) / uiAspect) <= 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (item.SeriesPrimaryImageTag) {
|
||||
imgType = 'Primary';
|
||||
imgTag = item.SeriesPrimaryImageTag;
|
||||
itemId = item.SeriesId;
|
||||
} else if (item.PrimaryImageTag) {
|
||||
|
||||
imgType = 'Primary';
|
||||
imgTag = item.PrimaryImageTag;
|
||||
itemId = item.PrimaryImageItemId;
|
||||
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.PrimaryImageItemId || item.Id || item.ItemId, {
|
||||
type: 'Primary',
|
||||
maxHeight: height,
|
||||
maxWidth: width,
|
||||
tag: item.PrimaryImageTag
|
||||
});
|
||||
|
||||
if (options.preferThumb && options.showTitle !== false) {
|
||||
forceName = true;
|
||||
}
|
||||
@@ -624,30 +569,15 @@ import 'programStyles';
|
||||
}
|
||||
}
|
||||
} else if (item.ParentPrimaryImageTag) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, {
|
||||
type: 'Primary',
|
||||
maxWidth: width,
|
||||
tag: item.ParentPrimaryImageTag
|
||||
});
|
||||
} else if (item.SeriesPrimaryImageTag) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, {
|
||||
type: 'Primary',
|
||||
maxWidth: width,
|
||||
tag: item.SeriesPrimaryImageTag
|
||||
});
|
||||
imgType = 'Primary';
|
||||
imgTag = item.ParentPrimaryImageTag;
|
||||
itemId = item.ParentPrimaryImageItemId;
|
||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
imgType = 'Primary';
|
||||
imgTag = item.AlbumPrimaryImageTag;
|
||||
itemId = item.AlbumId;
|
||||
height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null;
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.AlbumId, {
|
||||
type: 'Primary',
|
||||
maxHeight: height,
|
||||
maxWidth: width,
|
||||
tag: item.AlbumPrimaryImageTag
|
||||
});
|
||||
|
||||
if (primaryImageAspectRatio) {
|
||||
uiAspect = getDesiredAspect(shape);
|
||||
if (uiAspect) {
|
||||
@@ -655,57 +585,46 @@ import 'programStyles';
|
||||
}
|
||||
}
|
||||
} else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ImageTags.Thumb;
|
||||
} else if (item.BackdropImageTags && item.BackdropImageTags.length) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: width,
|
||||
tag: item.BackdropImageTags[0]
|
||||
});
|
||||
|
||||
imgType = 'Backdrop';
|
||||
imgTag = item.BackdropImageTags[0];
|
||||
} else if (item.ImageTags && item.ImageTags.Thumb) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.Id, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ImageTags.Thumb
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ImageTags.Thumb;
|
||||
} else if (item.SeriesThumbImageTag && options.inheritThumb !== false) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.SeriesId, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.SeriesThumbImageTag
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.SeriesThumbImageTag;
|
||||
itemId = item.SeriesId;
|
||||
} else if (item.ParentThumbItemId && options.inheritThumb !== false) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, {
|
||||
type: 'Thumb',
|
||||
maxWidth: width,
|
||||
tag: item.ParentThumbImageTag
|
||||
});
|
||||
|
||||
imgType = 'Thumb';
|
||||
imgTag = item.ParentThumbImageTag;
|
||||
itemId = item.ParentThumbItemId;
|
||||
} else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) {
|
||||
|
||||
imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, {
|
||||
type: 'Backdrop',
|
||||
maxWidth: width,
|
||||
tag: item.ParentBackdropImageTags[0]
|
||||
});
|
||||
|
||||
imgType = 'Backdrop';
|
||||
imgTag = item.ParentBackdropImageTags[0];
|
||||
itemId = item.ParentBackdropItemId;
|
||||
}
|
||||
|
||||
if (!itemId) {
|
||||
itemId = item.Id;
|
||||
}
|
||||
|
||||
if (imgTag && imgType) {
|
||||
imgUrl = apiClient.getScaledImageUrl(itemId, {
|
||||
type: imgType,
|
||||
maxHeight: height,
|
||||
maxWidth: width,
|
||||
tag: imgTag
|
||||
});
|
||||
}
|
||||
|
||||
const blurHashes = options.imageBlurhashes || item.ImageBlurHashes || {};
|
||||
|
||||
return {
|
||||
imgUrl: imgUrl,
|
||||
blurhash: (blurHashes[imgType] || {})[imgTag],
|
||||
forceName: forceName,
|
||||
coverImage: coverImage
|
||||
};
|
||||
@@ -736,7 +655,7 @@ import 'programStyles';
|
||||
for (let i = 0; i < character.length; i++) {
|
||||
sum += parseInt(character.charAt(i));
|
||||
}
|
||||
let index = String(sum).substr(-1);
|
||||
const index = String(sum).substr(-1);
|
||||
|
||||
return (index % numRandomColors) + 1;
|
||||
} else {
|
||||
@@ -761,9 +680,8 @@ import 'programStyles';
|
||||
let valid = 0;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
|
||||
let currentCssClass = cssClass;
|
||||
let text = lines[i];
|
||||
const text = lines[i];
|
||||
|
||||
if (valid > 0 && isOuterFooter) {
|
||||
currentCssClass += ' cardText-secondary';
|
||||
@@ -788,8 +706,7 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (forceLines) {
|
||||
|
||||
let linesLength = maxLines || Math.min(lines.length, maxLines || lines.length);
|
||||
const linesLength = maxLines || Math.min(lines.length, maxLines || lines.length);
|
||||
|
||||
while (valid < linesLength) {
|
||||
html += "<div class='" + cssClass + "'> </div>";
|
||||
@@ -820,7 +737,6 @@ import 'programStyles';
|
||||
let airTimeText = '';
|
||||
|
||||
if (item.StartDate) {
|
||||
|
||||
try {
|
||||
let date = datetime.parseISO8601Date(item.StartDate);
|
||||
|
||||
@@ -867,7 +783,6 @@ import 'programStyles';
|
||||
const showOtherText = isOuterFooter ? !overlayText : overlayText;
|
||||
|
||||
if (isOuterFooter && options.cardLayout && layoutManager.mobile) {
|
||||
|
||||
if (options.cardFooterAside !== 'none') {
|
||||
html += '<button is="paper-icon-button-light" class="itemAction btnCardOptions cardText-secondary" data-action="menu"><span class="material-icons more_vert"></span></button>';
|
||||
}
|
||||
@@ -882,9 +797,7 @@ import 'programStyles';
|
||||
|
||||
if (showOtherText) {
|
||||
if ((options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) {
|
||||
|
||||
if (isOuterFooter && item.Type === 'Episode' && item.SeriesName) {
|
||||
|
||||
if (item.SeriesId) {
|
||||
lines.push(getTextActionButton({
|
||||
Id: item.SeriesId,
|
||||
@@ -897,15 +810,12 @@ import 'programStyles';
|
||||
lines.push(item.SeriesName);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (isUsingLiveTvNaming(item)) {
|
||||
|
||||
lines.push(item.Name);
|
||||
|
||||
if (!item.EpisodeTitle) {
|
||||
titleAdded = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
const parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || '';
|
||||
|
||||
@@ -923,7 +833,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (showMediaTitle) {
|
||||
|
||||
const name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, {
|
||||
includeParentInfo: options.includeParentInfoInTitle
|
||||
});
|
||||
@@ -940,7 +849,6 @@ import 'programStyles';
|
||||
|
||||
if (showOtherText) {
|
||||
if (options.showParentTitle && parentTitleUnderneath) {
|
||||
|
||||
if (isOuterFooter && item.AlbumArtists && item.AlbumArtists.length) {
|
||||
item.AlbumArtists[0].Type = 'MusicArtist';
|
||||
item.AlbumArtists[0].IsFolder = true;
|
||||
@@ -974,7 +882,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showPremiereDate) {
|
||||
|
||||
if (item.PremiereDate) {
|
||||
try {
|
||||
lines.push(datetime.toLocaleDateString(
|
||||
@@ -983,7 +890,6 @@ import 'programStyles';
|
||||
));
|
||||
} catch (err) {
|
||||
lines.push('');
|
||||
|
||||
}
|
||||
} else {
|
||||
lines.push('');
|
||||
@@ -991,14 +897,10 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showYear || options.showSeriesYear) {
|
||||
|
||||
if (item.Type === 'Series') {
|
||||
if (item.Status === 'Continuing') {
|
||||
|
||||
lines.push(globalize.translate('SeriesYearToPresent', item.ProductionYear || ''));
|
||||
|
||||
} else {
|
||||
|
||||
if (item.EndDate && item.ProductionYear) {
|
||||
const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
lines.push(item.ProductionYear + ((endYear === item.ProductionYear) ? '' : (' - ' + endYear)));
|
||||
@@ -1012,9 +914,7 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showRuntime) {
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
lines.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
} else {
|
||||
lines.push('');
|
||||
@@ -1022,14 +922,11 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showAirTime) {
|
||||
|
||||
lines.push(getAirTimeText(item, options.showAirDateTime, options.showAirEndTime) || '');
|
||||
}
|
||||
|
||||
if (options.showChannelName) {
|
||||
|
||||
if (item.ChannelId) {
|
||||
|
||||
lines.push(getTextActionButton({
|
||||
|
||||
Id: item.ChannelId,
|
||||
@@ -1046,7 +943,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showCurrentProgram && item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
lines.push(item.CurrentProgram.Name);
|
||||
} else {
|
||||
@@ -1055,7 +951,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (options.showCurrentProgramTime && item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
lines.push(getAirTimeText(item.CurrentProgram, false, true) || '');
|
||||
} else {
|
||||
@@ -1065,7 +960,6 @@ import 'programStyles';
|
||||
|
||||
if (options.showSeriesTimerTime) {
|
||||
if (item.RecordAnyTime) {
|
||||
|
||||
lines.push(globalize.translate('Anytime'));
|
||||
} else {
|
||||
lines.push(datetime.getDisplayTime(item.StartDate));
|
||||
@@ -1091,6 +985,10 @@ import 'programStyles';
|
||||
lines = [];
|
||||
}
|
||||
|
||||
if (overlayText && showTitle) {
|
||||
lines = [item.Name];
|
||||
}
|
||||
|
||||
const addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile;
|
||||
|
||||
html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines);
|
||||
@@ -1100,7 +998,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
if (!isOuterFooter || logoUrl || options.cardLayout) {
|
||||
html = '<div class="' + footerClass + '">' + html;
|
||||
|
||||
@@ -1142,31 +1039,25 @@ import 'programStyles';
|
||||
* @returns {string} HTML markup for the item count indicator.
|
||||
*/
|
||||
function getItemCountsHtml(options, item) {
|
||||
let counts = [];
|
||||
const counts = [];
|
||||
let childText;
|
||||
|
||||
if (item.Type === 'Playlist') {
|
||||
|
||||
childText = '';
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
let minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
minutes = minutes || 1;
|
||||
|
||||
childText += globalize.translate('ValueMinutes', Math.round(minutes));
|
||||
|
||||
} else {
|
||||
childText += globalize.translate('ValueMinutes', 0);
|
||||
}
|
||||
|
||||
counts.push(childText);
|
||||
|
||||
} else if (item.Type === 'Genre' || item.Type === 'Studio') {
|
||||
|
||||
if (item.MovieCount) {
|
||||
|
||||
childText = item.MovieCount === 1 ?
|
||||
globalize.translate('ValueOneMovie') :
|
||||
globalize.translate('ValueMovieCount', item.MovieCount);
|
||||
@@ -1175,7 +1066,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (item.SeriesCount) {
|
||||
|
||||
childText = item.SeriesCount === 1 ?
|
||||
globalize.translate('ValueOneSeries') :
|
||||
globalize.translate('ValueSeriesCount', item.SeriesCount);
|
||||
@@ -1183,18 +1073,14 @@ import 'programStyles';
|
||||
counts.push(childText);
|
||||
}
|
||||
if (item.EpisodeCount) {
|
||||
|
||||
childText = item.EpisodeCount === 1 ?
|
||||
globalize.translate('ValueOneEpisode') :
|
||||
globalize.translate('ValueEpisodeCount', item.EpisodeCount);
|
||||
|
||||
counts.push(childText);
|
||||
}
|
||||
|
||||
} else if (item.Type === 'MusicGenre' || options.context === 'MusicArtist') {
|
||||
|
||||
if (item.AlbumCount) {
|
||||
|
||||
childText = item.AlbumCount === 1 ?
|
||||
globalize.translate('ValueOneAlbum') :
|
||||
globalize.translate('ValueAlbumCount', item.AlbumCount);
|
||||
@@ -1202,7 +1088,6 @@ import 'programStyles';
|
||||
counts.push(childText);
|
||||
}
|
||||
if (item.SongCount) {
|
||||
|
||||
childText = item.SongCount === 1 ?
|
||||
globalize.translate('ValueOneSong') :
|
||||
globalize.translate('ValueSongCount', item.SongCount);
|
||||
@@ -1210,16 +1095,13 @@ import 'programStyles';
|
||||
counts.push(childText);
|
||||
}
|
||||
if (item.MusicVideoCount) {
|
||||
|
||||
childText = item.MusicVideoCount === 1 ?
|
||||
globalize.translate('ValueOneMusicVideo') :
|
||||
globalize.translate('ValueMusicVideoCount', item.MusicVideoCount);
|
||||
|
||||
counts.push(childText);
|
||||
}
|
||||
|
||||
} else if (item.Type === 'Series') {
|
||||
|
||||
childText = item.RecursiveItemCount === 1 ?
|
||||
globalize.translate('ValueOneEpisode') :
|
||||
globalize.translate('ValueEpisodeCount', item.RecursiveItemCount);
|
||||
@@ -1235,10 +1117,11 @@ import 'programStyles';
|
||||
/**
|
||||
* Imports the refresh indicator element.
|
||||
*/
|
||||
function requireRefreshIndicator() {
|
||||
function importRefreshIndicator() {
|
||||
if (!refreshIndicatorLoaded) {
|
||||
refreshIndicatorLoaded = true;
|
||||
require(['emby-itemrefreshindicator']);
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-itemrefreshindicator');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1272,13 +1155,11 @@ import 'programStyles';
|
||||
let shape = options.shape;
|
||||
|
||||
if (shape === 'mixed') {
|
||||
|
||||
shape = null;
|
||||
|
||||
const primaryImageAspectRatio = item.PrimaryImageAspectRatio;
|
||||
|
||||
if (primaryImageAspectRatio) {
|
||||
|
||||
if (primaryImageAspectRatio >= 1.33) {
|
||||
shape = 'mixedBackdrop';
|
||||
} else if (primaryImageAspectRatio > 0.71) {
|
||||
@@ -1321,6 +1202,7 @@ import 'programStyles';
|
||||
|
||||
const imgInfo = getCardImageUrl(item, apiClient, options, shape);
|
||||
const imgUrl = imgInfo.imgUrl;
|
||||
const blurhash = imgInfo.blurhash;
|
||||
|
||||
const forceName = imgInfo.forceName;
|
||||
|
||||
@@ -1333,8 +1215,8 @@ import 'programStyles';
|
||||
if (coveredImage) {
|
||||
cardImageContainerClass += ' coveredImage';
|
||||
|
||||
if (item.MediaType === 'Photo' || item.Type === 'PhotoAlbum' || item.Type === 'Folder' || item.ProgramInfo || item.Type === 'Program' || item.Type === 'Recording') {
|
||||
cardImageContainerClass += ' coveredImage-noScale';
|
||||
if (item.Type === 'TvChannel') {
|
||||
cardImageContainerClass += ' coveredImage-contain';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1369,7 +1251,6 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
if (overlayText) {
|
||||
|
||||
logoUrl = null;
|
||||
|
||||
footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter';
|
||||
@@ -1384,7 +1265,7 @@ import 'programStyles';
|
||||
}
|
||||
|
||||
const mediaSourceCount = item.MediaSourceCount || 1;
|
||||
if (mediaSourceCount > 1) {
|
||||
if (mediaSourceCount > 1 && options.disableIndicators !== true) {
|
||||
innerCardFooter += '<div class="mediaSourceIndicator">' + mediaSourceCount + '</div>';
|
||||
}
|
||||
|
||||
@@ -1440,58 +1321,60 @@ import 'programStyles';
|
||||
let cardBoxClose = '';
|
||||
let cardScalableClose = '';
|
||||
|
||||
let cardContentClass = 'cardContent';
|
||||
if (!options.cardLayout) {
|
||||
cardContentClass += ' cardContent-shadow';
|
||||
const cardContentClass = 'cardContent';
|
||||
|
||||
let blurhashAttrib = '';
|
||||
if (blurhash && blurhash.length > 0) {
|
||||
blurhashAttrib = 'data-blurhash="' + blurhash + '"';
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
|
||||
// Don't use the IMG tag with safari because it puts a white border around it
|
||||
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + '">');
|
||||
cardImageContainerOpen = imgUrl ? ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + ' lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<div class="' + cardImageContainerClass + ' ' + cardContentClass + '">');
|
||||
|
||||
cardImageContainerClose = '</div>';
|
||||
} else {
|
||||
// Don't use the IMG tag with safari because it puts a white border around it
|
||||
cardImageContainerOpen = imgUrl ? ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction lazy" data-src="' + imgUrl + '">') : ('<button data-action="' + action + '" class="cardContent-button ' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction">');
|
||||
cardImageContainerOpen = imgUrl ? ('<button data-action="' + action + '" class="' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction lazy" data-src="' + imgUrl + '" ' + blurhashAttrib + '>') : ('<button data-action="' + action + '" class="' + cardImageContainerClass + ' ' + cardContentClass + ' itemAction">');
|
||||
|
||||
cardImageContainerClose = '</button>';
|
||||
}
|
||||
|
||||
let cardScalableClass = 'cardScalable';
|
||||
const 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>';
|
||||
cardScalableClose = '</div>';
|
||||
|
||||
let indicatorsHtml = '';
|
||||
if (options.disableIndicators !== true) {
|
||||
let indicatorsHtml = '';
|
||||
|
||||
if (options.missingIndicator !== false) {
|
||||
indicatorsHtml += indicators.getMissingIndicator(item);
|
||||
}
|
||||
if (options.missingIndicator !== false) {
|
||||
indicatorsHtml += indicators.getMissingIndicator(item);
|
||||
}
|
||||
|
||||
indicatorsHtml += indicators.getSyncIndicator(item);
|
||||
indicatorsHtml += indicators.getTimerIndicator(item);
|
||||
indicatorsHtml += indicators.getSyncIndicator(item);
|
||||
indicatorsHtml += indicators.getTimerIndicator(item);
|
||||
|
||||
indicatorsHtml += indicators.getTypeIndicator(item);
|
||||
indicatorsHtml += indicators.getTypeIndicator(item);
|
||||
|
||||
if (options.showGroupCount) {
|
||||
if (options.showGroupCount) {
|
||||
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, {
|
||||
minCount: 1
|
||||
});
|
||||
} else {
|
||||
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
|
||||
}
|
||||
|
||||
indicatorsHtml += indicators.getChildCountIndicatorHtml(item, {
|
||||
minCount: 1
|
||||
});
|
||||
} else {
|
||||
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
|
||||
}
|
||||
if (item.Type === 'CollectionFolder' || item.CollectionType) {
|
||||
const refreshClass = item.RefreshProgress ? '' : ' class="hide"';
|
||||
indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>';
|
||||
importRefreshIndicator();
|
||||
}
|
||||
|
||||
if (item.Type === 'CollectionFolder' || item.CollectionType) {
|
||||
const refreshClass = item.RefreshProgress ? '' : ' class="hide"';
|
||||
indicatorsHtml += '<div is="emby-itemrefreshindicator"' + refreshClass + ' data-progress="' + (item.RefreshProgress || 0) + '" data-status="' + item.RefreshStatus + '"></div>';
|
||||
requireRefreshIndicator();
|
||||
}
|
||||
|
||||
if (indicatorsHtml) {
|
||||
cardImageContainerOpen += '<div class="cardIndicators">' + indicatorsHtml + '</div>';
|
||||
if (indicatorsHtml) {
|
||||
cardImageContainerOpen += '<div class="cardIndicators">' + indicatorsHtml + '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!imgUrl) {
|
||||
@@ -1539,8 +1422,8 @@ import 'programStyles';
|
||||
|
||||
let additionalCardContent = '';
|
||||
|
||||
if (layoutManager.desktop) {
|
||||
additionalCardContent += getHoverMenuHtml(item, action);
|
||||
if (layoutManager.desktop && !options.disableHoverMenu) {
|
||||
additionalCardContent += getHoverMenuHtml(item, action, options);
|
||||
}
|
||||
|
||||
return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + ' data-prefix="' + prefix + '" class="' + className + '">' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + '</' + tagName + '>';
|
||||
@@ -1550,9 +1433,10 @@ import 'programStyles';
|
||||
* Generates HTML markup for the card overlay.
|
||||
* @param {object} item - Item used to generate the card overlay.
|
||||
* @param {string} action - Action assigned to the overlay.
|
||||
* @param {Array} options - Card builder options.
|
||||
* @returns {string} HTML markup of the card overlay.
|
||||
*/
|
||||
function getHoverMenuHtml(item, action) {
|
||||
function getHoverMenuHtml(item, action, options) {
|
||||
let html = '';
|
||||
|
||||
html += '<div class="cardOverlayContainer itemAction" data-action="' + action + '">';
|
||||
@@ -1568,20 +1452,20 @@ import 'programStyles';
|
||||
const userData = item.UserData || {};
|
||||
|
||||
if (itemHelper.canMarkPlayed(item)) {
|
||||
require(['emby-playstatebutton']);
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-playstatebutton');
|
||||
html += '<button is="emby-playstatebutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-played="' + (userData.Played) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover check"></span></button>';
|
||||
}
|
||||
|
||||
if (itemHelper.canRate(item)) {
|
||||
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
require(['emby-ratingbutton']);
|
||||
/* eslint-disable-next-line @babel/no-unused-expressions */
|
||||
import('emby-ratingbutton');
|
||||
html += '<button is="emby-ratingbutton" type="button" data-action="none" class="' + btnCssClass + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-itemtype="' + item.Type + '" data-likes="' + likes + '" data-isfavorite="' + (userData.IsFavorite) + '"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover favorite"></span></button>';
|
||||
}
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="' + btnCssClass + '" data-action="menu"><span class="material-icons cardOverlayButtonIcon cardOverlayButtonIcon-hover more_vert"></span></button>';
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
@@ -1605,6 +1489,8 @@ import 'programStyles';
|
||||
case 'MusicArtist':
|
||||
case 'Person':
|
||||
return '<span class="cardImageIcon material-icons person"></span>';
|
||||
case 'Audio':
|
||||
return '<span class="cardImageIcon material-icons audiotrack"></span>';
|
||||
case 'Movie':
|
||||
return '<span class="cardImageIcon material-icons movie"></span>';
|
||||
case 'Series':
|
||||
@@ -1613,6 +1499,12 @@ import 'programStyles';
|
||||
return '<span class="cardImageIcon material-icons book"></span>';
|
||||
case 'Folder':
|
||||
return '<span class="cardImageIcon material-icons folder"></span>';
|
||||
case 'BoxSet':
|
||||
return '<span class="cardImageIcon material-icons collections"></span>';
|
||||
case 'Playlist':
|
||||
return '<span class="cardImageIcon material-icons view_list"></span>';
|
||||
case 'PhotoAlbum':
|
||||
return '<span class="cardImageIcon material-icons photo_album"></span>';
|
||||
}
|
||||
|
||||
if (options && options.defaultCardImageIcon) {
|
||||
@@ -1646,7 +1538,6 @@ import 'programStyles';
|
||||
const html = buildCardsHtmlInternal(items, options);
|
||||
|
||||
if (html) {
|
||||
|
||||
if (options.itemsContainer.cardBuilderHtml !== html) {
|
||||
options.itemsContainer.innerHTML = html;
|
||||
|
||||
@@ -1659,7 +1550,6 @@ import 'programStyles';
|
||||
|
||||
imageLoader.lazyChildren(options.itemsContainer);
|
||||
} else {
|
||||
|
||||
options.itemsContainer.innerHTML = html;
|
||||
options.itemsContainer.cardBuilderHtml = null;
|
||||
}
|
||||
@@ -1683,7 +1573,6 @@ import 'programStyles';
|
||||
indicatorsElem = card.querySelector('.cardIndicators');
|
||||
|
||||
if (!indicatorsElem) {
|
||||
|
||||
const cardImageContainer = card.querySelector('.cardImageContainer');
|
||||
indicatorsElem = document.createElement('div');
|
||||
indicatorsElem.classList.add('cardIndicators');
|
||||
@@ -1707,11 +1596,9 @@ import 'programStyles';
|
||||
let itemProgressBar = null;
|
||||
|
||||
if (userData.Played) {
|
||||
|
||||
playedIndicator = card.querySelector('.playedIndicator');
|
||||
|
||||
if (!playedIndicator) {
|
||||
|
||||
playedIndicator = document.createElement('div');
|
||||
playedIndicator.classList.add('playedIndicator');
|
||||
playedIndicator.classList.add('indicator');
|
||||
@@ -1720,10 +1607,8 @@ import 'programStyles';
|
||||
}
|
||||
playedIndicator.innerHTML = '<span class="material-icons indicatorIcon check"></span>';
|
||||
} else {
|
||||
|
||||
playedIndicator = card.querySelector('.playedIndicator');
|
||||
if (playedIndicator) {
|
||||
|
||||
playedIndicator.parentNode.removeChild(playedIndicator);
|
||||
}
|
||||
}
|
||||
@@ -1731,7 +1616,6 @@ import 'programStyles';
|
||||
countIndicator = card.querySelector('.countIndicator');
|
||||
|
||||
if (!countIndicator) {
|
||||
|
||||
countIndicator = document.createElement('div');
|
||||
countIndicator.classList.add('countIndicator');
|
||||
indicatorsElem = ensureIndicators(card, indicatorsElem);
|
||||
@@ -1739,10 +1623,8 @@ import 'programStyles';
|
||||
}
|
||||
countIndicator.innerHTML = userData.UnplayedItemCount;
|
||||
} else if (enableCountIndicator) {
|
||||
|
||||
countIndicator = card.querySelector('.countIndicator');
|
||||
if (countIndicator) {
|
||||
|
||||
countIndicator.parentNode.removeChild(countIndicator);
|
||||
}
|
||||
}
|
||||
@@ -1754,7 +1636,6 @@ import 'programStyles';
|
||||
});
|
||||
|
||||
if (progressHtml) {
|
||||
|
||||
itemProgressBar = card.querySelector('.itemProgressBar');
|
||||
|
||||
if (!itemProgressBar) {
|
||||
@@ -1773,7 +1654,6 @@ import 'programStyles';
|
||||
|
||||
itemProgressBar.innerHTML = progressHtml;
|
||||
} else {
|
||||
|
||||
itemProgressBar = card.querySelector('.itemProgressBar');
|
||||
if (itemProgressBar) {
|
||||
itemProgressBar.parentNode.removeChild(itemProgressBar);
|
||||
@@ -1804,7 +1684,7 @@ import 'programStyles';
|
||||
const cells = itemsContainer.querySelectorAll('.card[data-id="' + programId + '"]');
|
||||
|
||||
for (let i = 0, length = cells.length; i < length; i++) {
|
||||
let cell = cells[i];
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (!icon) {
|
||||
const indicatorsElem = ensureIndicators(cell);
|
||||
@@ -1823,8 +1703,8 @@ import 'programStyles';
|
||||
const cells = itemsContainer.querySelectorAll('.card[data-timerid="' + timerId + '"]');
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
let cell = cells[i];
|
||||
let icon = cell.querySelector('.timerIndicator');
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (icon) {
|
||||
icon.parentNode.removeChild(icon);
|
||||
}
|
||||
@@ -1841,8 +1721,8 @@ import 'programStyles';
|
||||
const cells = itemsContainer.querySelectorAll('.card[data-seriestimerid="' + cancelledTimerId + '"]');
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
let cell = cells[i];
|
||||
let icon = cell.querySelector('.timerIndicator');
|
||||
const cell = cells[i];
|
||||
const icon = cell.querySelector('.timerIndicator');
|
||||
if (icon) {
|
||||
icon.parentNode.removeChild(icon);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
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 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
|
||||
|
||||
var className = 'card itemAction chapterCard';
|
||||
let className = 'card itemAction chapterCard';
|
||||
|
||||
if (layoutManager.tv) {
|
||||
className += ' show-focus';
|
||||
@@ -17,38 +25,36 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
|
||||
}
|
||||
}
|
||||
|
||||
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [];
|
||||
var videoStream = mediaStreams.filter(function (i) {
|
||||
return i.Type === 'Video';
|
||||
const mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [];
|
||||
const videoStream = mediaStreams.filter(({Type}) => {
|
||||
return Type === 'Video';
|
||||
})[0] || {};
|
||||
|
||||
var shape = (options.backdropShape || 'backdrop');
|
||||
let shape = (options.backdropShape || 'backdrop');
|
||||
|
||||
if (videoStream.Width && videoStream.Height) {
|
||||
|
||||
if ((videoStream.Width / videoStream.Height) <= 1.2) {
|
||||
shape = (options.squareShape || 'square');
|
||||
}
|
||||
}
|
||||
|
||||
className += ' ' + shape + 'Card';
|
||||
className += ` ${shape}Card`;
|
||||
|
||||
if (options.block || options.rows) {
|
||||
className += ' block';
|
||||
}
|
||||
|
||||
var html = '';
|
||||
var itemsInRow = 0;
|
||||
let html = '';
|
||||
let itemsInRow = 0;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
for (var i = 0, length = chapters.length; i < length; i++) {
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
for (let i = 0, length = chapters.length; i < length; i++) {
|
||||
if (options.rows && itemsInRow === 0) {
|
||||
html += '<div class="cardColumn">';
|
||||
}
|
||||
|
||||
var chapter = chapters[i];
|
||||
const chapter = chapters[i];
|
||||
|
||||
html += buildChapterCard(item, apiClient, chapter, i, options, className, shape);
|
||||
itemsInRow++;
|
||||
@@ -62,51 +68,45 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
|
||||
return html;
|
||||
}
|
||||
|
||||
function getImgUrl(item, chapter, index, maxWidth, apiClient) {
|
||||
function getImgUrl({Id}, {ImageTag}, index, maxWidth, apiClient) {
|
||||
if (ImageTag) {
|
||||
return apiClient.getScaledImageUrl(Id, {
|
||||
|
||||
if (chapter.ImageTag) {
|
||||
|
||||
return apiClient.getScaledImageUrl(item.Id, {
|
||||
|
||||
maxWidth: maxWidth * 2,
|
||||
tag: chapter.ImageTag,
|
||||
maxWidth: maxWidth,
|
||||
tag: ImageTag,
|
||||
type: 'Chapter',
|
||||
index: index
|
||||
index
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildChapterCard(item, apiClient, chapter, index, options, className, shape) {
|
||||
function buildChapterCard(item, apiClient, chapter, index, {width, coverImage}, className, shape) {
|
||||
const imgUrl = getImgUrl(item, chapter, index, width || 400, apiClient);
|
||||
|
||||
var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient);
|
||||
|
||||
var cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
|
||||
if (options.coverImage) {
|
||||
let cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
|
||||
if (coverImage) {
|
||||
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 + '"';
|
||||
var cardImageContainer = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
|
||||
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}"`;
|
||||
let cardImageContainer = imgUrl ? (`<div class="${cardImageContainerClass} lazy" data-src="${imgUrl}">`) : (`<div class="${cardImageContainerClass}">`);
|
||||
|
||||
if (!imgUrl) {
|
||||
cardImageContainer += '<span class="material-icons cardImageIcon local_movies"></span>';
|
||||
}
|
||||
|
||||
var nameHtml = '';
|
||||
nameHtml += '<div class="cardText">' + chapter.Name + '</div>';
|
||||
nameHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + '</div>';
|
||||
let nameHtml = '';
|
||||
nameHtml += `<div class="cardText">${chapter.Name}</div>`;
|
||||
nameHtml += `<div class="cardText">${datetime.getDisplayRunningTime(chapter.StartPositionTicks)}</div>`;
|
||||
|
||||
var cardBoxCssClass = 'cardBox';
|
||||
var cardScalableClass = 'cardScalable';
|
||||
const cardBoxCssClass = 'cardBox';
|
||||
const cardScalableClass = 'cardScalable';
|
||||
|
||||
var html = '<button type="button" class="' + className + '"' + dataAttributes + '><div class="' + cardBoxCssClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainer + '</div><div class="innerCardFooter">' + nameHtml + '</div></div></div></button>';
|
||||
|
||||
return html;
|
||||
return `<button type="button" class="${className}"${dataAttributes}><div class="${cardBoxCssClass}"><div class="${cardScalableClass}"><div class="cardPadder-${shape}"></div>${cardImageContainer}</div><div class="innerCardFooter">${nameHtml}</div></div></div></button>`;
|
||||
}
|
||||
|
||||
function buildChapterCards(item, chapters, options) {
|
||||
|
||||
export function buildChapterCards(item, chapters, options) {
|
||||
if (options.parentContainer) {
|
||||
// Abort if the container has been disposed
|
||||
if (!document.body.contains(options.parentContainer)) {
|
||||
@@ -121,15 +121,16 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse
|
||||
}
|
||||
}
|
||||
|
||||
var html = buildChapterCardsHtml(item, chapters, options);
|
||||
const html = buildChapterCardsHtml(item, chapters, options);
|
||||
|
||||
options.itemsContainer.innerHTML = html;
|
||||
|
||||
imageLoader.lazyChildren(options.itemsContainer);
|
||||
}
|
||||
|
||||
return {
|
||||
buildChapterCards: buildChapterCards
|
||||
};
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
buildChapterCards: buildChapterCards
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
define(['cardBuilder'], function (cardBuilder) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
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 || {}, {
|
||||
cardLayout: false,
|
||||
centerText: true,
|
||||
@@ -15,8 +20,8 @@ define(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.buildCards(items, options);
|
||||
}
|
||||
|
||||
return {
|
||||
buildPeopleCards: buildPeopleCards
|
||||
};
|
||||
/* eslint-enable indent */
|
||||
|
||||
});
|
||||
export default {
|
||||
buildPeopleCards: buildPeopleCards
|
||||
};
|
||||
|
||||
@@ -1,34 +1,28 @@
|
||||
define([], function() {
|
||||
'use strict';
|
||||
|
||||
if (window.appMode === 'cordova' || window.appMode === 'android') {
|
||||
return {
|
||||
load: function () {
|
||||
window.chrome = window.chrome || {};
|
||||
class CastSenderApi {
|
||||
load() {
|
||||
if (window.appMode === 'cordova' || window.appMode === 'android') {
|
||||
window.chrome = window.chrome || {};
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
let ccLoaded = false;
|
||||
if (ccLoaded) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
var ccLoaded = false;
|
||||
return {
|
||||
load: function () {
|
||||
if (ccLoaded) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var fileref = document.createElement('script');
|
||||
fileref.setAttribute('type', 'text/javascript');
|
||||
return new Promise(function (resolve) {
|
||||
const fileref = document.createElement('script');
|
||||
fileref.setAttribute('type', 'text/javascript');
|
||||
|
||||
fileref.onload = function () {
|
||||
ccLoaded = true;
|
||||
resolve();
|
||||
};
|
||||
fileref.onload = function () {
|
||||
ccLoaded = true;
|
||||
resolve();
|
||||
};
|
||||
|
||||
fileref.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js');
|
||||
document.querySelector('head').appendChild(fileref);
|
||||
});
|
||||
}
|
||||
};
|
||||
fileref.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js');
|
||||
document.querySelector('head').appendChild(fileref);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default CastSenderApi;
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
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) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
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) {
|
||||
loading.show();
|
||||
var providerId = options.providerId;
|
||||
connectionManager.getApiClient(options.serverId).ajax({
|
||||
const providerId = options.providerId;
|
||||
window.connectionManager.getApiClient(options.serverId).ajax({
|
||||
type: 'POST',
|
||||
url: ApiClient.getUrl('LiveTv/ChannelMappings'),
|
||||
data: {
|
||||
data: JSON.stringify({
|
||||
providerId: providerId,
|
||||
tunerChannelId: channelId,
|
||||
providerChannelId: providerChannelId
|
||||
},
|
||||
}),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json'
|
||||
}).then(function (mapping) {
|
||||
var listItem = dom.parentWithClass(button, 'listItem');
|
||||
}).then(mapping => {
|
||||
const listItem = dom.parentWithClass(button, 'listItem');
|
||||
button.setAttribute('data-providerid', mapping.ProviderChannelId);
|
||||
listItem.querySelector('.secondary').innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName);
|
||||
loading.hide();
|
||||
@@ -23,42 +34,42 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
|
||||
}
|
||||
|
||||
function onChannelsElementClick(e) {
|
||||
var btnMap = dom.parentWithClass(e.target, 'btnMap');
|
||||
const btnMap = dom.parentWithClass(e.target, 'btnMap');
|
||||
|
||||
if (btnMap) {
|
||||
var channelId = btnMap.getAttribute('data-id');
|
||||
var providerChannelId = btnMap.getAttribute('data-providerid');
|
||||
var menuItems = currentMappingOptions.ProviderChannels.map(function (m) {
|
||||
const channelId = btnMap.getAttribute('data-id');
|
||||
const providerChannelId = btnMap.getAttribute('data-providerid');
|
||||
const menuItems = currentMappingOptions.ProviderChannels.map(m => {
|
||||
return {
|
||||
name: m.Name,
|
||||
id: m.Id,
|
||||
selected: m.Id.toLowerCase() === providerChannelId.toLowerCase()
|
||||
};
|
||||
}).sort(function (a, b) {
|
||||
}).sort((a, b) => {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
actionsheet.show({
|
||||
positionTo: btnMap,
|
||||
items: menuItems
|
||||
}).then(function (newChannelId) {
|
||||
}).then(newChannelId => {
|
||||
mapChannel(btnMap, channelId, newChannelId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getChannelMappingOptions(serverId, providerId) {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getJSON(apiClient.getUrl('LiveTv/ChannelMappingOptions', {
|
||||
providerId: providerId
|
||||
}));
|
||||
}
|
||||
|
||||
function getMappingSecondaryName(mapping, providerName) {
|
||||
return (mapping.ProviderChannelName || '') + ' - ' + providerName;
|
||||
return `${mapping.ProviderChannelName || ''} - ${providerName}`;
|
||||
}
|
||||
|
||||
function getTunerChannelHtml(channel, providerName) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
html += '<div class="listItem">';
|
||||
html += '<span class="material-icons listItemIcon dvr"></span>';
|
||||
html += '<div class="listItemBody two-line">';
|
||||
@@ -73,16 +84,16 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
|
||||
|
||||
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>';
|
||||
}
|
||||
|
||||
function getEditorHtml() {
|
||||
var html = '';
|
||||
let html = '';
|
||||
html += '<div class="formDialogContent smoothScrollY">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
html += '<form style="margin:auto;">';
|
||||
html += '<h1>' + globalize.translate('HeaderChannels') + '</h1>';
|
||||
html += `<h1>${globalize.translate('Channels')}</h1>`;
|
||||
html += '<div class="channels paperList">';
|
||||
html += '</div>';
|
||||
html += '</form>';
|
||||
@@ -91,30 +102,29 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
|
||||
}
|
||||
|
||||
function initEditor(dlg, options) {
|
||||
getChannelMappingOptions(options.serverId, options.providerId).then(function (result) {
|
||||
getChannelMappingOptions(options.serverId, options.providerId).then(result => {
|
||||
currentMappingOptions = result;
|
||||
var channelsElement = dlg.querySelector('.channels');
|
||||
channelsElement.innerHTML = result.TunerChannels.map(function (channel) {
|
||||
const channelsElement = dlg.querySelector('.channels');
|
||||
channelsElement.innerHTML = result.TunerChannels.map(channel => {
|
||||
return getTunerChannelHtml(channel, result.ProviderName);
|
||||
}).join('');
|
||||
channelsElement.addEventListener('click', onChannelsElementClick);
|
||||
});
|
||||
}
|
||||
|
||||
var currentMappingOptions;
|
||||
var self = this;
|
||||
let currentMappingOptions;
|
||||
|
||||
self.show = function () {
|
||||
var dialogOptions = {
|
||||
this.show = () => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true
|
||||
};
|
||||
dialogOptions.size = 'small';
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('ui-body-a');
|
||||
dlg.classList.add('background-theme-a');
|
||||
var html = '';
|
||||
var title = globalize.translate('MapChannels');
|
||||
let html = '';
|
||||
const title = globalize.translate('MapChannels');
|
||||
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">';
|
||||
@@ -124,13 +134,13 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
|
||||
html += getEditorHtml();
|
||||
dlg.innerHTML = html;
|
||||
initEditor(dlg, options);
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
return new Promise(function (resolve, reject) {
|
||||
return new Promise(resolve => {
|
||||
dlg.addEventListener('close', resolve);
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,234 +0,0 @@
|
||||
define(['events'], function (events) {
|
||||
'use strict';
|
||||
|
||||
// LinkParser
|
||||
//
|
||||
// https://github.com/ravisorg/LinkParser
|
||||
//
|
||||
// Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and
|
||||
// IPv6, unrecognised TLDs, and more.
|
||||
//
|
||||
// This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
// http://creativecommons.org/licenses/by-sa/4.0/
|
||||
(function () {
|
||||
|
||||
// Original URL regex from the Android android.text.util.Linkify function, found here:
|
||||
// http://stackoverflow.com/a/19696443
|
||||
//
|
||||
// However there were problems with it, most probably related to the fact it was
|
||||
// written in 2007, and it's been highly modified.
|
||||
//
|
||||
// 1) I didn't like the fact that it was tied to specific TLDs, since new ones
|
||||
// are being added all the time it wouldn't be reasonable to expect developer to
|
||||
// be continually updating their regular expressions.
|
||||
//
|
||||
// 2) It didn't allow unicode characters in the domains which are now allowed in
|
||||
// many languages, (including some IDN TLDs). Again these are constantly being
|
||||
// added to and it doesn't seem reasonable to hard-code them. Note this ended up
|
||||
// not being possible in standard JS due to the way it handles multibyte strings.
|
||||
// It is possible using XRegExp, however a big performance hit results. Disabled
|
||||
// for now.
|
||||
//
|
||||
// 3) It didn't allow for IPv6 hostnames
|
||||
// IPv6 regex from http://stackoverflow.com/a/17871737
|
||||
//
|
||||
// 4) It was very poorly commented
|
||||
//
|
||||
// 5) It wasn't as smart as it could have been about what should be part of a
|
||||
// URL and what should be part of human language.
|
||||
|
||||
var protocols = '(?:(?:http|https|rtsp|ftp):\\/\\/)';
|
||||
var credentials = "(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}" // username (1-64 normal or url escaped characters)
|
||||
+ "(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?" // followed by optional password (: + 1-25 normal or url escaped characters)
|
||||
+ '\\@)';
|
||||
|
||||
// IPv6 Regex http://forums.intermapper.com/viewtopic.php?t=452
|
||||
// by Dartware, LLC is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License
|
||||
// http://intermapper.com/
|
||||
var ipv6 = '('
|
||||
+ '(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))'
|
||||
+ '|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))'
|
||||
+ '|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))'
|
||||
+ '|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||
+ '|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||
+ '|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||
+ '|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||
+ '|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))'
|
||||
+ ')(%.+)?';
|
||||
|
||||
var ipv4 = '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.'
|
||||
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.'
|
||||
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.'
|
||||
+ '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])';
|
||||
|
||||
// This would have been a lot cleaner if JS RegExp supported conditionals...
|
||||
var linkRegExpString =
|
||||
|
||||
// begin match for protocol / username / password / host
|
||||
'(?:'
|
||||
|
||||
// ============================
|
||||
// If we have a recognized protocol at the beginning of the URL, we're
|
||||
// more relaxed about what we accept, because we assume the user wants
|
||||
// this to be a URL, and we're not accidentally matching human language
|
||||
+ protocols + '?'
|
||||
|
||||
// optional username:password@
|
||||
+ credentials + '?'
|
||||
|
||||
// IP address (both v4 and v6)
|
||||
+ '(?:'
|
||||
|
||||
// IPv6
|
||||
+ ipv6
|
||||
|
||||
// IPv4
|
||||
+ '|' + ipv4
|
||||
|
||||
+ ')'
|
||||
|
||||
// end match for protocol / username / password / host
|
||||
+ ')'
|
||||
|
||||
// optional port number
|
||||
+ '(?:\\:\\d{1,5})?'
|
||||
|
||||
// plus optional path and query params (no unicode allowed here?)
|
||||
+ '(?:'
|
||||
+ '\\/(?:'
|
||||
// some characters we'll accept because it's unlikely human language
|
||||
// would use them after a URL unless they were part of the url
|
||||
+ '(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])'
|
||||
+ '|(?:\\%[a-f0-9]{2})'
|
||||
// some characters are much more likely to be used AFTER a url and
|
||||
// were not intended to be included in the url itself. Mostly end
|
||||
// of sentence type things. It's also likely that the URL would
|
||||
// still work if any of these characters were missing from the end
|
||||
// because we parsed it incorrectly. For these characters to be accepted
|
||||
// they must be followed by another character that we're reasonably
|
||||
// sure is part of the url
|
||||
+ "|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})))"
|
||||
+ ')*'
|
||||
+ '|\\b|\$'
|
||||
+ ')';
|
||||
|
||||
// regex = XRegExp(regex,'gi');
|
||||
var linkRegExp = RegExp(linkRegExpString, 'gi');
|
||||
|
||||
var protocolRegExp = RegExp('^' + protocols, 'i');
|
||||
|
||||
// if url doesn't begin with a known protocol, add http by default
|
||||
function ensureProtocol(url) {
|
||||
if (!url.match(protocolRegExp)) {
|
||||
url = 'http://' + url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
// look for links in the text
|
||||
var LinkParser = {
|
||||
parse: function (text) {
|
||||
var links = [];
|
||||
var match;
|
||||
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (match = linkRegExp.exec(text)) {
|
||||
console.debug(match);
|
||||
var txt = match[0];
|
||||
var pos = match.index;
|
||||
var len = txt.length;
|
||||
var url = ensureProtocol(text);
|
||||
links.push({ 'pos': pos, 'text': txt, 'len': len, 'url': url });
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
window.LinkParser = LinkParser;
|
||||
})();
|
||||
|
||||
var cache = {};
|
||||
|
||||
function isValidIpAddress(address) {
|
||||
|
||||
var links = LinkParser.parse(address);
|
||||
|
||||
return links.length == 1;
|
||||
}
|
||||
|
||||
function isLocalIpAddress(address) {
|
||||
|
||||
address = address.toLowerCase();
|
||||
|
||||
if (address.indexOf('127.0.0.1') !== -1) {
|
||||
return true;
|
||||
}
|
||||
if (address.indexOf('localhost') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getServerAddress(apiClient) {
|
||||
|
||||
var serverAddress = apiClient.serverAddress();
|
||||
|
||||
if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) {
|
||||
return Promise.resolve(serverAddress);
|
||||
}
|
||||
|
||||
var cachedValue = getCachedValue(serverAddress);
|
||||
if (cachedValue) {
|
||||
return Promise.resolve(cachedValue);
|
||||
}
|
||||
|
||||
return apiClient.getEndpointInfo().then(function (endpoint) {
|
||||
if (endpoint.IsInNetwork) {
|
||||
return apiClient.getPublicSystemInfo().then(function (info) {
|
||||
var localAddress = info.LocalAddress;
|
||||
if (!localAddress) {
|
||||
console.debug('No valid local address returned, defaulting to external one');
|
||||
localAddress = serverAddress;
|
||||
}
|
||||
addToCache(serverAddress, localAddress);
|
||||
return localAddress;
|
||||
});
|
||||
} else {
|
||||
addToCache(serverAddress, serverAddress);
|
||||
return serverAddress;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearCache() {
|
||||
cache = {};
|
||||
}
|
||||
|
||||
function addToCache(key, value) {
|
||||
cache[key] = {
|
||||
value: value,
|
||||
time: new Date().getTime()
|
||||
};
|
||||
}
|
||||
|
||||
function getCachedValue(key) {
|
||||
|
||||
var obj = cache[key];
|
||||
|
||||
if (obj && (new Date().getTime() - obj.time) < 180000) {
|
||||
return obj.value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
events.on(ConnectionManager, 'localusersignedin', clearCache);
|
||||
events.on(ConnectionManager, 'localusersignedout', clearCache);
|
||||
|
||||
return {
|
||||
getServerAddress: getServerAddress
|
||||
};
|
||||
});
|
||||
@@ -1,16 +1,30 @@
|
||||
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) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import layoutManager from 'layoutManager';
|
||||
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) {
|
||||
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 = window.connectionManager.getApiClient(currentServerId);
|
||||
|
||||
if (collectionId) {
|
||||
addToCollection(apiClient, panel, collectionId);
|
||||
@@ -23,8 +37,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
}
|
||||
|
||||
function createCollection(apiClient, dlg) {
|
||||
|
||||
var url = apiClient.getUrl('Collections', {
|
||||
const url = apiClient.getUrl('Collections', {
|
||||
|
||||
Name: dlg.querySelector('#txtNewCollectionName').value,
|
||||
IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked,
|
||||
@@ -36,27 +49,23 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
url: url,
|
||||
dataType: 'json'
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
}).then(result => {
|
||||
loading.hide();
|
||||
|
||||
var id = result.Id;
|
||||
const id = result.Id;
|
||||
|
||||
dlg.submitted = true;
|
||||
dialogHelper.close(dlg);
|
||||
redirectToCollection(apiClient, id);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function redirectToCollection(apiClient, id) {
|
||||
|
||||
appRouter.showItem(id, apiClient.serverId());
|
||||
}
|
||||
|
||||
function addToCollection(apiClient, dlg, id) {
|
||||
|
||||
var url = apiClient.getUrl('Collections/' + id + '/Items', {
|
||||
const url = apiClient.getUrl(`Collections/${id}/Items`, {
|
||||
|
||||
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
|
||||
});
|
||||
@@ -65,14 +74,13 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
type: 'POST',
|
||||
url: url
|
||||
|
||||
}).then(function () {
|
||||
|
||||
}).then(() => {
|
||||
loading.hide();
|
||||
|
||||
dlg.submitted = true;
|
||||
dialogHelper.close(dlg);
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('MessageItemsAdded'));
|
||||
});
|
||||
});
|
||||
@@ -83,14 +91,13 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
}
|
||||
|
||||
function populateCollections(panel) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var select = panel.querySelector('#selectCollectionToAddTo');
|
||||
const select = panel.querySelector('#selectCollectionToAddTo');
|
||||
|
||||
panel.querySelector('.newCollectionInfo').classList.add('hide');
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
|
||||
Recursive: true,
|
||||
IncludeItemTypes: 'BoxSet',
|
||||
@@ -98,16 +105,14 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
EnableTotalRecordCount: false
|
||||
};
|
||||
|
||||
var apiClient = connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) {
|
||||
const apiClient = window.connectionManager.getApiClient(currentServerId);
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), options).then(result => {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
html += `<option value="">${globalize.translate('OptionNew')}</option>`;
|
||||
|
||||
html += '<option value="">' + globalize.translate('OptionNew') + '</option>';
|
||||
|
||||
html += result.Items.map(function (i) {
|
||||
|
||||
return '<option value="' + i.Id + '">' + i.Name + '</option>';
|
||||
html += result.Items.map(i => {
|
||||
return `<option value="${i.Id}">${i.Name}</option>`;
|
||||
});
|
||||
|
||||
select.innerHTML = html;
|
||||
@@ -119,8 +124,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
}
|
||||
|
||||
function getEditorHtml() {
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
@@ -134,27 +138,27 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
html += '<br/>';
|
||||
html += '<br/>';
|
||||
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 class="newCollectionInfo">';
|
||||
|
||||
html += '<div class="inputContainer">';
|
||||
html += '<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="' + globalize.translate('LabelName') + '" />';
|
||||
html += '<div class="fieldDescription">' + globalize.translate('NewCollectionNameExample') + '</div>';
|
||||
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>';
|
||||
|
||||
html += '<label class="checkboxContainer">';
|
||||
html += '<input is="emby-checkbox" type="checkbox" id="chkEnableInternetMetadata" />';
|
||||
html += '<span>' + globalize.translate('SearchForCollectionInternetMetadata') + '</span>';
|
||||
html += `<span>${globalize.translate('SearchForCollectionInternetMetadata')}</span>`;
|
||||
html += '</label>';
|
||||
|
||||
// newCollectionInfo
|
||||
html += '</div>';
|
||||
|
||||
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 += '<input type="hidden" class="fldSelectedItemIds" />';
|
||||
@@ -167,7 +171,6 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
}
|
||||
|
||||
function initEditor(content, items) {
|
||||
|
||||
content.querySelector('#selectCollectionToAddTo').addEventListener('change', function () {
|
||||
if (this.value) {
|
||||
content.querySelector('.newCollectionInfo').classList.add('hide');
|
||||
@@ -188,7 +191,7 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
} else {
|
||||
content.querySelector('.fldSelectCollection').classList.add('hide');
|
||||
|
||||
var selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo');
|
||||
const selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo');
|
||||
selectCollectionToAddTo.innerHTML = '';
|
||||
selectCollectionToAddTo.value = '';
|
||||
triggerChange(selectCollectionToAddTo);
|
||||
@@ -196,79 +199,70 @@ define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectio
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
import('scrollHelper').then((scrollHelper) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function CollectionEditor() {
|
||||
export class showEditor {
|
||||
constructor(options) {
|
||||
const items = options.items || {};
|
||||
currentServerId = options.serverId;
|
||||
|
||||
}
|
||||
|
||||
CollectionEditor.prototype.show = function (options) {
|
||||
|
||||
var items = options.items || {};
|
||||
currentServerId = options.serverId;
|
||||
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
var title = items.length ? globalize.translate('HeaderAddToCollection') : globalize.translate('NewCollection');
|
||||
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
html += title;
|
||||
html += '</h3>';
|
||||
|
||||
if (appHost.supports('externallinks')) {
|
||||
html += '<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://web.archive.org/web/20181216120305/https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="' + globalize.translate('Help') + '"><span class="material-icons info"></span><span style="margin-left:.25em;">' + globalize.translate('Help') + '</span></a>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += getEditorHtml();
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
initEditor(dlg, items);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
||||
}
|
||||
|
||||
return dialogHelper.open(dlg).then(function () {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
if (dlg.submitted) {
|
||||
return Promise.resolve();
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
let html = '';
|
||||
const title = items.length ? globalize.translate('HeaderAddToCollection') : globalize.translate('NewCollection');
|
||||
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
html += title;
|
||||
html += '</h3>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += getEditorHtml();
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
initEditor(dlg, items);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
};
|
||||
return dialogHelper.open(dlg).then(() => {
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
|
||||
return CollectionEditor;
|
||||
});
|
||||
if (dlg.submitted) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default showEditor;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
import dialog from 'dialog';
|
||||
import globalize from 'globalize';
|
||||
|
||||
/* eslint-disable indent */
|
||||
export default (() => {
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.split(find).join(replace);
|
||||
}
|
||||
|
||||
if (browser.tv && window.confirm) {
|
||||
// Use the native confirm dialog
|
||||
return function (options) {
|
||||
return options => {
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
title: '',
|
||||
@@ -15,8 +18,8 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
|
||||
};
|
||||
}
|
||||
|
||||
var text = replaceAll(options.text || '', '<br/>', '\n');
|
||||
var result = confirm(text);
|
||||
const text = replaceAll(options.text || '', '<br/>', '\n');
|
||||
const result = window.confirm(text);
|
||||
|
||||
if (result) {
|
||||
return Promise.resolve();
|
||||
@@ -26,8 +29,8 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
|
||||
};
|
||||
} else {
|
||||
// Use our own dialog
|
||||
return function (text, title) {
|
||||
var options;
|
||||
return (text, title) => {
|
||||
let options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
@@ -37,7 +40,7 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
|
||||
options = text;
|
||||
}
|
||||
|
||||
var items = [];
|
||||
const items = [];
|
||||
|
||||
items.push({
|
||||
name: options.cancelText || globalize.translate('ButtonCancel'),
|
||||
@@ -53,7 +56,7 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
|
||||
|
||||
options.buttons = items;
|
||||
|
||||
return dialog(options).then(function (result) {
|
||||
return dialog.show(options).then(result => {
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -62,4 +65,5 @@ define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize)
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
})();
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
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) {
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
var enableTvLayout = layoutManager.tv;
|
||||
const enableTvLayout = layoutManager.tv;
|
||||
|
||||
if (enableTvLayout) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
@@ -22,7 +32,7 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
|
||||
|
||||
dlg.classList.add('align-items-center');
|
||||
dlg.classList.add('justify-content-center');
|
||||
var formDialogContent = dlg.querySelector('.formDialogContent');
|
||||
const formDialogContent = dlg.querySelector('.formDialogContent');
|
||||
formDialogContent.classList.add('no-grow');
|
||||
|
||||
if (enableTvLayout) {
|
||||
@@ -30,41 +40,36 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
|
||||
formDialogContent.style['max-height'] = '60%';
|
||||
scrollHelper.centerFocus.on(formDialogContent, false);
|
||||
} 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.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
// dialogHelper.close(dlg);
|
||||
//});
|
||||
|
||||
if (options.title) {
|
||||
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || '';
|
||||
} else {
|
||||
dlg.querySelector('.formDialogHeaderTitle').classList.add('hide');
|
||||
}
|
||||
|
||||
var displayText = options.html || options.text || '';
|
||||
const displayText = options.html || options.text || '';
|
||||
dlg.querySelector('.text').innerHTML = displayText;
|
||||
|
||||
if (!displayText) {
|
||||
dlg.querySelector('.dialogContentInner').classList.add('hide');
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
var html = '';
|
||||
var hasDescriptions = false;
|
||||
let i;
|
||||
let length;
|
||||
let html = '';
|
||||
let hasDescriptions = false;
|
||||
|
||||
for (i = 0, length = options.buttons.length; i < length; i++) {
|
||||
const item = options.buttons[i];
|
||||
const autoFocus = i === 0 ? ' autofocus' : '';
|
||||
|
||||
var item = options.buttons[i];
|
||||
var autoFocus = i === 0 ? ' autofocus' : '';
|
||||
|
||||
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
|
||||
let buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
|
||||
|
||||
if (item.type) {
|
||||
buttonClass += ' button-' + item.type;
|
||||
buttonClass += ` button-${item.type}`;
|
||||
}
|
||||
|
||||
if (item.description) {
|
||||
@@ -75,10 +80,10 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
|
||||
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) {
|
||||
html += '<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">' + item.description + '</div>';
|
||||
html += `<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">${item.description}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,19 +93,18 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
|
||||
dlg.querySelector('.formDialogFooter').classList.add('formDialogFooter-vertical');
|
||||
}
|
||||
|
||||
var dialogResult;
|
||||
let dialogResult;
|
||||
function onButtonClick() {
|
||||
dialogResult = this.getAttribute('data-id');
|
||||
dialogHelper.close(dlg);
|
||||
}
|
||||
|
||||
var buttons = dlg.querySelectorAll('.btnOption');
|
||||
const buttons = dlg.querySelectorAll('.btnOption');
|
||||
for (i = 0, length = buttons.length; i < length; i++) {
|
||||
buttons[i].addEventListener('click', onButtonClick);
|
||||
}
|
||||
|
||||
return dialogHelper.open(dlg).then(function () {
|
||||
|
||||
return dialogHelper.open(dlg).then(() => {
|
||||
if (enableTvLayout) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
@@ -113,9 +117,8 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
|
||||
});
|
||||
}
|
||||
|
||||
return function (text, title) {
|
||||
|
||||
var options;
|
||||
export async function show(text, title) {
|
||||
let options;
|
||||
if (typeof text === 'string') {
|
||||
options = {
|
||||
title: title,
|
||||
@@ -125,10 +128,13 @@ define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 're
|
||||
options = text;
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['text!./dialog.template.html'], function (template) {
|
||||
showDialog(options, template).then(resolve, reject);
|
||||
});
|
||||
const { default: template } = await import('text!./dialog.template.html');
|
||||
return new Promise((resolve, reject) => {
|
||||
showDialog(options, template).then(resolve, reject);
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
||||
@@ -4,12 +4,8 @@
|
||||
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
<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 class="formDialogFooter formDialogFooter-clear formDialogFooter-flex" style="padding-bottom: 1.5em;">
|
||||
</div>
|
||||
<div class="formDialogFooter formDialogFooter-clear formDialogFooter-flex" style="margin:1em"></div>
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', 'dom', 'css!./dialoghelper.css', 'scrollStyles'], function (appRouter, focusManager, browser, layoutManager, inputManager, dom) {
|
||||
'use strict';
|
||||
import appRouter from 'appRouter';
|
||||
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() {
|
||||
|
||||
// too slow
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
@@ -14,7 +21,6 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function removeCenterFocus(dlg) {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
if (dlg.classList.contains('scrollX')) {
|
||||
centerFocus(dlg, true, false);
|
||||
@@ -25,9 +31,8 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function tryRemoveElement(elem) {
|
||||
var parentNode = elem.parentNode;
|
||||
const parentNode = elem.parentNode;
|
||||
if (parentNode) {
|
||||
|
||||
// Seeing crashes in edge webview
|
||||
try {
|
||||
parentNode.removeChild(elem);
|
||||
@@ -38,15 +43,13 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function DialogHashHandler(dlg, hash, resolve) {
|
||||
|
||||
var self = this;
|
||||
const self = this;
|
||||
self.originalUrl = window.location.href;
|
||||
var activeElement = document.activeElement;
|
||||
var removeScrollLockOnClose = false;
|
||||
const activeElement = document.activeElement;
|
||||
let removeScrollLockOnClose = false;
|
||||
|
||||
function onHashChange(e) {
|
||||
|
||||
var isBack = self.originalUrl === window.location.href;
|
||||
const isBack = self.originalUrl === window.location.href;
|
||||
|
||||
if (isBack || !isOpened(dlg)) {
|
||||
window.removeEventListener('popstate', onHashChange);
|
||||
@@ -59,7 +62,6 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function onBackCommand(e) {
|
||||
|
||||
if (e.detail.command === 'back') {
|
||||
self.closedByBack = true;
|
||||
e.preventDefault();
|
||||
@@ -69,7 +71,6 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
|
||||
if (!isHistoryEnabled(dlg)) {
|
||||
inputManager.off(dlg, onBackCommand);
|
||||
}
|
||||
@@ -84,9 +85,9 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
if (!self.closedByBack && isHistoryEnabled(dlg)) {
|
||||
var state = history.state || {};
|
||||
const state = window.history.state || {};
|
||||
if (state.dialogId === hash) {
|
||||
history.back();
|
||||
window.history.back();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
if (dlg.getAttribute('data-removeonclose') !== 'false') {
|
||||
removeCenterFocus(dlg);
|
||||
|
||||
var dialogContainer = dlg.dialogContainer;
|
||||
const dialogContainer = dlg.dialogContainer;
|
||||
if (dialogContainer) {
|
||||
tryRemoveElement(dialogContainer);
|
||||
dlg.dialogContainer = null;
|
||||
@@ -108,7 +109,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
|
||||
//resolve();
|
||||
// if we just called history.back(), then use a timeout to allow the history events to fire first
|
||||
setTimeout(function () {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
element: dlg,
|
||||
closedByBack: self.closedByBack
|
||||
@@ -118,7 +119,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
|
||||
var center = !dlg.classList.contains('dialog-fixedSize');
|
||||
const center = !dlg.classList.contains('dialog-fixedSize');
|
||||
if (center) {
|
||||
dlg.classList.add('centeredDialog');
|
||||
}
|
||||
@@ -141,7 +142,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
animateDialogOpen(dlg);
|
||||
|
||||
if (isHistoryEnabled(dlg)) {
|
||||
appRouter.pushState({ dialogId: hash }, 'Dialog', '#' + hash);
|
||||
appRouter.pushState({ dialogId: hash }, 'Dialog', `#${hash}`);
|
||||
|
||||
window.addEventListener('popstate', onHashChange);
|
||||
} else {
|
||||
@@ -150,11 +151,10 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function addBackdropOverlay(dlg) {
|
||||
|
||||
var backdrop = document.createElement('div');
|
||||
const backdrop = document.createElement('div');
|
||||
backdrop.classList.add('dialogBackdrop');
|
||||
|
||||
var backdropParent = dlg.dialogContainer || dlg;
|
||||
const backdropParent = dlg.dialogContainer || dlg;
|
||||
backdropParent.parentNode.insertBefore(backdrop, backdropParent);
|
||||
dlg.backdrop = backdrop;
|
||||
|
||||
@@ -162,7 +162,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
void backdrop.offsetWidth;
|
||||
backdrop.classList.add('dialogBackdropOpened');
|
||||
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', function (e) {
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', e => {
|
||||
if (e.target === dlg.dialogContainer) {
|
||||
close(dlg);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', function (e) {
|
||||
dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', e => {
|
||||
if (e.target === dlg.dialogContainer) {
|
||||
// Close the application dialog menu
|
||||
close(dlg);
|
||||
@@ -184,40 +184,36 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
return dlg.getAttribute('data-history') === 'true';
|
||||
}
|
||||
|
||||
function open(dlg) {
|
||||
|
||||
export function open(dlg) {
|
||||
if (globalOnOpenCallback) {
|
||||
globalOnOpenCallback(dlg);
|
||||
}
|
||||
|
||||
var parent = dlg.parentNode;
|
||||
const parent = dlg.parentNode;
|
||||
if (parent) {
|
||||
parent.removeChild(dlg);
|
||||
}
|
||||
|
||||
var dialogContainer = document.createElement('div');
|
||||
const dialogContainer = document.createElement('div');
|
||||
dialogContainer.classList.add('dialogContainer');
|
||||
dialogContainer.appendChild(dlg);
|
||||
dlg.dialogContainer = dialogContainer;
|
||||
document.body.appendChild(dialogContainer);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
new DialogHashHandler(dlg, 'dlg' + new Date().getTime(), resolve);
|
||||
return new Promise((resolve, reject) => {
|
||||
new DialogHashHandler(dlg, `dlg${new Date().getTime()}`, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function isOpened(dlg) {
|
||||
|
||||
//return dlg.opened;
|
||||
return !dlg.classList.contains('hide');
|
||||
}
|
||||
|
||||
function close(dlg) {
|
||||
|
||||
export function close(dlg) {
|
||||
if (isOpened(dlg)) {
|
||||
if (isHistoryEnabled(dlg)) {
|
||||
history.back();
|
||||
window.history.back();
|
||||
} else {
|
||||
closeDialog(dlg);
|
||||
}
|
||||
@@ -225,15 +221,13 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function closeDialog(dlg) {
|
||||
|
||||
if (!dlg.classList.contains('hide')) {
|
||||
|
||||
dlg.dispatchEvent(new CustomEvent('closing', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
|
||||
var onAnimationFinish = function () {
|
||||
const onAnimationFinish = () => {
|
||||
focusManager.popScope(dlg);
|
||||
|
||||
dlg.classList.add('hide');
|
||||
@@ -248,8 +242,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function animateDialogOpen(dlg) {
|
||||
|
||||
var onAnimationFinish = function () {
|
||||
const onAnimationFinish = () => {
|
||||
focusManager.pushScope(dlg);
|
||||
|
||||
if (dlg.getAttribute('data-autofocus') === 'true') {
|
||||
@@ -263,8 +256,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
var onFinish = function () {
|
||||
const onFinish = () => {
|
||||
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
});
|
||||
@@ -280,27 +272,24 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function animateDialogClose(dlg, onAnimationFinish) {
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
var animated = true;
|
||||
let animated = true;
|
||||
|
||||
switch (dlg.animationConfig.exit.name) {
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
animated = false;
|
||||
break;
|
||||
}
|
||||
var onFinish = function () {
|
||||
const onFinish = () => {
|
||||
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
|
||||
once: true
|
||||
});
|
||||
@@ -318,10 +307,9 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
onAnimationFinish();
|
||||
}
|
||||
|
||||
var supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
|
||||
const supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
|
||||
|
||||
function shouldLockDocumentScroll(options) {
|
||||
|
||||
if (supportsOverscrollBehavior && (options.size || !browser.touch)) {
|
||||
return false;
|
||||
}
|
||||
@@ -342,8 +330,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function removeBackdrop(dlg) {
|
||||
|
||||
var backdrop = dlg.backdrop;
|
||||
const backdrop = dlg.backdrop;
|
||||
|
||||
if (!backdrop) {
|
||||
return;
|
||||
@@ -351,12 +338,11 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
|
||||
dlg.backdrop = null;
|
||||
|
||||
var onAnimationFinish = function () {
|
||||
const onAnimationFinish = () => {
|
||||
tryRemoveElement(backdrop);
|
||||
};
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
backdrop.classList.remove('dialogBackdropOpened');
|
||||
|
||||
// this is not firing animatonend
|
||||
@@ -368,20 +354,19 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
import('scrollHelper').then((scrollHelper) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function createDialog(options) {
|
||||
|
||||
export function createDialog(options) {
|
||||
options = options || {};
|
||||
|
||||
// If there's no native dialog support, use a plain div
|
||||
// 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
|
||||
var dlg = document.createElement('div');
|
||||
const dlg = document.createElement('div');
|
||||
|
||||
dlg.classList.add('focuscontainer');
|
||||
dlg.classList.add('hide');
|
||||
@@ -390,7 +375,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
dlg.setAttribute('data-lockscroll', 'true');
|
||||
}
|
||||
|
||||
if (options.enableHistory !== false && appRouter.enableNativeHistory()) {
|
||||
if (options.enableHistory === true) {
|
||||
dlg.setAttribute('data-history', 'true');
|
||||
}
|
||||
|
||||
@@ -406,17 +391,14 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
dlg.setAttribute('data-autofocus', 'true');
|
||||
}
|
||||
|
||||
var defaultEntryAnimation;
|
||||
var defaultExitAnimation;
|
||||
|
||||
defaultEntryAnimation = 'scaleup';
|
||||
defaultExitAnimation = 'scaledown';
|
||||
var entryAnimation = options.entryAnimation || defaultEntryAnimation;
|
||||
var exitAnimation = options.exitAnimation || defaultExitAnimation;
|
||||
const defaultEntryAnimation = 'scaleup';
|
||||
const defaultExitAnimation = 'scaledown';
|
||||
const entryAnimation = options.entryAnimation || defaultEntryAnimation;
|
||||
const exitAnimation = options.exitAnimation || defaultExitAnimation;
|
||||
|
||||
// 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);
|
||||
var exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220);
|
||||
const entryAnimationDuration = options.entryAnimationDuration || (options.size !== 'fullscreen' ? 180 : 280);
|
||||
const exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220);
|
||||
|
||||
dlg.animationConfig = {
|
||||
// scale up
|
||||
@@ -461,24 +443,22 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
|
||||
if (options.size) {
|
||||
dlg.classList.add('dialog-fixedSize');
|
||||
dlg.classList.add('dialog-' + options.size);
|
||||
dlg.classList.add(`dialog-${options.size}`);
|
||||
}
|
||||
|
||||
if (enableAnimation()) {
|
||||
|
||||
switch (dlg.animationConfig.entry.name) {
|
||||
|
||||
case 'fadein':
|
||||
dlg.style.animation = 'fadein ' + entryAnimationDuration + 'ms ease-out normal';
|
||||
dlg.style.animation = `fadein ${entryAnimationDuration}ms ease-out normal`;
|
||||
break;
|
||||
case 'scaleup':
|
||||
dlg.style.animation = 'scaleup ' + entryAnimationDuration + 'ms ease-out normal both';
|
||||
dlg.style.animation = `scaleup ${entryAnimationDuration}ms ease-out normal both`;
|
||||
break;
|
||||
case 'slideup':
|
||||
dlg.style.animation = 'slideup ' + entryAnimationDuration + 'ms ease-out normal';
|
||||
dlg.style.animation = `slideup ${entryAnimationDuration}ms ease-out normal`;
|
||||
break;
|
||||
case 'slidedown':
|
||||
dlg.style.animation = 'slidedown ' + entryAnimationDuration + 'ms ease-out normal';
|
||||
dlg.style.animation = `slidedown ${entryAnimationDuration}ms ease-out normal`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -488,12 +468,15 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager',
|
||||
return dlg;
|
||||
}
|
||||
|
||||
return {
|
||||
open: open,
|
||||
close: close,
|
||||
createDialog: createDialog,
|
||||
setOnOpen: function (val) {
|
||||
globalOnOpenCallback = val;
|
||||
}
|
||||
};
|
||||
});
|
||||
export function setOnOpen(val) {
|
||||
globalOnOpenCallback = val;
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
open: open,
|
||||
close: close,
|
||||
createDialog: createDialog,
|
||||
setOnOpen: setOnOpen
|
||||
};
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-input', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-button'], function(loading, dialogHelper, dom, globalize) {
|
||||
'use strict';
|
||||
import loading from 'loading';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import dom from 'dom';
|
||||
import globalize from 'globalize';
|
||||
import 'listViewStyle';
|
||||
import 'emby-input';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./directorybrowser';
|
||||
import 'formDialogStyle';
|
||||
import 'emby-button';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function getSystemInfo() {
|
||||
return systemInfo ? Promise.resolve(systemInfo) : ApiClient.getPublicSystemInfo().then(
|
||||
function(info) {
|
||||
info => {
|
||||
systemInfo = info;
|
||||
return info;
|
||||
}
|
||||
@@ -21,9 +31,9 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
|
||||
loading.show();
|
||||
|
||||
var promises = [];
|
||||
const promises = [];
|
||||
|
||||
if ('Network' === path) {
|
||||
if (path === 'Network') {
|
||||
promises.push(ApiClient.getNetworkDevices());
|
||||
} else {
|
||||
if (path) {
|
||||
@@ -35,10 +45,10 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
}
|
||||
|
||||
Promise.all(promises).then(
|
||||
function(responses) {
|
||||
var folders = responses[0];
|
||||
var parentPath = responses[1] || '';
|
||||
var html = '';
|
||||
responses => {
|
||||
const folders = responses[0];
|
||||
const parentPath = responses[1] || '';
|
||||
let html = '';
|
||||
|
||||
page.querySelector('.results').scrollTop = 0;
|
||||
page.querySelector('#txtDirectoryPickerPath').value = path || '';
|
||||
@@ -46,9 +56,9 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
if (path) {
|
||||
html += getItem('lnkPath lnkDirectory', '', parentPath, '...');
|
||||
}
|
||||
for (var i = 0, length = folders.length; i < length; i++) {
|
||||
var folder = folders[i];
|
||||
var cssClass = 'File' === folder.Type ? 'lnkPath lnkFile' : 'lnkPath lnkDirectory';
|
||||
for (let i = 0, length = folders.length; i < length; i++) {
|
||||
const folder = folders[i];
|
||||
const cssClass = folder.Type === 'File' ? 'lnkPath lnkFile' : 'lnkPath lnkDirectory';
|
||||
html += getItem(cssClass, folder.Type, folder.Path, folder.Name);
|
||||
}
|
||||
|
||||
@@ -58,7 +68,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
|
||||
page.querySelector('.results').innerHTML = html;
|
||||
loading.hide();
|
||||
}, function() {
|
||||
}, () => {
|
||||
if (updatePathOnError) {
|
||||
page.querySelector('#txtDirectoryPickerPath').value = '';
|
||||
page.querySelector('.results').innerHTML = '';
|
||||
@@ -69,8 +79,8 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
}
|
||||
|
||||
function getItem(cssClass, type, path, name) {
|
||||
var html = '';
|
||||
html += '<div class="listItem listItem-border ' + cssClass + '" data-type="' + type + '" data-path="' + path + '">';
|
||||
let html = '';
|
||||
html += `<div class="listItem listItem-border ${cssClass}" data-type="${type}" data-path="${path}">`;
|
||||
html += '<div class="listItemBody" style="padding-left:0;padding-top:.5em;padding-bottom:.5em;">';
|
||||
html += '<div class="listItemBodyText">';
|
||||
html += name;
|
||||
@@ -82,19 +92,19 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
}
|
||||
|
||||
function getEditorHtml(options, systemInfo) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
html += '<div class="formDialogContent scrollY">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered" style="padding-top:2em;">';
|
||||
if (!options.pathReadOnly) {
|
||||
var instruction = options.instruction ? options.instruction + '<br/><br/>' : '';
|
||||
const instruction = options.instruction ? `${options.instruction}<br/><br/>` : '';
|
||||
html += '<div class="infoBanner" style="margin-bottom:1.5em;">';
|
||||
html += instruction;
|
||||
if ('bsd' === systemInfo.OperatingSystem.toLowerCase()) {
|
||||
if (systemInfo.OperatingSystem.toLowerCase() === 'bsd') {
|
||||
html += '<br/>';
|
||||
html += '<br/>';
|
||||
html += globalize.translate('MessageDirectoryPickerBSDInstruction');
|
||||
html += '<br/>';
|
||||
} else if ('linux' === systemInfo.OperatingSystem.toLowerCase()) {
|
||||
} else if (systemInfo.OperatingSystem.toLowerCase() === 'linux') {
|
||||
html += '<br/>';
|
||||
html += '<br/>';
|
||||
html += globalize.translate('MessageDirectoryPickerLinuxInstruction');
|
||||
@@ -105,17 +115,17 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
html += '<form style="margin:auto;">';
|
||||
html += '<div class="inputContainer" style="display: flex; align-items: center;">';
|
||||
html += '<div style="flex-grow:1;">';
|
||||
var labelKey;
|
||||
let labelKey;
|
||||
if (options.includeFiles !== true) {
|
||||
labelKey = 'LabelFolder';
|
||||
} else {
|
||||
labelKey = 'LabelPath';
|
||||
}
|
||||
var readOnlyAttribute = options.pathReadOnly ? ' readonly' : '';
|
||||
html += '<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ' + readOnlyAttribute + ' label="' + globalize.translate(labelKey) + '"/>';
|
||||
const readOnlyAttribute = options.pathReadOnly ? ' readonly' : '';
|
||||
html += `<input is="emby-input" id="txtDirectoryPickerPath" type="text" required="required" ${readOnlyAttribute} label="${globalize.translate(labelKey)}"/>`;
|
||||
html += '</div>';
|
||||
if (!readOnlyAttribute) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="' + globalize.translate('ButtonRefresh') + '"><span class="material-icons search"></span></button>';
|
||||
html += `<button type="button" is="paper-icon-button-light" class="btnRefreshDirectories emby-input-iconbutton" title="${globalize.translate('Refresh')}"><span class="material-icons search"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
if (!readOnlyAttribute) {
|
||||
@@ -123,14 +133,14 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
}
|
||||
if (options.enableNetworkSharePath) {
|
||||
html += '<div class="inputContainer" style="margin-top:2em;">';
|
||||
html += '<input is="emby-input" id="txtNetworkPath" type="text" label="' + globalize.translate('LabelOptionalNetworkPath') + '"/>';
|
||||
html += `<input is="emby-input" id="txtNetworkPath" type="text" label="${globalize.translate('LabelOptionalNetworkPath')}"/>`;
|
||||
html += '<div class="fieldDescription">';
|
||||
html += globalize.translate('LabelOptionalNetworkPathHelp', '<b>\\\\server</b>', '<b>\\\\192.168.1.101</b>');
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
html += '<div class="formDialogFooter">';
|
||||
html += '<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">' + globalize.translate('ButtonOk') + '</button>';
|
||||
html += `<button is="emby-button" type="submit" class="raised button-submit block formDialogFooterItem">${globalize.translate('ButtonOk')}</button>`;
|
||||
html += '</div>';
|
||||
html += '</form>';
|
||||
html += '</div>';
|
||||
@@ -147,7 +157,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
}
|
||||
|
||||
function alertTextWithOptions(options) {
|
||||
require(['alert'], function(alert) {
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(options);
|
||||
});
|
||||
}
|
||||
@@ -156,11 +166,12 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
return apiClient.ajax({
|
||||
type: 'POST',
|
||||
url: apiClient.getUrl('Environment/ValidatePath'),
|
||||
data: {
|
||||
data: JSON.stringify({
|
||||
ValidateWriteable: validateWriteable,
|
||||
Path: path
|
||||
}
|
||||
}).catch(function(response) {
|
||||
}),
|
||||
contentType: 'application/json'
|
||||
}).catch(response => {
|
||||
if (response) {
|
||||
if (response.status === 404) {
|
||||
alertText(globalize.translate('PathNotFound'));
|
||||
@@ -180,10 +191,10 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
}
|
||||
|
||||
function initEditor(content, options, fileOptions) {
|
||||
content.addEventListener('click', function(e) {
|
||||
var lnkPath = dom.parentWithClass(e.target, 'lnkPath');
|
||||
content.addEventListener('click', e => {
|
||||
const lnkPath = dom.parentWithClass(e.target, 'lnkPath');
|
||||
if (lnkPath) {
|
||||
var path = lnkPath.getAttribute('data-path');
|
||||
const path = lnkPath.getAttribute('data-path');
|
||||
if (lnkPath.classList.contains('lnkFile')) {
|
||||
content.querySelector('#txtDirectoryPickerPath').value = path;
|
||||
} else {
|
||||
@@ -192,25 +203,25 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
}
|
||||
});
|
||||
|
||||
content.addEventListener('click', function(e) {
|
||||
content.addEventListener('click', e => {
|
||||
if (dom.parentWithClass(e.target, 'btnRefreshDirectories')) {
|
||||
var path = content.querySelector('#txtDirectoryPickerPath').value;
|
||||
const path = content.querySelector('#txtDirectoryPickerPath').value;
|
||||
refreshDirectoryBrowser(content, path, fileOptions);
|
||||
}
|
||||
});
|
||||
|
||||
content.addEventListener('change', function(e) {
|
||||
var txtDirectoryPickerPath = dom.parentWithTag(e.target, 'INPUT');
|
||||
if (txtDirectoryPickerPath && 'txtDirectoryPickerPath' === txtDirectoryPickerPath.id) {
|
||||
content.addEventListener('change', e => {
|
||||
const txtDirectoryPickerPath = dom.parentWithTag(e.target, 'INPUT');
|
||||
if (txtDirectoryPickerPath && txtDirectoryPickerPath.id === 'txtDirectoryPickerPath') {
|
||||
refreshDirectoryBrowser(content, txtDirectoryPickerPath.value, fileOptions);
|
||||
}
|
||||
});
|
||||
|
||||
content.querySelector('form').addEventListener('submit', function(e) {
|
||||
if (options.callback) {
|
||||
var networkSharePath = this.querySelector('#txtNetworkPath');
|
||||
let networkSharePath = this.querySelector('#txtNetworkPath');
|
||||
networkSharePath = networkSharePath ? networkSharePath.value : null;
|
||||
var path = this.querySelector('#txtDirectoryPickerPath').value;
|
||||
const path = this.querySelector('#txtDirectoryPickerPath').value;
|
||||
validatePath(path, options.validateWriteable, ApiClient).then(options.callback(path, networkSharePath));
|
||||
}
|
||||
e.preventDefault();
|
||||
@@ -224,77 +235,79 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
||||
return Promise.resolve(options.path);
|
||||
} else {
|
||||
return ApiClient.getJSON(ApiClient.getUrl('Environment/DefaultDirectoryBrowser')).then(
|
||||
function(result) {
|
||||
result => {
|
||||
return result.Path || '';
|
||||
}, function() {
|
||||
}, () => {
|
||||
return '';
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function directoryBrowser() {
|
||||
var currentDialog;
|
||||
var self = this;
|
||||
self.show = function(options) {
|
||||
options = options || {};
|
||||
var fileOptions = {
|
||||
includeDirectories: true
|
||||
};
|
||||
if (options.includeDirectories != null) {
|
||||
fileOptions.includeDirectories = options.includeDirectories;
|
||||
}
|
||||
if (options.includeFiles != null) {
|
||||
fileOptions.includeFiles = options.includeFiles;
|
||||
}
|
||||
Promise.all([getSystemInfo(), getDefaultPath(options)]).then(
|
||||
function(responses) {
|
||||
var systemInfo = responses[0];
|
||||
var initialPath = responses[1];
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add('ui-body-a');
|
||||
dlg.classList.add('background-theme-a');
|
||||
dlg.classList.add('directoryPicker');
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseDialog autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
html += options.header || globalize.translate('HeaderSelectPath');
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
html += getEditorHtml(options, systemInfo);
|
||||
dlg.innerHTML = html;
|
||||
initEditor(dlg, options, fileOptions);
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.querySelector('.btnCloseDialog').addEventListener('click', function() {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
currentDialog = dlg;
|
||||
dlg.querySelector('#txtDirectoryPickerPath').value = initialPath;
|
||||
var txtNetworkPath = dlg.querySelector('#txtNetworkPath');
|
||||
if (txtNetworkPath) {
|
||||
txtNetworkPath.value = options.networkSharePath || '';
|
||||
}
|
||||
if (!options.pathReadOnly) {
|
||||
refreshDirectoryBrowser(dlg, initialPath, fileOptions, true);
|
||||
}
|
||||
class directoryBrowser {
|
||||
constructor() {
|
||||
let currentDialog;
|
||||
this.show = options => {
|
||||
options = options || {};
|
||||
const fileOptions = {
|
||||
includeDirectories: true
|
||||
};
|
||||
if (options.includeDirectories != null) {
|
||||
fileOptions.includeDirectories = options.includeDirectories;
|
||||
}
|
||||
);
|
||||
};
|
||||
self.close = function() {
|
||||
if (currentDialog) {
|
||||
dialogHelper.close(currentDialog);
|
||||
}
|
||||
};
|
||||
if (options.includeFiles != null) {
|
||||
fileOptions.includeFiles = options.includeFiles;
|
||||
}
|
||||
Promise.all([getSystemInfo(), getDefaultPath(options)]).then(
|
||||
responses => {
|
||||
const systemInfo = responses[0];
|
||||
const initialPath = responses[1];
|
||||
const dlg = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add('ui-body-a');
|
||||
dlg.classList.add('background-theme-a');
|
||||
dlg.classList.add('directoryPicker');
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
let html = '';
|
||||
html += '<div class="formDialogHeader">';
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseDialog autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>';
|
||||
html += '<h3 class="formDialogHeaderTitle">';
|
||||
html += options.header || globalize.translate('HeaderSelectPath');
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
html += getEditorHtml(options, systemInfo);
|
||||
dlg.innerHTML = html;
|
||||
initEditor(dlg, options, fileOptions);
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.querySelector('.btnCloseDialog').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
currentDialog = dlg;
|
||||
dlg.querySelector('#txtDirectoryPickerPath').value = initialPath;
|
||||
const txtNetworkPath = dlg.querySelector('#txtNetworkPath');
|
||||
if (txtNetworkPath) {
|
||||
txtNetworkPath.value = options.networkSharePath || '';
|
||||
}
|
||||
if (!options.pathReadOnly) {
|
||||
refreshDirectoryBrowser(dlg, initialPath, fileOptions, true);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
this.close = () => {
|
||||
if (currentDialog) {
|
||||
dialogHelper.close(currentDialog);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var systemInfo;
|
||||
return directoryBrowser;
|
||||
});
|
||||
let systemInfo;
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default directoryBrowser;
|
||||
|
||||
@@ -1,22 +1,40 @@
|
||||
define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-button'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
import layoutManager from 'layoutManager';
|
||||
import pluginManager from 'pluginManager';
|
||||
import appHost from 'apphost';
|
||||
import focusManager from 'focusManager';
|
||||
import datetime from 'datetime';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import skinManager from 'skinManager';
|
||||
import events from 'events';
|
||||
import 'emby-select';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-button';
|
||||
|
||||
function fillThemes(select, isDashboard) {
|
||||
select.innerHTML = skinManager.getThemes().map(function (t) {
|
||||
var value = t.id;
|
||||
if (t.isDefault && !isDashboard) {
|
||||
value = '';
|
||||
} else if (t.isDefaultServerDashboard && isDashboard) {
|
||||
value = '';
|
||||
}
|
||||
/* eslint-disable indent */
|
||||
|
||||
return '<option value="' + value + '">' + t.name + '</option>';
|
||||
}).join('');
|
||||
function fillThemes(context, userSettings) {
|
||||
const select = context.querySelector('#selectTheme');
|
||||
|
||||
skinManager.getThemes().then(themes => {
|
||||
select.innerHTML = themes.map(t => {
|
||||
return `<option value="${t.id}">${t.name}</option>`;
|
||||
}).join('');
|
||||
|
||||
// get default theme
|
||||
var defaultTheme = themes.find(theme => {
|
||||
return theme.default;
|
||||
});
|
||||
|
||||
// set the current theme
|
||||
select.value = userSettings.theme() || defaultTheme.id;
|
||||
});
|
||||
}
|
||||
|
||||
function loadScreensavers(context, userSettings) {
|
||||
var selectScreensaver = context.querySelector('.selectScreensaver');
|
||||
var options = pluginManager.ofType('screensaver').map(function (plugin) {
|
||||
const selectScreensaver = context.querySelector('.selectScreensaver');
|
||||
const options = pluginManager.ofType('screensaver').map(plugin => {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
@@ -28,9 +46,10 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
value: 'none'
|
||||
});
|
||||
|
||||
selectScreensaver.innerHTML = options.map(function (o) {
|
||||
return '<option value="' + o.value + '">' + o.name + '</option>';
|
||||
selectScreensaver.innerHTML = options.map(o => {
|
||||
return `<option value="${o.value}">${o.name}</option>`;
|
||||
}).join('');
|
||||
|
||||
selectScreensaver.value = userSettings.screensaver();
|
||||
|
||||
if (!selectScreensaver.value) {
|
||||
@@ -39,61 +58,7 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
}
|
||||
}
|
||||
|
||||
function loadSoundEffects(context, userSettings) {
|
||||
|
||||
var selectSoundEffects = context.querySelector('.selectSoundEffects');
|
||||
var options = pluginManager.ofType('soundeffects').map(function (plugin) {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
options.unshift({
|
||||
name: globalize.translate('None'),
|
||||
value: 'none'
|
||||
});
|
||||
|
||||
selectSoundEffects.innerHTML = options.map(function (o) {
|
||||
return '<option value="' + o.value + '">' + o.name + '</option>';
|
||||
}).join('');
|
||||
selectSoundEffects.value = userSettings.soundEffects();
|
||||
|
||||
if (!selectSoundEffects.value) {
|
||||
// TODO: set the default instead of none
|
||||
selectSoundEffects.value = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function loadSkins(context, userSettings) {
|
||||
|
||||
var selectSkin = context.querySelector('.selectSkin');
|
||||
|
||||
var options = pluginManager.ofType('skin').map(function (plugin) {
|
||||
return {
|
||||
name: plugin.name,
|
||||
value: plugin.id
|
||||
};
|
||||
});
|
||||
|
||||
selectSkin.innerHTML = options.map(function (o) {
|
||||
return '<option value="' + o.value + '">' + o.name + '</option>';
|
||||
}).join('');
|
||||
selectSkin.value = userSettings.skin();
|
||||
|
||||
if (!selectSkin.value && options.length) {
|
||||
selectSkin.value = options[0].value;
|
||||
}
|
||||
|
||||
if (options.length > 1 && appHost.supports('skins')) {
|
||||
context.querySelector('.selectSkinContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectSkinContainer').classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function showOrHideMissingEpisodesField(context, user, apiClient) {
|
||||
|
||||
function showOrHideMissingEpisodesField(context) {
|
||||
if (browser.tizen || browser.web0s) {
|
||||
context.querySelector('.fldDisplayMissingEpisodes').classList.add('hide');
|
||||
return;
|
||||
@@ -102,17 +67,7 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
context.querySelector('.fldDisplayMissingEpisodes').classList.remove('hide');
|
||||
}
|
||||
|
||||
function loadForm(context, user, userSettings, apiClient) {
|
||||
|
||||
var loggedInUserId = apiClient.getCurrentUserId();
|
||||
var userId = user.Id;
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
context.querySelector('.selectDashboardThemeContainer').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.selectDashboardThemeContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
function loadForm(context, user, userSettings) {
|
||||
if (appHost.supports('displaylanguage')) {
|
||||
context.querySelector('.languageSection').classList.remove('hide');
|
||||
} else {
|
||||
@@ -131,18 +86,6 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
context.querySelector('.learnHowToContributeContainer').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('runatstartup')) {
|
||||
context.querySelector('.fldAutorun').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldAutorun').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('soundeffects')) {
|
||||
context.querySelector('.fldSoundEffects').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.fldSoundEffects').classList.add('hide');
|
||||
}
|
||||
|
||||
if (appHost.supports('screensaver')) {
|
||||
context.querySelector('.selectScreensaverContainer').classList.remove('hide');
|
||||
} else {
|
||||
@@ -165,22 +108,15 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
context.querySelector('.fldThemeVideo').classList.add('hide');
|
||||
}
|
||||
|
||||
context.querySelector('.chkRunAtStartup').checked = appSettings.runAtStartup();
|
||||
|
||||
var selectTheme = context.querySelector('#selectTheme');
|
||||
var selectDashboardTheme = context.querySelector('#selectDashboardTheme');
|
||||
|
||||
fillThemes(selectTheme);
|
||||
fillThemes(selectDashboardTheme, true);
|
||||
fillThemes(context, userSettings);
|
||||
loadScreensavers(context, userSettings);
|
||||
loadSoundEffects(context, userSettings);
|
||||
loadSkins(context, userSettings);
|
||||
|
||||
context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false;
|
||||
|
||||
context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs();
|
||||
context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos();
|
||||
context.querySelector('#chkFadein').checked = userSettings.enableFastFadein();
|
||||
context.querySelector('#chkBlurhash').checked = userSettings.enableBlurhash();
|
||||
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
|
||||
context.querySelector('#chkDetailsBanner').checked = userSettings.detailsBanner();
|
||||
|
||||
@@ -189,20 +125,14 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
|
||||
context.querySelector('#txtLibraryPageSize').value = userSettings.libraryPageSize();
|
||||
|
||||
selectDashboardTheme.value = userSettings.dashboardTheme() || '';
|
||||
selectTheme.value = userSettings.theme() || '';
|
||||
|
||||
context.querySelector('.selectLayout').value = layoutManager.getSavedLayout() || '';
|
||||
|
||||
showOrHideMissingEpisodesField(context, user, apiClient);
|
||||
showOrHideMissingEpisodesField(context);
|
||||
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
|
||||
appSettings.runAtStartup(context.querySelector('.chkRunAtStartup').checked);
|
||||
|
||||
user.Configuration.DisplayMissingEpisodes = context.querySelector('.chkDisplayMissingEpisodes').checked;
|
||||
|
||||
if (appHost.supports('displaylanguage')) {
|
||||
@@ -213,16 +143,13 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
|
||||
userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked);
|
||||
userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked);
|
||||
userSettingsInstance.dashboardTheme(context.querySelector('#selectDashboardTheme').value);
|
||||
userSettingsInstance.theme(context.querySelector('#selectTheme').value);
|
||||
userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value);
|
||||
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
|
||||
|
||||
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
|
||||
|
||||
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
|
||||
|
||||
userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked);
|
||||
userSettingsInstance.enableBlurhash(context.querySelector('#chkBlurhash').checked);
|
||||
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
|
||||
userSettingsInstance.detailsBanner(context.querySelector('#chkDetailsBanner').checked);
|
||||
|
||||
@@ -237,29 +164,29 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(function (user) {
|
||||
saveUser(context, user, userSettings, apiClient).then(function () {
|
||||
apiClient.getUser(userId).then(user => {
|
||||
saveUser(context, user, userSettings, apiClient).then(() => {
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
});
|
||||
}
|
||||
events.trigger(instance, 'saved');
|
||||
}, function () {
|
||||
}, () => {
|
||||
loading.hide();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
var self = this;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userId = self.options.userId;
|
||||
var userSettings = self.options.userSettings;
|
||||
const self = this;
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userId = self.options.userId;
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
var enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
const enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
|
||||
@@ -270,50 +197,51 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', '
|
||||
return false;
|
||||
}
|
||||
|
||||
function embed(options, self) {
|
||||
require(['text!./displaySettings.template.html'], function (template) {
|
||||
options.element.innerHTML = globalize.translateDocument(template, 'core');
|
||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||
if (options.enableSaveButton) {
|
||||
options.element.querySelector('.btnSave').classList.remove('hide');
|
||||
}
|
||||
self.loadData(options.autoFocus);
|
||||
});
|
||||
async function embed(options, self) {
|
||||
const { default: template } = await import('text!./displaySettings.template.html');
|
||||
options.element.innerHTML = globalize.translateHtml(template, 'core');
|
||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||
if (options.enableSaveButton) {
|
||||
options.element.querySelector('.btnSave').classList.remove('hide');
|
||||
}
|
||||
self.loadData(options.autoFocus);
|
||||
}
|
||||
|
||||
function DisplaySettings(options) {
|
||||
this.options = options;
|
||||
embed(options, this);
|
||||
}
|
||||
class DisplaySettings {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
embed(options, this);
|
||||
}
|
||||
|
||||
DisplaySettings.prototype.loadData = function (autoFocus) {
|
||||
var self = this;
|
||||
var context = self.options.element;
|
||||
loadData(autoFocus) {
|
||||
const self = this;
|
||||
const context = self.options.element;
|
||||
|
||||
loading.show();
|
||||
loading.show();
|
||||
|
||||
var userId = self.options.userId;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userSettings = self.options.userSettings;
|
||||
const userId = self.options.userId;
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
return apiClient.getUser(userId).then(function (user) {
|
||||
return userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
self.dataLoaded = true;
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
if (autoFocus) {
|
||||
focusManager.autoFocus(context);
|
||||
}
|
||||
return apiClient.getUser(userId).then(user => {
|
||||
return userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
self.dataLoaded = true;
|
||||
loadForm(context, user, userSettings);
|
||||
if (autoFocus) {
|
||||
focusManager.autoFocus(context);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
DisplaySettings.prototype.submit = function () {
|
||||
onSubmit.call(this);
|
||||
};
|
||||
submit() {
|
||||
onSubmit.call(this);
|
||||
}
|
||||
|
||||
DisplaySettings.prototype.destroy = function () {
|
||||
this.options = null;
|
||||
};
|
||||
destroy() {
|
||||
this.options = null;
|
||||
}
|
||||
}
|
||||
|
||||
return DisplaySettings;
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
export default DisplaySettings;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<form style="margin: 0 auto;">
|
||||
|
||||
<h2 class="sectionTitle">
|
||||
${Display}
|
||||
</h2>
|
||||
@@ -123,40 +122,36 @@
|
||||
<div class="fieldDescription">${LabelPleaseRestart}</div>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer hide selectSkinContainer">
|
||||
<select is="emby-select" class="selectSkin" label="${LabelSkin}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer">
|
||||
<select id="selectTheme" is="emby-select" label="${LabelTheme}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer selectDashboardThemeContainer hide">
|
||||
<select id="selectDashboardTheme" is="emby-select" label="${LabelDashboardTheme}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer hide selectScreensaverContainer">
|
||||
<select is="emby-select" class="selectScreensaver" label="${LabelScreensaver}"></select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer fldSoundEffects hide">
|
||||
<select is="emby-select" class="selectSoundEffects" label="${LabelSoundEffects}"></select>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer inputContainer-withDescription fldFadein">
|
||||
<div class="inputContainer inputContainer-withDescription">
|
||||
<input is="emby-input" type="number" id="txtLibraryPageSize" pattern="[0-9]*" required="required" min="0" max="1000" step="1" label="${LabelLibraryPageSize}" />
|
||||
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldFadein">
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkFadein" />
|
||||
<span>${EnableFastImageFadeIn}</span>
|
||||
<span>${EnableFasterAnimations}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableFastImageFadeInHelp}</div>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableFasterAnimationsHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldDetailsBanner">
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkBlurhash" />
|
||||
<span>${EnableBlurHash}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBlurHashHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkDetailsBanner" />
|
||||
<span>${EnableDetailsBanner}</span>
|
||||
@@ -167,7 +162,7 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkBackdrops" />
|
||||
<span>${EnableBackdrops}</span>
|
||||
<span>${Backdrops}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableBackdropsHelp}</div>
|
||||
</div>
|
||||
@@ -175,7 +170,7 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldThemeSong hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkThemeSong" />
|
||||
<span>${EnableThemeSongs}</span>
|
||||
<span>${ThemeSongs}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableThemeSongsHelp}</div>
|
||||
</div>
|
||||
@@ -183,18 +178,11 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldThemeVideo hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkThemeVideo" />
|
||||
<span>${EnableThemeVideos}</span>
|
||||
<span>${ThemeVideos}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableThemeVideosHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer hide fldAutorun">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkRunAtStartup" />
|
||||
<span>${RunAtStartup}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldDisplayMissingEpisodes hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkDisplayMissingEpisodes" />
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoader', 'globalize', 'layoutManager', 'scrollStyles', 'emby-itemscontainer'], function (loading, libraryBrowser, cardBuilder, dom, appHost, imageLoader, globalize, layoutManager) {
|
||||
'use strict';
|
||||
import loading from 'loading';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import dom from 'dom';
|
||||
import appHost from 'apphost';
|
||||
import imageLoader from 'imageLoader';
|
||||
import globalize from 'globalize';
|
||||
import layoutManager from 'layoutManager';
|
||||
import 'scrollStyles';
|
||||
import 'emby-itemscontainer';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function enableScrollX() {
|
||||
return !layoutManager.desktop;
|
||||
@@ -19,21 +28,21 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
|
||||
function getSections() {
|
||||
return [{
|
||||
name: 'HeaderFavoriteMovies',
|
||||
name: 'Movies',
|
||||
types: 'Movie',
|
||||
id: 'favoriteMovies',
|
||||
shape: getPosterShape(),
|
||||
showTitle: false,
|
||||
overlayPlayButton: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteShows',
|
||||
name: 'Shows',
|
||||
types: 'Series',
|
||||
id: 'favoriteShows',
|
||||
shape: getPosterShape(),
|
||||
showTitle: false,
|
||||
overlayPlayButton: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteEpisodes',
|
||||
name: 'Episodes',
|
||||
types: 'Episode',
|
||||
id: 'favoriteEpisode',
|
||||
shape: getThumbShape(),
|
||||
@@ -44,7 +53,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
overlayText: false,
|
||||
centerText: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteVideos',
|
||||
name: 'Videos',
|
||||
types: 'Video,MusicVideo',
|
||||
id: 'favoriteVideos',
|
||||
shape: getThumbShape(),
|
||||
@@ -54,7 +63,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
overlayText: false,
|
||||
centerText: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteArtists',
|
||||
name: 'Artists',
|
||||
types: 'MusicArtist',
|
||||
id: 'favoriteArtists',
|
||||
shape: getSquareShape(),
|
||||
@@ -66,7 +75,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
overlayPlayButton: true,
|
||||
coverImage: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteAlbums',
|
||||
name: 'Albums',
|
||||
types: 'MusicAlbum',
|
||||
id: 'favoriteAlbums',
|
||||
shape: getSquareShape(),
|
||||
@@ -78,7 +87,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
overlayPlayButton: true,
|
||||
coverImage: true
|
||||
}, {
|
||||
name: 'HeaderFavoriteSongs',
|
||||
name: 'Songs',
|
||||
types: 'Audio',
|
||||
id: 'favoriteSongs',
|
||||
shape: getSquareShape(),
|
||||
@@ -94,8 +103,8 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
}
|
||||
|
||||
function loadSection(elem, userId, topParentId, section, isSingleSection) {
|
||||
var screenWidth = dom.getWindowSize().innerWidth;
|
||||
var options = {
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
const options = {
|
||||
SortBy: 'SortName',
|
||||
SortOrder: 'Ascending',
|
||||
Filters: 'IsFavorite',
|
||||
@@ -118,9 +127,9 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
}
|
||||
}
|
||||
|
||||
var promise;
|
||||
let promise;
|
||||
|
||||
if ('MusicArtist' === section.types) {
|
||||
if (section.types === 'MusicArtist') {
|
||||
promise = ApiClient.getArtists(userId, options);
|
||||
} else {
|
||||
options.IncludeItemTypes = section.types;
|
||||
@@ -128,7 +137,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
}
|
||||
|
||||
return promise.then(function (result) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
if (result.Items.length) {
|
||||
if (html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">', !layoutManager.tv && options.Limit && result.Items.length >= options.Limit) {
|
||||
@@ -144,7 +153,7 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
|
||||
html += '</div>';
|
||||
if (enableScrollX()) {
|
||||
var scrollXClass = 'scrollX hiddenScrollX';
|
||||
let scrollXClass = 'scrollX hiddenScrollX';
|
||||
if (layoutManager.tv) {
|
||||
scrollXClass += ' smoothScrollX';
|
||||
}
|
||||
@@ -154,14 +163,13 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
html += '<div is="emby-itemscontainer" class="itemsContainer vertical-wrap padded-left padded-right">';
|
||||
}
|
||||
|
||||
var supportsImageAnalysis = appHost.supports('imageanalysis');
|
||||
var cardLayout = (appHost.preferVisualCards || supportsImageAnalysis) && section.autoCardLayout && section.showTitle;
|
||||
let cardLayout = appHost.preferVisualCards && section.autoCardLayout && section.showTitle;
|
||||
cardLayout = false;
|
||||
html += cardBuilder.getCardsHtml(result.Items, {
|
||||
preferThumb: section.preferThumb,
|
||||
shape: section.shape,
|
||||
centerText: section.centerText && !cardLayout,
|
||||
overlayText: false !== section.overlayText,
|
||||
overlayText: section.overlayText !== false,
|
||||
showTitle: section.showTitle,
|
||||
showParentTitle: section.showParentTitle,
|
||||
scalable: true,
|
||||
@@ -180,10 +188,10 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
});
|
||||
}
|
||||
|
||||
function loadSections(page, userId, topParentId, types) {
|
||||
export function loadSections(page, userId, topParentId, types) {
|
||||
loading.show();
|
||||
var sections = getSections();
|
||||
var sectionid = getParameterByName('sectionid');
|
||||
let sections = getSections();
|
||||
const sectionid = getParameterByName('sectionid');
|
||||
|
||||
if (sectionid) {
|
||||
sections = sections.filter(function (s) {
|
||||
@@ -193,30 +201,28 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
|
||||
if (types) {
|
||||
sections = sections.filter(function (s) {
|
||||
return -1 !== types.indexOf(s.id);
|
||||
return types.indexOf(s.id) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
var elem = page.querySelector('.favoriteSections');
|
||||
let elem = page.querySelector('.favoriteSections');
|
||||
|
||||
if (!elem.innerHTML) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
for (i = 0, length = sections.length; i < length; i++) {
|
||||
for (let i = 0, length = sections.length; i < length; i++) {
|
||||
html += '<div class="verticalSection section' + sections[i].id + '"></div>';
|
||||
}
|
||||
|
||||
elem.innerHTML = html;
|
||||
}
|
||||
|
||||
var promises = [];
|
||||
const promises = [];
|
||||
|
||||
for (i = 0, length = sections.length; i < length; i++) {
|
||||
var section = sections[i];
|
||||
for (let i = 0, length = sections.length; i < length; i++) {
|
||||
const section = sections[i];
|
||||
elem = page.querySelector('.section' + section.id);
|
||||
promises.push(loadSection(elem, userId, topParentId, section, 1 === sections.length));
|
||||
promises.push(loadSection(elem, userId, topParentId, section, sections.length === 1));
|
||||
}
|
||||
|
||||
Promise.all(promises).then(function () {
|
||||
@@ -224,7 +230,8 @@ define(['loading', 'libraryBrowser', 'cardBuilder', 'dom', 'apphost', 'imageLoad
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
render: loadSections
|
||||
};
|
||||
});
|
||||
export default {
|
||||
render: loadSections
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
define([], function () {
|
||||
'use strict';
|
||||
|
||||
function getFetchPromise(request) {
|
||||
|
||||
var headers = request.headers || {};
|
||||
/* eslint-disable indent */
|
||||
export function getFetchPromise(request) {
|
||||
const headers = request.headers || {};
|
||||
|
||||
if (request.dataType === 'json') {
|
||||
headers.accept = 'application/json';
|
||||
}
|
||||
|
||||
var fetchRequest = {
|
||||
const fetchRequest = {
|
||||
headers: headers,
|
||||
method: request.type,
|
||||
credentials: 'same-origin'
|
||||
};
|
||||
|
||||
var contentType = request.contentType;
|
||||
let contentType = request.contentType;
|
||||
|
||||
if (request.data) {
|
||||
|
||||
if (typeof request.data === 'string') {
|
||||
fetchRequest.body = request.data;
|
||||
} else {
|
||||
@@ -29,16 +25,15 @@ define([], function () {
|
||||
}
|
||||
|
||||
if (contentType) {
|
||||
|
||||
headers['Content-Type'] = contentType;
|
||||
}
|
||||
|
||||
var url = request.url;
|
||||
let url = request.url;
|
||||
|
||||
if (request.query) {
|
||||
var paramString = paramsToString(request.query);
|
||||
const paramString = paramsToString(request.query);
|
||||
if (paramString) {
|
||||
url += '?' + paramString;
|
||||
url += `?${paramString}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,12 +45,10 @@ define([], function () {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
var timeout = setTimeout(reject, timeoutMs);
|
||||
const timeout = setTimeout(reject, timeoutMs);
|
||||
|
||||
options = options || {};
|
||||
options.credentials = 'same-origin';
|
||||
@@ -63,50 +56,46 @@ define([], function () {
|
||||
fetch(url, options).then(function (response) {
|
||||
clearTimeout(timeout);
|
||||
|
||||
console.debug('fetchWithTimeout: succeeded connecting to url: ' + url);
|
||||
console.debug(`fetchWithTimeout: succeeded connecting to url: ${url}`);
|
||||
|
||||
resolve(response);
|
||||
}, function (error) {
|
||||
|
||||
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) {
|
||||
|
||||
var values = [];
|
||||
|
||||
for (var key in params) {
|
||||
|
||||
var value = params[key];
|
||||
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
values.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
|
||||
}
|
||||
}
|
||||
return values.join('&');
|
||||
return Object.entries(params)
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
.filter(([_, v]) => v !== null && v !== undefined && v !== '')
|
||||
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
|
||||
.join('&');
|
||||
}
|
||||
|
||||
function ajax(request) {
|
||||
export function ajax(request) {
|
||||
if (!request) {
|
||||
throw new Error('Request cannot be null');
|
||||
}
|
||||
|
||||
request.headers = request.headers || {};
|
||||
|
||||
console.debug('requesting url: ' + request.url);
|
||||
console.debug(`requesting url: ${request.url}`);
|
||||
|
||||
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 (request.dataType === 'json' || request.headers.accept === 'application/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();
|
||||
} else {
|
||||
return response;
|
||||
@@ -115,12 +104,8 @@ define([], function () {
|
||||
return Promise.reject(response);
|
||||
}
|
||||
}, function (err) {
|
||||
console.error('request failed to url: ' + request.url);
|
||||
console.error(`request failed to url: ${request.url}`);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
return {
|
||||
getFetchPromise: getFetchPromise,
|
||||
ajax: ajax
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'browser', 'require', 'emby-checkbox', 'emby-collapse', 'css!./style'], function (dom, dialogHelper, globalize, connectionManager, events, browser, require) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import events from 'events';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-collapse';
|
||||
import 'css!./style.css';
|
||||
|
||||
/* eslint-disable indent */
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
var elem = context.querySelector(selector);
|
||||
const elem = context.querySelector(selector);
|
||||
if (items.length) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
var html = '';
|
||||
let html = '';
|
||||
html += '<div class="checkboxList">';
|
||||
html += items.map(function (filter) {
|
||||
var itemHtml = '';
|
||||
var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
|
||||
let itemHtml = '';
|
||||
const checkedHtml = isCheckedFn(filter) ? 'checked' : '';
|
||||
itemHtml += '<label>';
|
||||
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter + '" class="' + cssClass + '"/>';
|
||||
itemHtml += '<span>' + filter + '</span>';
|
||||
itemHtml += `<input is="emby-checkbox" type="checkbox" ${checkedHtml} data-filter="${filter}" class="${cssClass}"/>`;
|
||||
itemHtml += `<span>${filter}</span>`;
|
||||
itemHtml += '</label>';
|
||||
return itemHtml;
|
||||
}).join('');
|
||||
@@ -24,21 +30,24 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
|
||||
}
|
||||
|
||||
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) {
|
||||
var delimeter = '|';
|
||||
return (delimeter + (query.Genres || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
const delimeter = '|';
|
||||
return (delimeter + (query.Genres || '') + delimeter).includes(delimeter + i + delimeter);
|
||||
});
|
||||
renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
|
||||
var delimeter = '|';
|
||||
return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
const delimeter = '|';
|
||||
return (delimeter + (query.OfficialRatings || '') + delimeter).includes(delimeter + i + delimeter);
|
||||
});
|
||||
renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
|
||||
var delimeter = '|';
|
||||
return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
const delimeter = '|';
|
||||
return (delimeter + (query.Tags || '') + delimeter).includes(delimeter + i + delimeter);
|
||||
});
|
||||
renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
|
||||
var delimeter = ',';
|
||||
return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
const delimeter = ',';
|
||||
return (delimeter + (query.Years || '') + delimeter).includes(delimeter + i + delimeter);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,59 +61,58 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context {HTMLDivElement} Dialog
|
||||
* @param options {any} Options
|
||||
*/
|
||||
function updateFilterControls(context, options) {
|
||||
var elems;
|
||||
var i;
|
||||
var length;
|
||||
var query = options.query;
|
||||
const query = options.query;
|
||||
|
||||
if (options.mode == 'livetvchannels') {
|
||||
context.querySelector('.chkFavorite').checked = query.IsFavorite == true;
|
||||
context.querySelector('.chkLikes').checked = query.IsLiked == true;
|
||||
context.querySelector('.chkDislikes').checked = query.IsDisliked == true;
|
||||
if (options.mode === 'livetvchannels') {
|
||||
context.querySelector('.chkFavorite').checked = query.IsFavorite === true;
|
||||
context.querySelector('.chkLikes').checked = query.IsLiked === true;
|
||||
context.querySelector('.chkDislikes').checked = query.IsDisliked === true;
|
||||
} else {
|
||||
elems = context.querySelectorAll('.chkStandardFilter');
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
var chkStandardFilter = elems[i];
|
||||
var filters = ',' + (query.Filters || '');
|
||||
var filterName = chkStandardFilter.getAttribute('data-filter');
|
||||
chkStandardFilter.checked = filters.indexOf(',' + filterName) != -1;
|
||||
for (const elem of context.querySelectorAll('.chkStandardFilter')) {
|
||||
const filters = `,${query.Filters || ''}`;
|
||||
const filterName = elem.getAttribute('data-filter');
|
||||
elem.checked = filters.includes(`,${filterName}`);
|
||||
}
|
||||
}
|
||||
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
var chkVideoTypeFilter = elems[i];
|
||||
var filters = ',' + (query.VideoTypes || '');
|
||||
var filterName = chkVideoTypeFilter.getAttribute('data-filter');
|
||||
chkVideoTypeFilter.checked = filters.indexOf(',' + filterName) != -1;
|
||||
for (const elem of context.querySelectorAll('.chkVideoTypeFilter')) {
|
||||
const filters = `,${query.VideoTypes || ''}`;
|
||||
const filterName = elem.getAttribute('data-filter');
|
||||
elem.checked = filters.includes(`,${filterName}`);
|
||||
}
|
||||
context.querySelector('.chk3DFilter').checked = query.Is3D == true;
|
||||
context.querySelector('.chkHDFilter').checked = query.IsHD == true;
|
||||
context.querySelector('.chk4KFilter').checked = query.Is4K == true;
|
||||
context.querySelector('.chkSDFilter').checked = query.IsHD == true;
|
||||
context.querySelector('#chkSubtitle').checked = query.HasSubtitles == true;
|
||||
context.querySelector('#chkTrailer').checked = query.HasTrailer == true;
|
||||
context.querySelector('#chkThemeSong').checked = query.HasThemeSong == true;
|
||||
context.querySelector('#chkThemeVideo').checked = query.HasThemeVideo == true;
|
||||
context.querySelector('#chkSpecialFeature').checked = query.HasSpecialFeature == true;
|
||||
context.querySelector('#chkSpecialEpisode').checked = query.ParentIndexNumber == 0;
|
||||
context.querySelector('#chkMissingEpisode').checked = query.IsMissing == true;
|
||||
context.querySelector('#chkFutureEpisode').checked = query.IsUnaired == true;
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
var chkStatus = elems[i];
|
||||
var filters = ',' + (query.SeriesStatus || '');
|
||||
var filterName = chkStatus.getAttribute('data-filter');
|
||||
chkStatus.checked = filters.indexOf(',' + filterName) != -1;
|
||||
context.querySelector('.chk3DFilter').checked = query.Is3D === true;
|
||||
context.querySelector('.chkHDFilter').checked = query.IsHD === true;
|
||||
context.querySelector('.chk4KFilter').checked = query.Is4K === true;
|
||||
context.querySelector('.chkSDFilter').checked = query.IsHD === true;
|
||||
context.querySelector('#chkSubtitle').checked = query.HasSubtitles === true;
|
||||
context.querySelector('#chkTrailer').checked = query.HasTrailer === true;
|
||||
context.querySelector('#chkThemeSong').checked = query.HasThemeSong === true;
|
||||
context.querySelector('#chkThemeVideo').checked = query.HasThemeVideo === true;
|
||||
context.querySelector('#chkSpecialFeature').checked = query.HasSpecialFeature === true;
|
||||
context.querySelector('#chkSpecialEpisode').checked = query.ParentIndexNumber === 0;
|
||||
context.querySelector('#chkMissingEpisode').checked = query.IsMissing === true;
|
||||
context.querySelector('#chkFutureEpisode').checked = query.IsUnaired === true;
|
||||
for (const elem of context.querySelectorAll('.chkStatus')) {
|
||||
const filters = `,${query.SeriesStatus || ''}`;
|
||||
const filterName = elem.getAttribute('data-filter');
|
||||
elem.checked = filters.includes(`,${filterName}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param instance {FilterDialog} An instance of FilterDialog
|
||||
*/
|
||||
function triggerChange(instance) {
|
||||
events.trigger(instance, 'filterchange');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
@@ -115,263 +123,287 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
|
||||
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');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if (options.mode == 'series') {
|
||||
if (options.mode === 'series') {
|
||||
context.querySelector('.seriesStatus').classList.remove('hide');
|
||||
}
|
||||
|
||||
if (options.mode == 'episodes') {
|
||||
if (options.mode === 'episodes') {
|
||||
showByClass(context, 'episodeFilter');
|
||||
}
|
||||
}
|
||||
|
||||
function showByClass(context, className) {
|
||||
var elems = context.querySelectorAll('.' + className);
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].classList.remove('hide');
|
||||
for (const elem of context.querySelectorAll(`.${className}`)) {
|
||||
elem.classList.remove('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function hideByClass(context, className) {
|
||||
var elems = context.querySelectorAll('.' + className);
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].classList.add('hide');
|
||||
for (const elem of context.querySelectorAll(`.${className}`)) {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
function onFavoriteChange() {
|
||||
var query = options.query;
|
||||
query.StartIndex = 0;
|
||||
query.IsFavorite = !!this.checked || null;
|
||||
triggerChange(self);
|
||||
class FilterDialog {
|
||||
constructor(options) {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
function onStandardFilterChange() {
|
||||
var query = options.query;
|
||||
var filterName = this.getAttribute('data-filter');
|
||||
var filters = query.Filters || '';
|
||||
filters = (',' + filters).replace(',' + filterName, '').substring(1);
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onFavoriteChange(elem) {
|
||||
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.Filters = filters;
|
||||
triggerChange(self);
|
||||
triggerChange(this);
|
||||
}
|
||||
|
||||
function onVideoTypeFilterChange() {
|
||||
var query = options.query;
|
||||
var filterName = this.getAttribute('data-filter');
|
||||
var filters = query.VideoTypes || '';
|
||||
filters = (',' + filters).replace(',' + filterName, '').substring(1);
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onVideoTypeFilterChange(elem) {
|
||||
const query = this.options.query;
|
||||
const filterName = elem.getAttribute('data-filter');
|
||||
let filters = query.VideoTypes || '';
|
||||
filters = (`,${filters}`).replace(`,${filterName}`, '').substring(1);
|
||||
|
||||
if (this.checked) {
|
||||
filters = filters ? filters + ',' + filterName : filterName;
|
||||
if (elem.checked) {
|
||||
filters = filters ? `${filters},${filterName}` : filterName;
|
||||
}
|
||||
|
||||
query.StartIndex = 0;
|
||||
query.VideoTypes = filters;
|
||||
triggerChange(self);
|
||||
triggerChange(this);
|
||||
}
|
||||
|
||||
function onStatusChange() {
|
||||
var query = options.query;
|
||||
var filterName = this.getAttribute('data-filter');
|
||||
var filters = query.SeriesStatus || '';
|
||||
filters = (',' + filters).replace(',' + filterName, '').substring(1);
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onStatusChange(elem) {
|
||||
const query = this.options.query;
|
||||
const filterName = elem.getAttribute('data-filter');
|
||||
let filters = query.SeriesStatus || '';
|
||||
filters = (`,${filters}`).replace(`,${filterName}`, '').substring(1);
|
||||
|
||||
if (this.checked) {
|
||||
filters = filters ? filters + ',' + filterName : filterName;
|
||||
if (elem.checked) {
|
||||
filters = filters ? `${filters},${filterName}` : filterName;
|
||||
}
|
||||
|
||||
query.SeriesStatus = filters;
|
||||
query.StartIndex = 0;
|
||||
triggerChange(self);
|
||||
triggerChange(this);
|
||||
}
|
||||
|
||||
function bindEvents(context) {
|
||||
var elems;
|
||||
var i;
|
||||
var length;
|
||||
var query = options.query;
|
||||
/**
|
||||
* @param context {HTMLDivElement} The dialog
|
||||
*/
|
||||
bindEvents(context) {
|
||||
const query = this.options.query;
|
||||
|
||||
if (options.mode == 'livetvchannels') {
|
||||
elems = context.querySelectorAll('.chkFavorite');
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('change', onFavoriteChange);
|
||||
if (this.options.mode === 'livetvchannels') {
|
||||
for (const elem of context.querySelectorAll('.chkFavorite')) {
|
||||
elem.addEventListener('change', () => this.onFavoriteChange(elem));
|
||||
}
|
||||
context.querySelector('.chkLikes').addEventListener('change', function () {
|
||||
|
||||
const chkLikes = context.querySelector('.chkLikes');
|
||||
chkLikes.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.IsLiked = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.IsLiked = chkLikes.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('.chkDislikes').addEventListener('change', function () {
|
||||
const chkDislikes = context.querySelector('.chkDislikes');
|
||||
chkDislikes.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.IsDisliked = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.IsDisliked = chkDislikes.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
} else {
|
||||
elems = context.querySelectorAll('.chkStandardFilter');
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('change', onStandardFilterChange);
|
||||
for (const elem of context.querySelectorAll('.chkStandardFilter')) {
|
||||
elem.addEventListener('change', () => this.onStandardFilterChange(elem));
|
||||
}
|
||||
}
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('change', onVideoTypeFilterChange);
|
||||
|
||||
for (const elem of context.querySelectorAll('.chkVideoTypeFilter')) {
|
||||
elem.addEventListener('change', () => this.onVideoTypeFilterChange(elem));
|
||||
}
|
||||
context.querySelector('.chk3DFilter').addEventListener('change', function () {
|
||||
const chk3DFilter = context.querySelector('.chk3DFilter');
|
||||
chk3DFilter.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.Is3D = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.Is3D = chk3DFilter.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('.chk4KFilter').addEventListener('change', function () {
|
||||
const chk4KFilter = context.querySelector('.chk4KFilter');
|
||||
chk4KFilter.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.Is4K = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.Is4K = chk4KFilter.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('.chkHDFilter').addEventListener('change', function () {
|
||||
const chkHDFilter = context.querySelector('.chkHDFilter');
|
||||
chkHDFilter.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.IsHD = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.IsHD = chkHDFilter.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('.chkSDFilter').addEventListener('change', function () {
|
||||
const chkSDFilter = context.querySelector('.chkSDFilter');
|
||||
chkSDFilter.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.IsHD = this.checked ? false : null;
|
||||
triggerChange(self);
|
||||
query.IsHD = chkSDFilter.checked ? false : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
elems = context.querySelectorAll('.chkStatus');
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('change', onStatusChange);
|
||||
for (const elem of context.querySelectorAll('.chkStatus')) {
|
||||
elem.addEventListener('change', () => this.onStatusChange(elem));
|
||||
}
|
||||
context.querySelector('#chkTrailer').addEventListener('change', function () {
|
||||
const chkTrailer = context.querySelector('#chkTrailer');
|
||||
chkTrailer.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.HasTrailer = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.HasTrailer = chkTrailer.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('#chkThemeSong').addEventListener('change', function () {
|
||||
const chkThemeSong = context.querySelector('#chkThemeSong');
|
||||
chkThemeSong.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.HasThemeSong = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.HasThemeSong = chkThemeSong.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('#chkSpecialFeature').addEventListener('change', function () {
|
||||
const chkSpecialFeature = context.querySelector('#chkSpecialFeature');
|
||||
chkSpecialFeature.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.HasSpecialFeature = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.HasSpecialFeature = chkSpecialFeature.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('#chkThemeVideo').addEventListener('change', function () {
|
||||
const chkThemeVideo = context.querySelector('#chkThemeVideo');
|
||||
chkThemeVideo.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.HasThemeVideo = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.HasThemeVideo = chkThemeVideo.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('#chkMissingEpisode').addEventListener('change', function () {
|
||||
const chkMissingEpisode = context.querySelector('#chkMissingEpisode');
|
||||
chkMissingEpisode.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.IsMissing = this.checked ? true : false;
|
||||
triggerChange(self);
|
||||
query.IsMissing = !!chkMissingEpisode.checked;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('#chkSpecialEpisode').addEventListener('change', function () {
|
||||
const chkSpecialEpisode = context.querySelector('#chkSpecialEpisode');
|
||||
chkSpecialEpisode.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
query.ParentIndexNumber = this.checked ? 0 : null;
|
||||
triggerChange(self);
|
||||
query.ParentIndexNumber = chkSpecialEpisode.checked ? 0 : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.querySelector('#chkFutureEpisode').addEventListener('change', function () {
|
||||
const chkFutureEpisode = context.querySelector('#chkFutureEpisode');
|
||||
chkFutureEpisode.addEventListener('change', () => {
|
||||
query.StartIndex = 0;
|
||||
if (this.checked) {
|
||||
if (chkFutureEpisode.checked) {
|
||||
query.IsUnaired = true;
|
||||
query.IsVirtualUnaired = null;
|
||||
} else {
|
||||
query.IsUnaired = null;
|
||||
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.HasSubtitles = this.checked ? true : null;
|
||||
triggerChange(self);
|
||||
query.HasSubtitles = chkSubtitle.checked ? true : null;
|
||||
triggerChange(this);
|
||||
});
|
||||
context.addEventListener('change', function (e) {
|
||||
var chkGenreFilter = dom.parentWithClass(e.target, 'chkGenreFilter');
|
||||
context.addEventListener('change', (e) => {
|
||||
const chkGenreFilter = dom.parentWithClass(e.target, 'chkGenreFilter');
|
||||
if (chkGenreFilter) {
|
||||
var filterName = chkGenreFilter.getAttribute('data-filter');
|
||||
var filters = query.Genres || '';
|
||||
var delimiter = '|';
|
||||
const filterName = chkGenreFilter.getAttribute('data-filter');
|
||||
let filters = query.Genres || '';
|
||||
const delimiter = '|';
|
||||
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
|
||||
if (chkGenreFilter.checked) {
|
||||
filters = filters ? (filters + delimiter + filterName) : filterName;
|
||||
}
|
||||
query.StartIndex = 0;
|
||||
query.Genres = filters;
|
||||
triggerChange(self);
|
||||
triggerChange(this);
|
||||
return;
|
||||
}
|
||||
var chkTagFilter = dom.parentWithClass(e.target, 'chkTagFilter');
|
||||
const chkTagFilter = dom.parentWithClass(e.target, 'chkTagFilter');
|
||||
if (chkTagFilter) {
|
||||
var filterName = chkTagFilter.getAttribute('data-filter');
|
||||
var filters = query.Tags || '';
|
||||
var delimiter = '|';
|
||||
const filterName = chkTagFilter.getAttribute('data-filter');
|
||||
let filters = query.Tags || '';
|
||||
const delimiter = '|';
|
||||
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
|
||||
if (chkTagFilter.checked) {
|
||||
filters = filters ? (filters + delimiter + filterName) : filterName;
|
||||
}
|
||||
query.StartIndex = 0;
|
||||
query.Tags = filters;
|
||||
triggerChange(self);
|
||||
triggerChange(this);
|
||||
return;
|
||||
}
|
||||
var chkYearFilter = dom.parentWithClass(e.target, 'chkYearFilter');
|
||||
const chkYearFilter = dom.parentWithClass(e.target, 'chkYearFilter');
|
||||
if (chkYearFilter) {
|
||||
var filterName = chkYearFilter.getAttribute('data-filter');
|
||||
var filters = query.Years || '';
|
||||
var delimiter = ',';
|
||||
const filterName = chkYearFilter.getAttribute('data-filter');
|
||||
let filters = query.Years || '';
|
||||
const delimiter = ',';
|
||||
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
|
||||
if (chkYearFilter.checked) {
|
||||
filters = filters ? (filters + delimiter + filterName) : filterName;
|
||||
}
|
||||
query.StartIndex = 0;
|
||||
query.Years = filters;
|
||||
triggerChange(self);
|
||||
triggerChange(this);
|
||||
return;
|
||||
}
|
||||
var chkOfficialRatingFilter = dom.parentWithClass(e.target, 'chkOfficialRatingFilter');
|
||||
const chkOfficialRatingFilter = dom.parentWithClass(e.target, 'chkOfficialRatingFilter');
|
||||
if (chkOfficialRatingFilter) {
|
||||
var filterName = chkOfficialRatingFilter.getAttribute('data-filter');
|
||||
var filters = query.OfficialRatings || '';
|
||||
var delimiter = '|';
|
||||
const filterName = chkOfficialRatingFilter.getAttribute('data-filter');
|
||||
let filters = query.OfficialRatings || '';
|
||||
const delimiter = '|';
|
||||
filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1);
|
||||
if (chkOfficialRatingFilter.checked) {
|
||||
filters = filters ? (filters + delimiter + filterName) : filterName;
|
||||
}
|
||||
query.StartIndex = 0;
|
||||
query.OfficialRatings = filters;
|
||||
triggerChange(self);
|
||||
return;
|
||||
triggerChange(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
self.show = function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['text!./filterdialog.template.html'], function (template) {
|
||||
var dlg = dialogHelper.createDialog({
|
||||
show() {
|
||||
return import('text!./filterdialog.template.html').then(({default: template}) => {
|
||||
return new Promise((resolve) => {
|
||||
const dlg = dialogHelper.createDialog({
|
||||
removeOnClose: true,
|
||||
modal: false
|
||||
});
|
||||
@@ -379,19 +411,22 @@ define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'brow
|
||||
dlg.classList.add('background-theme-a');
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('filterDialog');
|
||||
dlg.innerHTML = globalize.translateDocument(template);
|
||||
setVisibility(dlg, options);
|
||||
dlg.innerHTML = globalize.translateHtml(template);
|
||||
setVisibility(dlg, this.options);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.addEventListener('close', resolve);
|
||||
updateFilterControls(dlg, options);
|
||||
bindEvents(dlg);
|
||||
if (enableDynamicFilters(options.mode)) {
|
||||
updateFilterControls(dlg, this.options);
|
||||
this.bindEvents(dlg);
|
||||
if (enableDynamicFilters(this.options.mode)) {
|
||||
dlg.classList.add('dynamicFilterDialog');
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), options.query);
|
||||
const apiClient = window.connectionManager.getApiClient(this.options.serverId);
|
||||
loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), this.options.query);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default FilterDialog;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<div style="margin: 0;padding:1.5em 2em;" class="filterDialogContent">
|
||||
|
||||
<div is="emby-collapse" title="${HeaderFilters}">
|
||||
<div is="emby-collapse" title="${Filters}">
|
||||
<div class="collapseContent">
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
data-filter="IsPlayed" />
|
||||
<span>${OptionPlayed}</span>
|
||||
<span>${Played}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
data-filter="IsUnPlayed" />
|
||||
<span>${OptionUnplayed}</span>
|
||||
<span>${Unplayed}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter videoStandard"
|
||||
@@ -21,7 +21,7 @@
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter chkFavorite"
|
||||
data-filter="IsFavorite" />
|
||||
<span>${OptionFavorite}</span>
|
||||
<span>${Favorites}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStandardFilter chkLikes" data-filter="Likes" />
|
||||
@@ -53,30 +53,30 @@
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStatus" data-filter="Continuing" />
|
||||
<span>${OptionContinuing}</span>
|
||||
<span>${Continuing}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkStatus" data-filter="Ended" />
|
||||
<span>${OptionEnded}</span>
|
||||
<span>${Ended}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderFeatures}" class="features hide">
|
||||
<div is="emby-collapse" title="${Features}" class="features hide">
|
||||
<div class="collapseContent">
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkSubtitle" />
|
||||
<span>${OptionHasSubtitles}</span>
|
||||
<span>${Subtitles}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkTrailer" />
|
||||
<span>${OptionHasTrailer}</span>
|
||||
<span>${ButtonTrailer}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkSpecialFeature" />
|
||||
<span>${OptionHasSpecialFeatures}</span>
|
||||
<span>${SpecialFeatures}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkFeatureFilter" id="chkThemeSong" />
|
||||
@@ -90,7 +90,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderGenres}" class="genreFilters hide">
|
||||
<div is="emby-collapse" title="${Genres}" class="genreFilters hide">
|
||||
<div class="collapseContent filterOptions">
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,7 +100,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div is="emby-collapse" title="${HeaderTags}" class="tagFilters hide">
|
||||
<div is="emby-collapse" title="${Tags}" class="tagFilters hide">
|
||||
<div class="collapseContent filterOptions">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,271 +1,219 @@
|
||||
define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', 'inputManager', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import focusManager from 'focusManager';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import inputManager from 'inputManager';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import * as userSettings from 'userSettings';
|
||||
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';
|
||||
|
||||
function onSubmit(e) {
|
||||
function onSubmit(e) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
var elem = context.querySelector(selector);
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
if (items.length) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
var html = '';
|
||||
|
||||
var elem = context.querySelector(selector);
|
||||
html += items.map(function (filter) {
|
||||
var itemHtml = '';
|
||||
|
||||
if (items.length) {
|
||||
var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
|
||||
itemHtml += '<label>';
|
||||
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>';
|
||||
itemHtml += '<span>' + filter.Name + '</span>';
|
||||
itemHtml += '</label>';
|
||||
|
||||
elem.classList.remove('hide');
|
||||
return itemHtml;
|
||||
}).join('');
|
||||
|
||||
elem.querySelector('.filterOptions').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderDynamicFilters(context, result, options) {
|
||||
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
|
||||
// Switching from | to ,
|
||||
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
|
||||
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
function setBasicFilter(context, key, elem) {
|
||||
var value = elem.checked;
|
||||
value = value ? value : null;
|
||||
userSettings.setFilter(key, value);
|
||||
}
|
||||
function moveCheckboxFocus(elem, offset) {
|
||||
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
|
||||
var elems = focusManager.getFocusableElements(parent);
|
||||
|
||||
var index = -1;
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i] === elem) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index += offset;
|
||||
|
||||
index = Math.min(elems.length - 1, index);
|
||||
index = Math.max(0, index);
|
||||
|
||||
var newElem = elems[index];
|
||||
if (newElem) {
|
||||
focusManager.focus(newElem);
|
||||
}
|
||||
}
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('scrollHelper').then(({ default: scrollHelper }) => {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
function onInputCommand(e) {
|
||||
switch (e.detail.command) {
|
||||
case 'left':
|
||||
moveCheckboxFocus(e.target, -1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'right':
|
||||
moveCheckboxFocus(e.target, 1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input'));
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
html += items.map(function (filter) {
|
||||
|
||||
var itemHtml = '';
|
||||
|
||||
var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
|
||||
itemHtml += '<label>';
|
||||
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>';
|
||||
itemHtml += '<span>' + filter.Name + '</span>';
|
||||
itemHtml += '</label>';
|
||||
|
||||
return itemHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
elem.querySelector('.filterOptions').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderDynamicFilters(context, result, options) {
|
||||
// Video type
|
||||
var videoTypes = [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
// If there's a huge number of these they will be really show to render
|
||||
//if (result.Tags) {
|
||||
// result.Tags.length = Math.min(result.Tags.length, 50);
|
||||
//}
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
videoTypes.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
|
||||
|
||||
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
|
||||
// Series status
|
||||
var seriesStatuses = [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
// Switching from | to ,
|
||||
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
|
||||
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
|
||||
});
|
||||
|
||||
//renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
|
||||
// var delimeter = '|';
|
||||
// return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
|
||||
//renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
|
||||
// var delimeter = '|';
|
||||
// return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
|
||||
//renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
|
||||
|
||||
// var delimeter = ',';
|
||||
// return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
|
||||
//});
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
seriesStatuses.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
function loadDynamicFilters(context, options) {
|
||||
// Genres
|
||||
var genres = [];
|
||||
elems = context.querySelectorAll('.chkGenreFilter');
|
||||
|
||||
var apiClient = connectionManager.getApiClient(options.serverId);
|
||||
|
||||
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
|
||||
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ParentId: options.parentId,
|
||||
IncludeItemTypes: options.itemTypes.join(',')
|
||||
});
|
||||
|
||||
apiClient.getFilters(filterMenuOptions).then(function (result) {
|
||||
|
||||
renderDynamicFilters(context, result, options);
|
||||
}, function () {
|
||||
|
||||
// older server
|
||||
});
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].checked) {
|
||||
genres.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
function initEditor(context, settings) {
|
||||
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
} else {
|
||||
elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
}
|
||||
}
|
||||
|
||||
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.basicFilterSection').classList.remove('hide');
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
}
|
||||
function bindCheckboxInput(context, on) {
|
||||
var elems = context.querySelectorAll('.checkboxList-verticalwrap');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
if (on) {
|
||||
inputManager.on(elems[i], onInputCommand);
|
||||
} else {
|
||||
context.querySelector('.basicFilterSection').classList.add('hide');
|
||||
inputManager.off(elems[i], onInputCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
function initEditor(context, settings) {
|
||||
context.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
if (context.querySelector('.featureSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.featureSection').classList.remove('hide');
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
} else {
|
||||
context.querySelector('.featureSection').classList.add('hide');
|
||||
elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false;
|
||||
}
|
||||
}
|
||||
|
||||
function saveValues(context, settings, settingsKey) {
|
||||
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
var elems = context.querySelectorAll('.simpleFilter');
|
||||
var i;
|
||||
var length;
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].tagName === 'INPUT') {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
|
||||
} else {
|
||||
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input'));
|
||||
}
|
||||
}
|
||||
|
||||
// Video type
|
||||
var videoTypes = [];
|
||||
elems = context.querySelectorAll('.chkVideoTypeFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
videoTypes.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
|
||||
|
||||
// Series status
|
||||
var seriesStatuses = [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
seriesStatuses.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
|
||||
// Genres
|
||||
var genres = [];
|
||||
elems = context.querySelectorAll('.chkGenreFilter');
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
if (elems[i].checked) {
|
||||
genres.push(elems[i].getAttribute('data-filter'));
|
||||
}
|
||||
}
|
||||
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
function setBasicFilter(context, key, elem) {
|
||||
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
|
||||
elems = context.querySelectorAll('.chkSeriesStatus');
|
||||
|
||||
var value = elem.checked;
|
||||
value = value ? value : null;
|
||||
userSettings.setFilter(key, value);
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.basicFilterSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.basicFilterSection').classList.add('hide');
|
||||
}
|
||||
|
||||
function moveCheckboxFocus(elem, offset) {
|
||||
|
||||
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
|
||||
var elems = focusManager.getFocusableElements(parent);
|
||||
|
||||
var index = -1;
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
if (elems[i] === elem) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index += offset;
|
||||
|
||||
index = Math.min(elems.length - 1, index);
|
||||
index = Math.max(0, index);
|
||||
|
||||
var newElem = elems[index];
|
||||
if (newElem) {
|
||||
focusManager.focus(newElem);
|
||||
}
|
||||
if (context.querySelector('.featureSection .viewSetting:not(.hide)')) {
|
||||
context.querySelector('.featureSection').classList.remove('hide');
|
||||
} else {
|
||||
context.querySelector('.featureSection').classList.add('hide');
|
||||
}
|
||||
}
|
||||
function loadDynamicFilters(context, options) {
|
||||
var apiClient = window.connectionManager.getApiClient(options.serverId);
|
||||
|
||||
function onInputCommand(e) {
|
||||
switch (e.detail.command) {
|
||||
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
|
||||
|
||||
case 'left':
|
||||
moveCheckboxFocus(e.target, -1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case 'right':
|
||||
moveCheckboxFocus(e.target, 1);
|
||||
e.preventDefault();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function FilterMenu() {
|
||||
|
||||
}
|
||||
|
||||
function bindCheckboxInput(context, on) {
|
||||
|
||||
var elems = context.querySelectorAll('.checkboxList-verticalwrap');
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
if (on) {
|
||||
inputManager.on(elems[i], onInputCommand);
|
||||
} else {
|
||||
inputManager.off(elems[i], onInputCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FilterMenu.prototype.show = function (options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['text!./filtermenu.template.html'], function (template) {
|
||||
UserId: apiClient.getCurrentUserId(),
|
||||
ParentId: options.parentId,
|
||||
IncludeItemTypes: options.itemTypes.join(',')
|
||||
});
|
||||
|
||||
apiClient.getFilters(filterMenuOptions).then((result) => {
|
||||
renderDynamicFilters(context, result, options);
|
||||
});
|
||||
}
|
||||
class FilterMenu {
|
||||
show(options) {
|
||||
return new Promise( (resolve, reject) => {
|
||||
import('text!./filtermenu.template.html').then(({ default: template }) => {
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
@@ -286,10 +234,10 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||
|
||||
html += template;
|
||||
|
||||
dlg.innerHTML = globalize.translateDocument(html, 'core');
|
||||
dlg.innerHTML = globalize.translateHtml(html, 'core');
|
||||
|
||||
var settingElements = dlg.querySelectorAll('.viewSetting');
|
||||
for (var i = 0, length = settingElements.length; i < length; i++) {
|
||||
for (let i = 0, length = settingElements.length; i < length; i++) {
|
||||
if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) {
|
||||
settingElements[i].classList.add('hide');
|
||||
} else {
|
||||
@@ -301,9 +249,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||
loadDynamicFilters(dlg, options);
|
||||
|
||||
bindCheckboxInput(dlg, true);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
@@ -314,17 +260,10 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||
var submitted;
|
||||
|
||||
dlg.querySelector('form').addEventListener('change', function () {
|
||||
|
||||
submitted = true;
|
||||
//if (options.onChange) {
|
||||
// saveValues(dlg, options.settings, options.settingsKey);
|
||||
// options.onChange();
|
||||
//}
|
||||
|
||||
}, true);
|
||||
|
||||
dialogHelper.open(dlg).then(function () {
|
||||
|
||||
dialogHelper.open(dlg).then( function() {
|
||||
bindCheckboxInput(dlg, false);
|
||||
|
||||
if (layoutManager.tv) {
|
||||
@@ -332,19 +271,16 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost',
|
||||
}
|
||||
|
||||
if (submitted) {
|
||||
|
||||
//if (!options.onChange) {
|
||||
saveValues(dlg, options.settings, options.settingsKey);
|
||||
resolve();
|
||||
return resolve();
|
||||
//}
|
||||
return;
|
||||
}
|
||||
|
||||
reject();
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return FilterMenu;
|
||||
});
|
||||
export default FilterMenu;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
import dom from 'dom';
|
||||
import scrollManager from 'scrollManager';
|
||||
|
||||
var scopes = [];
|
||||
function pushScope(elem) {
|
||||
@@ -7,14 +9,12 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function popScope(elem) {
|
||||
|
||||
if (scopes.length) {
|
||||
scopes.length -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
function autoFocus(view, defaultToFirst, findAutoFocusElement) {
|
||||
|
||||
var element;
|
||||
if (findAutoFocusElement !== false) {
|
||||
element = view.querySelector('*[autofocus]');
|
||||
@@ -37,7 +37,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function focus(element) {
|
||||
|
||||
try {
|
||||
element.focus({
|
||||
preventScroll: scrollManager.isEnabled()
|
||||
@@ -50,16 +49,13 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'];
|
||||
var focusableContainerTagNames = ['BODY', 'DIALOG'];
|
||||
var focusableQuery = focusableTagNames.map(function (t) {
|
||||
|
||||
if (t === 'INPUT') {
|
||||
t += ':not([type="range"]):not([type="file"])';
|
||||
}
|
||||
return t + ':not([tabindex="-1"]):not(:disabled)';
|
||||
|
||||
}).join(',') + ',.focusable';
|
||||
|
||||
function isFocusable(elem) {
|
||||
|
||||
if (focusableTagNames.indexOf(elem.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
@@ -83,7 +79,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function focusableParent(elem) {
|
||||
|
||||
var originalElement = elem;
|
||||
|
||||
while (!isFocusable(elem)) {
|
||||
@@ -101,7 +96,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusableInternal(elem) {
|
||||
|
||||
// http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
|
||||
if (elem.offsetParent === null) {
|
||||
return false;
|
||||
@@ -112,7 +106,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
|
||||
// Determines if a focusable element can be focused at a given point in time
|
||||
function isCurrentlyFocusable(elem) {
|
||||
|
||||
if (elem.disabled) {
|
||||
return false;
|
||||
}
|
||||
@@ -143,7 +136,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var focusableElements = [];
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (excludeClass && elem.classList.contains(excludeClass)) {
|
||||
@@ -163,7 +155,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function isFocusContainer(elem, direction) {
|
||||
|
||||
if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
@@ -217,7 +208,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function getOffset(elem) {
|
||||
|
||||
var box;
|
||||
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
@@ -234,7 +224,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
if (box.right === null) {
|
||||
|
||||
// Create a new object because some browsers will throw an error when trying to set data onto the Rect object
|
||||
var newBox = {
|
||||
top: box.top,
|
||||
@@ -253,7 +242,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function nav(activeElement, direction, container, focusableElements) {
|
||||
|
||||
activeElement = activeElement || document.activeElement;
|
||||
|
||||
if (activeElement) {
|
||||
@@ -272,14 +260,10 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var rect = getOffset(activeElement);
|
||||
|
||||
// Get elements and work out x/y points
|
||||
var cache = [];
|
||||
var point1x = parseFloat(rect.left) || 0;
|
||||
var point1y = parseFloat(rect.top) || 0;
|
||||
var point2x = parseFloat(point1x + rect.width - 1) || point1x;
|
||||
var point2y = parseFloat(point1y + rect.height - 1) || point1y;
|
||||
// Shortcuts to help with compression
|
||||
var min = Math.min;
|
||||
var max = Math.max;
|
||||
|
||||
var sourceMidX = rect.left + (rect.width / 2);
|
||||
var sourceMidY = rect.top + (rect.height / 2);
|
||||
@@ -301,10 +285,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//if (!isCurrentlyFocusableInternal(curr)) {
|
||||
// continue;
|
||||
//}
|
||||
|
||||
var elementRect = getOffset(curr);
|
||||
|
||||
// not currently visible
|
||||
@@ -313,7 +293,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
if (elementRect.left >= rect.left) {
|
||||
@@ -369,7 +348,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var distY;
|
||||
|
||||
switch (direction) {
|
||||
|
||||
case 0:
|
||||
// left
|
||||
distX = Math.abs(point1x - Math.min(point1x, x2));
|
||||
@@ -403,7 +381,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
if (nearestElement) {
|
||||
|
||||
// See if there's a focusable container, and if so, send the focus command to that
|
||||
if (activeElement) {
|
||||
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
|
||||
@@ -418,12 +395,10 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function intersectsInternal(a1, a2, b1, b2) {
|
||||
|
||||
return (b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2);
|
||||
}
|
||||
|
||||
function intersects(a1, a2, b1, b2) {
|
||||
|
||||
return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2);
|
||||
}
|
||||
|
||||
@@ -434,11 +409,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function focusFirst(container, focusableSelector) {
|
||||
|
||||
var elems = container.querySelectorAll(focusableSelector);
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
@@ -449,11 +422,9 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function focusLast(container, focusableSelector) {
|
||||
|
||||
var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse();
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
@@ -464,7 +435,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
|
||||
function moveFocus(sourceElement, container, focusableSelector, offset) {
|
||||
|
||||
var elems = container.querySelectorAll(focusableSelector);
|
||||
var list = [];
|
||||
var i;
|
||||
@@ -472,7 +442,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var elem;
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elem = elems[i];
|
||||
|
||||
if (isCurrentlyFocusableInternal(elem)) {
|
||||
@@ -483,7 +452,6 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
var currentIndex = -1;
|
||||
|
||||
for (i = 0, length = list.length; i < length; i++) {
|
||||
|
||||
elem = list[i];
|
||||
|
||||
if (sourceElement === elem || elem.contains(sourceElement)) {
|
||||
@@ -506,37 +474,38 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) {
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
autoFocus: autoFocus,
|
||||
focus: focus,
|
||||
focusableParent: focusableParent,
|
||||
getFocusableElements: getFocusableElements,
|
||||
moveLeft: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 0, container, focusableElements);
|
||||
},
|
||||
moveRight: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 1, container, focusableElements);
|
||||
},
|
||||
moveUp: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 2, container, focusableElements);
|
||||
},
|
||||
moveDown: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 3, container, focusableElements);
|
||||
},
|
||||
sendText: sendText,
|
||||
isCurrentlyFocusable: isCurrentlyFocusable,
|
||||
pushScope: pushScope,
|
||||
popScope: popScope,
|
||||
focusFirst: focusFirst,
|
||||
focusLast: focusLast,
|
||||
moveFocus: moveFocus
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
autoFocus: autoFocus,
|
||||
focus: focus,
|
||||
focusableParent: focusableParent,
|
||||
getFocusableElements: getFocusableElements,
|
||||
moveLeft: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 0, container, focusableElements);
|
||||
},
|
||||
moveRight: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 1, container, focusableElements);
|
||||
},
|
||||
moveUp: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 2, container, focusableElements);
|
||||
},
|
||||
moveDown: function (sourceElement, options) {
|
||||
var container = options ? options.container : null;
|
||||
var focusableElements = options ? options.focusableElements : null;
|
||||
nav(sourceElement, 3, container, focusableElements);
|
||||
},
|
||||
sendText: sendText,
|
||||
isCurrentlyFocusable: isCurrentlyFocusable,
|
||||
pushScope: pushScope,
|
||||
popScope: popScope,
|
||||
focusFirst: focusFirst,
|
||||
focusLast: focusLast,
|
||||
moveFocus: moveFocus
|
||||
};
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
/* Without this emby-checkbox is able to appear on top */
|
||||
z-index: 1;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, connectionManager) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
import dom from 'dom';
|
||||
import appRouter from 'appRouter';
|
||||
|
||||
function onGroupedCardClick(e, card) {
|
||||
var itemId = card.getAttribute('data-id');
|
||||
var serverId = card.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var apiClient = window.connectionManager.getApiClient(serverId);
|
||||
var userId = apiClient.getCurrentUserId();
|
||||
var playedIndicator = card.querySelector('.playedIndicator');
|
||||
var playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null;
|
||||
@@ -18,11 +20,11 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn
|
||||
|
||||
if (!actionableParent || actionableParent.classList.contains('cardContent')) {
|
||||
apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) {
|
||||
if (1 === items.length) {
|
||||
if (items.length === 1) {
|
||||
return void appRouter.showItem(items[0]);
|
||||
}
|
||||
|
||||
var url = 'itemdetails.html?id=' + itemId + '&serverId=' + serverId;
|
||||
var url = 'details?id=' + itemId + '&serverId=' + serverId;
|
||||
Dashboard.navigate(url);
|
||||
});
|
||||
e.stopPropagation();
|
||||
@@ -31,7 +33,7 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn
|
||||
}
|
||||
}
|
||||
|
||||
function onItemsContainerClick(e) {
|
||||
export default function onItemsContainerClick(e) {
|
||||
var groupedCard = dom.parentWithClass(e.target, 'groupedCard');
|
||||
|
||||
if (groupedCard) {
|
||||
@@ -39,7 +41,4 @@ define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, conn
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
onItemsContainerClick: onItemsContainerClick
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,160 +1,149 @@
|
||||
define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import globalize from 'globalize';
|
||||
import * as userSettings from 'userSettings';
|
||||
import layoutManager from 'layoutManager';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-radio';
|
||||
import 'css!./../formdialog';
|
||||
import 'material-icons';
|
||||
|
||||
function saveCategories(context, options) {
|
||||
function saveCategories(context, options) {
|
||||
const categories = [];
|
||||
|
||||
var categories = [];
|
||||
const chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (const chkCategory of chkCategorys) {
|
||||
const type = chkCategory.getAttribute('data-type');
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
if (chkCategorys[i].checked) {
|
||||
categories.push(type);
|
||||
}
|
||||
}
|
||||
|
||||
if (categories.length >= 4) {
|
||||
categories.push('series');
|
||||
}
|
||||
|
||||
// differentiate between none and all
|
||||
categories.push('all');
|
||||
options.categories = categories;
|
||||
}
|
||||
|
||||
function loadCategories(context, options) {
|
||||
|
||||
var selectedCategories = options.categories || [];
|
||||
|
||||
var chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (var i = 0, length = chkCategorys.length; i < length; i++) {
|
||||
|
||||
var type = chkCategorys[i].getAttribute('data-type');
|
||||
|
||||
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
if (chkCategory.checked) {
|
||||
categories.push(type);
|
||||
}
|
||||
}
|
||||
|
||||
function save(context) {
|
||||
if (categories.length >= 4) {
|
||||
categories.push('series');
|
||||
}
|
||||
|
||||
var i;
|
||||
var length;
|
||||
// differentiate between none and all
|
||||
categories.push('all');
|
||||
options.categories = categories;
|
||||
}
|
||||
|
||||
var chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
for (i = 0, length = chkIndicators.length; i < length; i++) {
|
||||
function loadCategories(context, options) {
|
||||
const selectedCategories = options.categories || [];
|
||||
|
||||
var type = chkIndicators[i].getAttribute('data-type');
|
||||
userSettings.set('guide-indicator-' + type, chkIndicators[i].checked);
|
||||
const chkCategorys = context.querySelectorAll('.chkCategory');
|
||||
for (const chkCategory of chkCategorys) {
|
||||
const type = chkCategory.getAttribute('data-type');
|
||||
|
||||
chkCategory.checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
function save(context) {
|
||||
const chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
|
||||
for (const chkIndicator of chkIndicators) {
|
||||
const type = chkIndicator.getAttribute('data-type');
|
||||
userSettings.set('guide-indicator-' + type, chkIndicator.checked);
|
||||
}
|
||||
|
||||
userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked);
|
||||
userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked);
|
||||
|
||||
const sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (const sortBy of sortBys) {
|
||||
if (sortBy.checked) {
|
||||
userSettings.set('livetv-channelorder', sortBy.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked);
|
||||
userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked);
|
||||
function load(context) {
|
||||
const chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
|
||||
var sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
if (sortBys[i].checked) {
|
||||
userSettings.set('livetv-channelorder', sortBys[i].value);
|
||||
break;
|
||||
}
|
||||
for (const chkIndicator of chkIndicators) {
|
||||
const type = chkIndicator.getAttribute('data-type');
|
||||
|
||||
if (chkIndicator.getAttribute('data-default') === 'true') {
|
||||
chkIndicator.checked = userSettings.get('guide-indicator-' + type) !== 'false';
|
||||
} else {
|
||||
chkIndicator.checked = userSettings.get('guide-indicator-' + type) === 'true';
|
||||
}
|
||||
}
|
||||
|
||||
function load(context) {
|
||||
context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true';
|
||||
context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false';
|
||||
|
||||
var i;
|
||||
var length;
|
||||
const sortByValue = userSettings.get('livetv-channelorder') || 'Number';
|
||||
|
||||
var chkIndicators = context.querySelectorAll('.chkIndicator');
|
||||
for (i = 0, length = chkIndicators.length; i < length; i++) {
|
||||
const sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (const sortBy of sortBys) {
|
||||
sortBy.checked = sortBy.value === sortByValue;
|
||||
}
|
||||
}
|
||||
|
||||
var type = chkIndicators[i].getAttribute('data-type');
|
||||
function showEditor(options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let settingsChanged = false;
|
||||
|
||||
if (chkIndicators[i].getAttribute('data-default') === 'true') {
|
||||
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) !== 'false';
|
||||
import('text!./guide-settings.template.html').then(({ default: template }) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) === 'true';
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
}
|
||||
|
||||
context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true';
|
||||
context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false';
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
var sortByValue = userSettings.get('livetv-channelorder') || 'Number';
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var sortBys = context.querySelectorAll('.chkSortOrder');
|
||||
for (i = 0, length = sortBys.length; i < length; i++) {
|
||||
sortBys[i].checked = sortBys[i].value === sortByValue;
|
||||
}
|
||||
}
|
||||
let html = '';
|
||||
|
||||
function showEditor(options) {
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
dlg.innerHTML = html;
|
||||
|
||||
var settingsChanged = false;
|
||||
|
||||
require(['text!./guide-settings.template.html'], function (template) {
|
||||
|
||||
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 = '';
|
||||
|
||||
html += globalize.translateDocument(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
dlg.addEventListener('change', function () {
|
||||
|
||||
settingsChanged = true;
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
save(dlg);
|
||||
saveCategories(dlg, options);
|
||||
|
||||
if (settingsChanged) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
load(dlg);
|
||||
loadCategories(dlg, options);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.addEventListener('change', function () {
|
||||
settingsChanged = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: showEditor
|
||||
};
|
||||
});
|
||||
dlg.addEventListener('close', function () {
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
save(dlg);
|
||||
saveCategories(dlg, options);
|
||||
|
||||
if (settingsChanged) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
|
||||
}
|
||||
|
||||
load(dlg);
|
||||
loadCategories(dlg, options);
|
||||
dialogHelper.open(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
show: showEditor
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${Previous}" tabindex="-1">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.programContainer.emby-scroller {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.channelPrograms {
|
||||
height: 4.42em;
|
||||
contain: strict;
|
||||
|
||||
+1162
-1221
File diff suppressed because it is too large
Load Diff
@@ -29,10 +29,10 @@
|
||||
</div>
|
||||
|
||||
<div class="guideOptions hide">
|
||||
<button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${LabelPrevious}">
|
||||
<button is="paper-icon-button-light" type="button" class="btnPreviousPage" title="${Previous}">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" type="button" class="btnNextPage" title="${LabelNext}">
|
||||
<button is="paper-icon-button-light" type="button" class="btnNextPage" title="${Next}">
|
||||
<span class="material-icons arrow_forward" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,30 +1,37 @@
|
||||
define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loading', 'connectionManager', 'homeSections', 'dom', 'events', 'listViewStyle', 'emby-select', 'emby-checkbox'], function (require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) {
|
||||
'use strict';
|
||||
import layoutManager from 'layoutManager';
|
||||
import focusManager from 'focusManager';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import homeSections from 'homeSections';
|
||||
import dom from 'dom';
|
||||
import events from 'events';
|
||||
import 'listViewStyle';
|
||||
import 'emby-select';
|
||||
import 'emby-checkbox';
|
||||
|
||||
var numConfigurableSections = 7;
|
||||
/* eslint-disable indent */
|
||||
|
||||
const numConfigurableSections = 7;
|
||||
|
||||
function renderViews(page, user, result) {
|
||||
|
||||
var folderHtml = '';
|
||||
let folderHtml = '';
|
||||
|
||||
folderHtml += '<div class="checkboxList">';
|
||||
folderHtml += result.map(function (i) {
|
||||
folderHtml += result.map(i => {
|
||||
let currentHtml = '';
|
||||
|
||||
var currentHtml = '';
|
||||
const id = `chkGroupFolder${i.Id}`;
|
||||
|
||||
var id = 'chkGroupFolder' + i.Id;
|
||||
const isChecked = user.Configuration.GroupedFolders.includes(i.Id);
|
||||
|
||||
var isChecked = user.Configuration.GroupedFolders.indexOf(i.Id) !== -1;
|
||||
|
||||
var checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
const checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
|
||||
currentHtml += '<label>';
|
||||
currentHtml += '<input type="checkbox" is="emby-checkbox" class="chkGroupFolder" data-folderid="' + i.Id + '" id="' + id + '"' + checkedHtml + '/>';
|
||||
currentHtml += '<span>' + i.Name + '</span>';
|
||||
currentHtml += `<input type="checkbox" is="emby-checkbox" class="chkGroupFolder" data-folderid="${i.Id}" id="${id}"${checkedHtml}/>`;
|
||||
currentHtml += `<span>${i.Name}</span>`;
|
||||
currentHtml += '</label>';
|
||||
|
||||
return currentHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
folderHtml += '</div>';
|
||||
@@ -33,8 +40,7 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
function getLandingScreenOptions(type) {
|
||||
|
||||
var list = [];
|
||||
const list = [];
|
||||
|
||||
if (type === 'movies') {
|
||||
list.push({
|
||||
@@ -122,28 +128,22 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
function getLandingScreenOptionsHtml(type, userValue) {
|
||||
return getLandingScreenOptions(type).map(o => {
|
||||
const selected = userValue === o.value || (o.isDefault && !userValue);
|
||||
const selectedHtml = selected ? ' selected' : '';
|
||||
const optionValue = o.isDefault ? '' : o.value;
|
||||
|
||||
return getLandingScreenOptions(type).map(function (o) {
|
||||
|
||||
var selected = userValue === o.value || (o.isDefault && !userValue);
|
||||
var selectedHtml = selected ? ' selected' : '';
|
||||
var optionValue = o.isDefault ? '' : o.value;
|
||||
|
||||
return '<option value="' + optionValue + '"' + selectedHtml + '>' + o.name + '</option>';
|
||||
return `<option value="${optionValue}"${selectedHtml}>${o.name}</option>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function renderViewOrder(context, user, result) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
html += result.Items.map((view) => {
|
||||
let currentHtml = '';
|
||||
|
||||
var index = 0;
|
||||
|
||||
html += result.Items.map(function (view) {
|
||||
|
||||
var currentHtml = '';
|
||||
|
||||
currentHtml += '<div class="listItem viewItem" data-viewid="' + view.Id + '">';
|
||||
currentHtml += `<div class="listItem viewItem" data-viewid="${view.Id}">`;
|
||||
|
||||
currentHtml += '<span class="material-icons listItemIcon folder_open"></span>';
|
||||
|
||||
@@ -155,29 +155,25 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
|
||||
currentHtml += '</div>';
|
||||
|
||||
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemUp btnViewItemMove autoSize" title="' + globalize.translate('Up') + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="' + globalize.translate('Down') + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
currentHtml += `<button type="button" is="paper-icon-button-light" class="btnViewItemUp btnViewItemMove autoSize" title="${globalize.translate('Up')}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
currentHtml += `<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="${globalize.translate('Down')}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
|
||||
currentHtml += '</div>';
|
||||
|
||||
index++;
|
||||
return currentHtml;
|
||||
|
||||
}).join('');
|
||||
|
||||
context.querySelector('.viewOrderList').innerHTML = html;
|
||||
}
|
||||
|
||||
function updateHomeSectionValues(context, userSettings) {
|
||||
for (let i = 1; i <= 7; i++) {
|
||||
const select = context.querySelector(`#selectHomeSection${i}`);
|
||||
const defaultValue = homeSections.getDefaultSection(i - 1);
|
||||
|
||||
for (var i = 1; i <= 7; i++) {
|
||||
const option = select.querySelector(`option[value=${defaultValue}]`) || select.querySelector('option[value=""]');
|
||||
|
||||
var select = context.querySelector('#selectHomeSection' + i);
|
||||
var defaultValue = homeSections.getDefaultSection(i - 1);
|
||||
|
||||
var option = select.querySelector('option[value=' + defaultValue + ']') || select.querySelector('option[value=""]');
|
||||
|
||||
var userValue = userSettings.get('homesection' + (i - 1));
|
||||
const userValue = userSettings.get(`homesection${i - 1}`);
|
||||
|
||||
option.value = '';
|
||||
|
||||
@@ -192,43 +188,39 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
function getPerLibrarySettingsHtml(item, user, userSettings, apiClient) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
|
||||
var isChecked;
|
||||
let isChecked;
|
||||
|
||||
if (item.Type === 'Channel' || item.CollectionType === 'boxsets' || item.CollectionType === 'playlists') {
|
||||
isChecked = (user.Configuration.MyMediaExcludes || []).indexOf(item.Id) === -1;
|
||||
isChecked = !(user.Configuration.MyMediaExcludes || []).includes(item.Id);
|
||||
html += '<div>';
|
||||
html += '<label>';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInMyMedia" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : '') + '/>';
|
||||
html += '<span>' + globalize.translate('DisplayInMyMedia') + '</span>';
|
||||
html += `<input type="checkbox" is="emby-checkbox" class="chkIncludeInMyMedia" data-folderid="${item.Id}"${isChecked ? ' checked="checked"' : ''}/>`;
|
||||
html += `<span>${globalize.translate('DisplayInMyMedia')}</span>`;
|
||||
html += '</label>';
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
var excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels'];
|
||||
if (excludeFromLatest.indexOf(item.CollectionType || '') === -1) {
|
||||
|
||||
isChecked = user.Configuration.LatestItemsExcludes.indexOf(item.Id) === -1;
|
||||
const excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels'];
|
||||
if (!excludeFromLatest.includes(item.CollectionType || '')) {
|
||||
isChecked = !user.Configuration.LatestItemsExcludes.includes(item.Id);
|
||||
html += '<label class="fldIncludeInLatest">';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : '') + '/>';
|
||||
html += '<span>' + globalize.translate('DisplayInOtherHomeScreenSections') + '</span>';
|
||||
html += `<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="${item.Id}"${isChecked ? ' checked="checked"' : ''}/>`;
|
||||
html += `<span>${globalize.translate('DisplayInOtherHomeScreenSections')}</span>`;
|
||||
html += '</label>';
|
||||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
html = '<div class="checkboxListContainer">' + html + '</div>';
|
||||
html = `<div class="checkboxListContainer">${html}</div>`;
|
||||
}
|
||||
|
||||
if (item.CollectionType === 'movies' || item.CollectionType === 'tvshows' || item.CollectionType === 'music' || item.CollectionType === 'livetv') {
|
||||
|
||||
var idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id;
|
||||
const idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id;
|
||||
html += '<div class="selectContainer">';
|
||||
html += '<select is="emby-select" class="selectLanding" data-folderid="' + idForLanding + '" label="' + globalize.translate('LabelDefaultScreen') + '">';
|
||||
html += `<select is="emby-select" class="selectLanding" data-folderid="${idForLanding}" label="${globalize.translate('LabelDefaultScreen')}">`;
|
||||
|
||||
var userValue = userSettings.get('landing-' + idForLanding);
|
||||
const userValue = userSettings.get(`landing-${idForLanding}`);
|
||||
|
||||
html += getLandingScreenOptionsHtml(item.CollectionType, userValue);
|
||||
|
||||
@@ -237,8 +229,7 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
if (html) {
|
||||
|
||||
var prefix = '';
|
||||
let prefix = '';
|
||||
prefix += '<div class="verticalSection">';
|
||||
|
||||
prefix += '<h2 class="sectionTitle">';
|
||||
@@ -253,12 +244,10 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
function renderPerLibrarySettings(context, user, userViews, userSettings, apiClient) {
|
||||
const elem = context.querySelector('.perLibrarySettings');
|
||||
let html = '';
|
||||
|
||||
var elem = context.querySelector('.perLibrarySettings');
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = userViews.length; i < length; i++) {
|
||||
|
||||
for (let i = 0, length = userViews.length; i < length; i++) {
|
||||
html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient);
|
||||
}
|
||||
|
||||
@@ -266,16 +255,14 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
function loadForm(context, user, userSettings, apiClient) {
|
||||
|
||||
context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false;
|
||||
|
||||
updateHomeSectionValues(context, userSettings);
|
||||
|
||||
var promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id);
|
||||
var promise2 = apiClient.getJSON(apiClient.getUrl('Users/' + user.Id + '/GroupingOptions'));
|
||||
|
||||
Promise.all([promise1, promise2]).then(function (responses) {
|
||||
const promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id);
|
||||
const promise2 = apiClient.getJSON(apiClient.getUrl(`Users/${user.Id}/GroupingOptions`));
|
||||
|
||||
Promise.all([promise1, promise2]).then(responses => {
|
||||
renderViewOrder(context, user, responses[0]);
|
||||
|
||||
renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient);
|
||||
@@ -286,48 +273,23 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
});
|
||||
}
|
||||
|
||||
function getSibling(elem, type, className) {
|
||||
|
||||
var sibling = elem[type];
|
||||
|
||||
while (sibling != null) {
|
||||
if (sibling.classList.contains(className)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sibling != null) {
|
||||
if (!sibling.classList.contains(className)) {
|
||||
sibling = null;
|
||||
}
|
||||
}
|
||||
|
||||
return sibling;
|
||||
}
|
||||
|
||||
function onSectionOrderListClick(e) {
|
||||
|
||||
var target = dom.parentWithClass(e.target, 'btnViewItemMove');
|
||||
const target = dom.parentWithClass(e.target, 'btnViewItemMove');
|
||||
|
||||
if (target) {
|
||||
var viewItem = dom.parentWithClass(target, 'viewItem');
|
||||
const viewItem = dom.parentWithClass(target, 'viewItem');
|
||||
|
||||
if (viewItem) {
|
||||
var ul = dom.parentWithClass(viewItem, 'paperList');
|
||||
|
||||
if (target.classList.contains('btnViewItemDown')) {
|
||||
|
||||
var next = viewItem.nextSibling;
|
||||
const next = viewItem.nextSibling;
|
||||
|
||||
if (next) {
|
||||
viewItem.parentNode.removeChild(viewItem);
|
||||
next.parentNode.insertBefore(viewItem, next.nextSibling);
|
||||
focusManager.focus(e.target);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
var prev = viewItem.previousSibling;
|
||||
const prev = viewItem.previousSibling;
|
||||
|
||||
if (prev) {
|
||||
viewItem.parentNode.removeChild(viewItem);
|
||||
@@ -340,44 +302,37 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
function getCheckboxItems(selector, context, isChecked) {
|
||||
const inputs = context.querySelectorAll(selector);
|
||||
const list = [];
|
||||
|
||||
var inputs = context.querySelectorAll(selector);
|
||||
var list = [];
|
||||
|
||||
for (var i = 0, length = inputs.length; i < length; i++) {
|
||||
|
||||
for (let i = 0, length = inputs.length; i < length; i++) {
|
||||
if (inputs[i].checked === isChecked) {
|
||||
list.push(inputs[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||
|
||||
user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked;
|
||||
|
||||
user.Configuration.LatestItemsExcludes = getCheckboxItems('.chkIncludeInLatest', context, false).map(function (i) {
|
||||
|
||||
user.Configuration.LatestItemsExcludes = getCheckboxItems('.chkIncludeInLatest', context, false).map(i => {
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
user.Configuration.MyMediaExcludes = getCheckboxItems('.chkIncludeInMyMedia', context, false).map(function (i) {
|
||||
|
||||
user.Configuration.MyMediaExcludes = getCheckboxItems('.chkIncludeInMyMedia', context, false).map(i => {
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
user.Configuration.GroupedFolders = getCheckboxItems('.chkGroupFolder', context, true).map(function (i) {
|
||||
|
||||
user.Configuration.GroupedFolders = getCheckboxItems('.chkGroupFolder', context, true).map(i => {
|
||||
return i.getAttribute('data-folderid');
|
||||
});
|
||||
|
||||
var viewItems = context.querySelectorAll('.viewItem');
|
||||
var orderedViews = [];
|
||||
var i;
|
||||
var length;
|
||||
const viewItems = context.querySelectorAll('.viewItem');
|
||||
const orderedViews = [];
|
||||
let i;
|
||||
let length;
|
||||
for (i = 0, length = viewItems.length; i < length; i++) {
|
||||
orderedViews.push(viewItems[i].getAttribute('data-viewid'));
|
||||
}
|
||||
@@ -394,48 +349,42 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
userSettingsInstance.set('homesection5', context.querySelector('#selectHomeSection6').value);
|
||||
userSettingsInstance.set('homesection6', context.querySelector('#selectHomeSection7').value);
|
||||
|
||||
var selectLandings = context.querySelectorAll('.selectLanding');
|
||||
const selectLandings = context.querySelectorAll('.selectLanding');
|
||||
for (i = 0, length = selectLandings.length; i < length; i++) {
|
||||
var selectLanding = selectLandings[i];
|
||||
userSettingsInstance.set('landing-' + selectLanding.getAttribute('data-folderid'), selectLanding.value);
|
||||
const selectLanding = selectLandings[i];
|
||||
userSettingsInstance.set(`landing-${selectLanding.getAttribute('data-folderid')}`, selectLanding.value);
|
||||
}
|
||||
|
||||
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
|
||||
}
|
||||
|
||||
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.getUser(userId).then(function (user) {
|
||||
|
||||
saveUser(context, user, userSettings, apiClient).then(function () {
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
saveUser(context, user, userSettings, apiClient).then(() => {
|
||||
loading.hide();
|
||||
if (enableSaveConfirmation) {
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
});
|
||||
}
|
||||
|
||||
events.trigger(instance, 'saved');
|
||||
|
||||
}, function () {
|
||||
}, () => {
|
||||
loading.hide();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
const self = this;
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userId = self.options.userId;
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
var self = this;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userId = self.options.userId;
|
||||
var userSettings = self.options.userSettings;
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
|
||||
var enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
const enableSaveConfirmation = self.options.enableSaveConfirmation;
|
||||
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
|
||||
});
|
||||
|
||||
@@ -447,14 +396,13 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
function onChange(e) {
|
||||
|
||||
var chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
|
||||
const chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
|
||||
if (!chkIncludeInMyMedia) {
|
||||
return;
|
||||
}
|
||||
|
||||
var section = dom.parentWithClass(chkIncludeInMyMedia, 'verticalSection');
|
||||
var fldIncludeInLatest = section.querySelector('.fldIncludeInLatest');
|
||||
const section = dom.parentWithClass(chkIncludeInMyMedia, 'verticalSection');
|
||||
const fldIncludeInLatest = section.querySelector('.fldIncludeInLatest');
|
||||
if (fldIncludeInLatest) {
|
||||
if (chkIncludeInMyMedia.checked) {
|
||||
fldIncludeInLatest.classList.remove('hide');
|
||||
@@ -465,14 +413,12 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
}
|
||||
|
||||
function embed(options, self) {
|
||||
|
||||
require(['text!./homeScreenSettings.template.html'], function (template) {
|
||||
|
||||
for (var i = 1; i <= numConfigurableSections; i++) {
|
||||
template = template.replace('{section' + i + 'label}', globalize.translate('LabelHomeScreenSectionValue', i));
|
||||
return import('text!./homeScreenSettings.template.html').then(({default: template}) => {
|
||||
for (let i = 1; i <= numConfigurableSections; i++) {
|
||||
template = template.replace(`{section${i}label}`, globalize.translate('LabelHomeScreenSectionValue', i));
|
||||
}
|
||||
|
||||
options.element.innerHTML = globalize.translateDocument(template, 'core');
|
||||
options.element.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
options.element.querySelector('.viewOrderList').addEventListener('click', onSectionOrderListClick);
|
||||
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
|
||||
@@ -492,47 +438,44 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa
|
||||
});
|
||||
}
|
||||
|
||||
function HomeScreenSettings(options) {
|
||||
class HomeScreenSettings {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
embed(options, this);
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
loadData(autoFocus) {
|
||||
const self = this;
|
||||
const context = self.options.element;
|
||||
|
||||
embed(options, this);
|
||||
loading.show();
|
||||
|
||||
const userId = self.options.userId;
|
||||
const apiClient = window.connectionManager.getApiClient(self.options.serverId);
|
||||
const userSettings = self.options.userSettings;
|
||||
|
||||
apiClient.getUser(userId).then(user => {
|
||||
userSettings.setUserInfo(userId, apiClient).then(() => {
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
|
||||
if (autoFocus) {
|
||||
focusManager.autoFocus(context);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
submit() {
|
||||
onSubmit.call(this);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.options = null;
|
||||
}
|
||||
}
|
||||
|
||||
HomeScreenSettings.prototype.loadData = function (autoFocus) {
|
||||
/* eslint-enable indent */
|
||||
|
||||
var self = this;
|
||||
var context = self.options.element;
|
||||
|
||||
loading.show();
|
||||
|
||||
var userId = self.options.userId;
|
||||
var apiClient = connectionManager.getApiClient(self.options.serverId);
|
||||
var userSettings = self.options.userSettings;
|
||||
|
||||
apiClient.getUser(userId).then(function (user) {
|
||||
|
||||
userSettings.setUserInfo(userId, apiClient).then(function () {
|
||||
|
||||
self.dataLoaded = true;
|
||||
|
||||
loadForm(context, user, userSettings, apiClient);
|
||||
|
||||
if (autoFocus) {
|
||||
focusManager.autoFocus(context);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
HomeScreenSettings.prototype.submit = function () {
|
||||
onSubmit.call(this);
|
||||
};
|
||||
|
||||
HomeScreenSettings.prototype.destroy = function () {
|
||||
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return HomeScreenSettings;
|
||||
});
|
||||
export default HomeScreenSettings;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<form style="margin:0 auto;">
|
||||
<div class="verticalSection verticalSection-extrabottompadding">
|
||||
<h2 class="sectionTitle">${HeaderHome}</h2>
|
||||
<h2 class="sectionTitle">${Home}</h2>
|
||||
|
||||
<div class="selectContainer hide selectTVHomeScreenContainer">
|
||||
<select is="emby-select" class="selectTVHomeScreen" label="${LabelTVHomeScreen}">
|
||||
@@ -25,7 +25,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -38,7 +38,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -51,7 +51,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -64,7 +64,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -77,7 +77,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -90,7 +90,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
@@ -103,7 +103,7 @@
|
||||
<option value="resume">${HeaderContinueWatching}</option>
|
||||
<option value="resumeaudio">${HeaderContinueListening}</option>
|
||||
<option value="latestmedia">${HeaderLatestMedia}</option>
|
||||
<option value="nextup">${HeaderNextUp}</option>
|
||||
<option value="nextup">${NextUp}</option>
|
||||
<option value="livetv">${LiveTV}</option>
|
||||
<option value="none">${None}</option>
|
||||
</select>
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'layoutManager', 'imageLoader', 'globalize', 'itemShortcuts', 'itemHelper', 'appRouter', 'scripts/imagehelper', 'paper-icon-button-light', 'emby-itemscontainer', 'emby-scroller', 'emby-button', 'css!./homesections'], function (connectionManager, cardBuilder, appSettings, dom, appHost, layoutManager, imageLoader, globalize, itemShortcuts, itemHelper, appRouter, imageHelper) {
|
||||
'use strict';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
import imageLoader from 'imageLoader';
|
||||
import globalize from 'globalize';
|
||||
import appRouter from 'appRouter';
|
||||
import imageHelper from 'scripts/imagehelper';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-itemscontainer';
|
||||
import 'emby-scroller';
|
||||
import 'emby-button';
|
||||
import 'css!./homesections';
|
||||
|
||||
function getDefaultSection(index) {
|
||||
/* eslint-disable indent */
|
||||
|
||||
export function getDefaultSection(index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return 'smalllibrarytiles';
|
||||
@@ -23,9 +35,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function getAllSectionsToShow(userSettings, sectionCount) {
|
||||
var sections = [];
|
||||
for (var i = 0, length = sectionCount; i < length; i++) {
|
||||
var section = userSettings.get('homesection' + i) || getDefaultSection(i);
|
||||
const sections = [];
|
||||
for (let i = 0, length = sectionCount; i < length; i++) {
|
||||
let section = userSettings.get('homesection' + i) || getDefaultSection(i);
|
||||
if (section === 'folders') {
|
||||
section = getDefaultSection(0);
|
||||
}
|
||||
@@ -36,22 +48,22 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
return sections;
|
||||
}
|
||||
|
||||
function loadSections(elem, apiClient, user, userSettings) {
|
||||
export function loadSections(elem, apiClient, user, userSettings) {
|
||||
return getUserViews(apiClient, user.Id).then(function (userViews) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
if (userViews.length) {
|
||||
var sectionCount = 7;
|
||||
for (var i = 0; i < sectionCount; i++) {
|
||||
const sectionCount = 7;
|
||||
for (let i = 0; i < sectionCount; i++) {
|
||||
html += '<div class="verticalSection section' + i + '"></div>';
|
||||
}
|
||||
|
||||
elem.innerHTML = html;
|
||||
elem.classList.add('homeSectionsContainer');
|
||||
|
||||
var promises = [];
|
||||
var sections = getAllSectionsToShow(userSettings, sectionCount);
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
const promises = [];
|
||||
const sections = getAllSectionsToShow(userSettings, sectionCount);
|
||||
for (let i = 0; i < sections.length; i++) {
|
||||
promises.push(loadSection(elem, apiClient, user, userSettings, userViews, sections, i));
|
||||
}
|
||||
|
||||
@@ -62,7 +74,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
});
|
||||
});
|
||||
} else {
|
||||
var noLibDescription;
|
||||
let noLibDescription;
|
||||
if (user['Policy'] && user['Policy']['IsAdministrator']) {
|
||||
noLibDescription = globalize.translate('NoCreatedLibraries', '<br><a id="button-createLibrary" class="button-link">', '</a>');
|
||||
} else {
|
||||
@@ -75,7 +87,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
html += '</div>';
|
||||
elem.innerHTML = html;
|
||||
|
||||
var createNowLink = elem.querySelector('#button-createLibrary');
|
||||
const createNowLink = elem.querySelector('#button-createLibrary');
|
||||
if (createNowLink) {
|
||||
createNowLink.addEventListener('click', function () {
|
||||
Dashboard.navigate('library.html');
|
||||
@@ -85,9 +97,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
});
|
||||
}
|
||||
|
||||
function destroySections(elem) {
|
||||
var elems = elem.querySelectorAll('.itemsContainer');
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
export function destroySections(elem) {
|
||||
const elems = elem.querySelectorAll('.itemsContainer');
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].fetchData = null;
|
||||
elems[i].parentContainer = null;
|
||||
elems[i].getItemsHtml = null;
|
||||
@@ -96,35 +108,32 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
elem.innerHTML = '';
|
||||
}
|
||||
|
||||
function pause(elem) {
|
||||
var elems = elem.querySelectorAll('.itemsContainer');
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
export function pause(elem) {
|
||||
const elems = elem.querySelectorAll('.itemsContainer');
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
elems[i].pause();
|
||||
}
|
||||
}
|
||||
|
||||
function resume(elem, options) {
|
||||
var elems = elem.querySelectorAll('.itemsContainer');
|
||||
var i;
|
||||
var length;
|
||||
var promises = [];
|
||||
export function resume(elem, options) {
|
||||
const elems = elem.querySelectorAll('.itemsContainer');
|
||||
const promises = [];
|
||||
|
||||
for (i = 0, length = elems.length; i < length; i++) {
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
promises.push(elems[i].resume(options));
|
||||
}
|
||||
|
||||
var promise = Promise.all(promises);
|
||||
const promise = Promise.all(promises);
|
||||
if (!options || options.returnPromise !== false) {
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
function loadSection(page, apiClient, user, userSettings, userViews, allSections, index) {
|
||||
const section = allSections[index];
|
||||
const userId = user.Id;
|
||||
|
||||
var section = allSections[index];
|
||||
var userId = user.Id;
|
||||
|
||||
var elem = page.querySelector('.section' + index);
|
||||
const elem = page.querySelector('.section' + index);
|
||||
|
||||
if (section === 'latestmedia') {
|
||||
loadRecentlyAdded(elem, apiClient, user, userViews);
|
||||
@@ -168,11 +177,11 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function getPortraitShape() {
|
||||
return enableScrollX() ? 'autooverflow' : 'auto';
|
||||
return enableScrollX() ? 'overflowPortrait' : 'portrait';
|
||||
}
|
||||
|
||||
function getLibraryButtonsHtml(items) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<div class="verticalSection verticalSection-extrabottompadding">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderMyMedia') + '</h2>';
|
||||
@@ -180,9 +189,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
html += '<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right vertical-wrap focuscontainer-x" data-multiselect="false">';
|
||||
|
||||
// library card background images
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
var item = items[i];
|
||||
var icon = imageHelper.getLibraryIcon(item.CollectionType);
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
const item = items[i];
|
||||
const icon = imageHelper.getLibraryIcon(item.CollectionType);
|
||||
html += '<a is="emby-linkbutton" href="' + appRouter.getRouteUrl(item) + '" class="raised homeLibraryButton"><span class="material-icons homeLibraryIcon ' + icon + '"></span><span class="homeLibraryText">' + item.Name + '</span></a>';
|
||||
}
|
||||
|
||||
@@ -194,24 +203,16 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function loadlibraryButtons(elem, apiClient, user, userSettings, userViews) {
|
||||
elem.classList.remove('verticalSection');
|
||||
var html = getLibraryButtonsHtml(userViews);
|
||||
const html = getLibraryButtonsHtml(userViews);
|
||||
|
||||
elem.innerHTML = html;
|
||||
imageLoader.lazyChildren(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random integer between min (inclusive) and max (inclusive)
|
||||
* Using Math.round() will give you a non-uniform distribution!
|
||||
*/
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function getFetchLatestItemsFn(serverId, parentId, collectionType) {
|
||||
return function () {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var limit = 16;
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
let limit = 16;
|
||||
|
||||
if (enableScrollX()) {
|
||||
if (collectionType === 'music') {
|
||||
@@ -227,7 +228,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
}
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
Limit: limit,
|
||||
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo,Path',
|
||||
ImageTypeLimit: 1,
|
||||
@@ -241,8 +242,8 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function getLatestItemsHtmlFn(itemType, viewType) {
|
||||
return function (items) {
|
||||
var cardLayout = false;
|
||||
var shape;
|
||||
const cardLayout = false;
|
||||
let shape;
|
||||
if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books' || viewType === 'tvshows') {
|
||||
shape = getPortraitShape();
|
||||
} else if (viewType === 'music' || viewType === 'homevideos') {
|
||||
@@ -254,7 +255,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
shape: shape,
|
||||
preferThumb: viewType !== 'movies' && itemType !== 'Channel' && viewType !== 'music' ? 'auto' : null,
|
||||
preferThumb: viewType !== 'movies' && viewType !== 'tvshows' && itemType !== 'Channel' && viewType !== 'music' ? 'auto' : null,
|
||||
showUnplayedIndicator: false,
|
||||
showChildCountIndicator: true,
|
||||
context: 'home',
|
||||
@@ -272,7 +273,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function renderLatestSection(elem, apiClient, user, parent) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">';
|
||||
if (!layoutManager.tv) {
|
||||
@@ -303,7 +304,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
elem.innerHTML = html;
|
||||
|
||||
var itemsContainer = elem.querySelector('.itemsContainer');
|
||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||
itemsContainer.fetchData = getFetchLatestItemsFn(apiClient.serverId(), parent.Id, parent.CollectionType);
|
||||
itemsContainer.getItemsHtml = getLatestItemsHtmlFn(parent.Type, parent.CollectionType);
|
||||
itemsContainer.parentContainer = elem;
|
||||
@@ -311,10 +312,10 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function loadRecentlyAdded(elem, apiClient, user, userViews) {
|
||||
elem.classList.remove('verticalSection');
|
||||
var excludeViewTypes = ['playlists', 'livetv', 'boxsets', 'channels'];
|
||||
const excludeViewTypes = ['playlists', 'livetv', 'boxsets', 'channels'];
|
||||
|
||||
for (var i = 0, length = userViews.length; i < length; i++) {
|
||||
var item = userViews[i];
|
||||
for (let i = 0, length = userViews.length; i < length; i++) {
|
||||
const item = userViews[i];
|
||||
if (user.Configuration.LatestItemsExcludes.indexOf(item.Id) !== -1) {
|
||||
continue;
|
||||
}
|
||||
@@ -323,7 +324,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
continue;
|
||||
}
|
||||
|
||||
var frag = document.createElement('div');
|
||||
const frag = document.createElement('div');
|
||||
frag.classList.add('verticalSection');
|
||||
frag.classList.add('hide');
|
||||
elem.appendChild(frag);
|
||||
@@ -332,14 +333,8 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
}
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(deps, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function loadLibraryTiles(elem, apiClient, user, userSettings, shape, userViews, allSections) {
|
||||
var html = '';
|
||||
export function loadLibraryTiles(elem, apiClient, user, userSettings, shape, userViews, allSections) {
|
||||
let html = '';
|
||||
if (userViews.length) {
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderMyMedia') + '</h2>';
|
||||
if (enableScrollX()) {
|
||||
@@ -372,10 +367,10 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function getContinueWatchingFetchFn(serverId) {
|
||||
return function () {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var screenWidth = dom.getWindowSize().innerWidth;
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
|
||||
var limit;
|
||||
let limit;
|
||||
if (enableScrollX()) {
|
||||
limit = 12;
|
||||
} else {
|
||||
@@ -383,7 +378,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
limit = Math.min(limit, 5);
|
||||
}
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
Limit: limit,
|
||||
Recursive: true,
|
||||
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
|
||||
@@ -398,7 +393,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function getContinueWatchingItemsHtml(items) {
|
||||
var cardLayout = false;
|
||||
const cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
preferThumb: true,
|
||||
@@ -419,7 +414,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function loadResumeVideo(elem, apiClient, userId) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueWatching') + '</h2>';
|
||||
if (enableScrollX()) {
|
||||
@@ -437,7 +432,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
elem.classList.add('hide');
|
||||
elem.innerHTML = html;
|
||||
|
||||
var itemsContainer = elem.querySelector('.itemsContainer');
|
||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||
itemsContainer.fetchData = getContinueWatchingFetchFn(apiClient.serverId());
|
||||
itemsContainer.getItemsHtml = getContinueWatchingItemsHtml;
|
||||
itemsContainer.parentContainer = elem;
|
||||
@@ -445,10 +440,10 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function getContinueListeningFetchFn(serverId) {
|
||||
return function () {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
var screenWidth = dom.getWindowSize().innerWidth;
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
const screenWidth = dom.getWindowSize().innerWidth;
|
||||
|
||||
var limit;
|
||||
let limit;
|
||||
if (enableScrollX()) {
|
||||
limit = 12;
|
||||
} else {
|
||||
@@ -456,7 +451,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
limit = Math.min(limit, 5);
|
||||
}
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
Limit: limit,
|
||||
Recursive: true,
|
||||
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
|
||||
@@ -471,7 +466,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function getContinueListeningItemsHtml(items) {
|
||||
var cardLayout = false;
|
||||
const cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
preferThumb: true,
|
||||
@@ -492,7 +487,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function loadResumeAudio(elem, apiClient, userId) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + globalize.translate('HeaderContinueWatching') + '</h2>';
|
||||
if (enableScrollX()) {
|
||||
@@ -510,7 +505,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
elem.classList.add('hide');
|
||||
elem.innerHTML = html;
|
||||
|
||||
var itemsContainer = elem.querySelector('.itemsContainer');
|
||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||
itemsContainer.fetchData = getContinueListeningFetchFn(apiClient.serverId());
|
||||
itemsContainer.getItemsHtml = getContinueListeningItemsHtml;
|
||||
itemsContainer.parentContainer = elem;
|
||||
@@ -518,7 +513,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function getOnNowFetchFn(serverId) {
|
||||
return function () {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getLiveTvRecommendedPrograms({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
IsAiring: true,
|
||||
@@ -532,7 +527,6 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function getOnNowItemsHtml(items) {
|
||||
var cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
preferThumb: 'auto',
|
||||
@@ -559,7 +553,6 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var userId = user.Id;
|
||||
return apiClient.getLiveTvRecommendedPrograms({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
IsAiring: true,
|
||||
@@ -569,7 +562,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
EnableTotalRecordCount: false,
|
||||
Fields: 'ChannelInfo,PrimaryImageAspectRatio'
|
||||
}).then(function (result) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
if (result.Items.length) {
|
||||
elem.classList.remove('padded-left');
|
||||
elem.classList.remove('padded-right');
|
||||
@@ -632,7 +625,6 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
html += '</h2>';
|
||||
html += '<span class="material-icons chevron_right"></span>';
|
||||
html += '</a>';
|
||||
|
||||
} else {
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderOnNow') + '</h2>';
|
||||
}
|
||||
@@ -654,7 +646,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
elem.innerHTML = html;
|
||||
|
||||
var itemsContainer = elem.querySelector('.itemsContainer');
|
||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||
itemsContainer.parentContainer = elem;
|
||||
itemsContainer.fetchData = getOnNowFetchFn(apiClient.serverId());
|
||||
itemsContainer.getItemsHtml = getOnNowItemsHtml;
|
||||
@@ -664,7 +656,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function getNextUpFetchFn(serverId) {
|
||||
return function () {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getNextUpEpisodes({
|
||||
Limit: enableScrollX() ? 24 : 15,
|
||||
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo,Path',
|
||||
@@ -677,7 +669,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function getNextUpItemsHtml(items) {
|
||||
var cardLayout = false;
|
||||
const cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
preferThumb: true,
|
||||
@@ -695,7 +687,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function loadNextUp(elem, apiClient, userId) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<div class="sectionTitleContainer sectionTitleContainer-cards padded-left">';
|
||||
if (!layoutManager.tv) {
|
||||
@@ -703,12 +695,12 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
serverId: apiClient.serverId()
|
||||
}) + '" class="button-flat button-flat-mini sectionTitleTextButton">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">';
|
||||
html += globalize.translate('HeaderNextUp');
|
||||
html += globalize.translate('NextUp');
|
||||
html += '</h2>';
|
||||
html += '<span class="material-icons chevron_right"></span>';
|
||||
html += '</a>';
|
||||
} else {
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('HeaderNextUp') + '</h2>';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards">' + globalize.translate('NextUp') + '</h2>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
@@ -727,7 +719,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
elem.classList.add('hide');
|
||||
elem.innerHTML = html;
|
||||
|
||||
var itemsContainer = elem.querySelector('.itemsContainer');
|
||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||
itemsContainer.fetchData = getNextUpFetchFn(apiClient.serverId());
|
||||
itemsContainer.getItemsHtml = getNextUpItemsHtml;
|
||||
itemsContainer.parentContainer = elem;
|
||||
@@ -735,7 +727,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function getLatestRecordingsFetchFn(serverId, activeRecordingsOnly) {
|
||||
return function () {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getLiveTvRecordings({
|
||||
userId: apiClient.getCurrentUserId(),
|
||||
Limit: enableScrollX() ? 12 : 5,
|
||||
@@ -749,7 +741,6 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
|
||||
function getLatestRecordingItemsHtml(activeRecordingsOnly) {
|
||||
return function (items) {
|
||||
var cardLayout = false;
|
||||
return cardBuilder.getCardsHtml({
|
||||
items: items,
|
||||
shape: enableScrollX() ? 'autooverflow' : 'auto',
|
||||
@@ -774,11 +765,11 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
}
|
||||
|
||||
function loadLatestLiveTvRecordings(elem, activeRecordingsOnly, apiClient, userId) {
|
||||
var title = activeRecordingsOnly ?
|
||||
const title = activeRecordingsOnly ?
|
||||
globalize.translate('HeaderActiveRecordings') :
|
||||
globalize.translate('HeaderLatestRecordings');
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<div class="sectionTitleContainer sectionTitleContainer-cards">';
|
||||
html += '<h2 class="sectionTitle sectionTitle-cards padded-left">' + title + '</h2>';
|
||||
@@ -799,18 +790,19 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la
|
||||
elem.classList.add('hide');
|
||||
elem.innerHTML = html;
|
||||
|
||||
var itemsContainer = elem.querySelector('.itemsContainer');
|
||||
const itemsContainer = elem.querySelector('.itemsContainer');
|
||||
itemsContainer.fetchData = getLatestRecordingsFetchFn(apiClient.serverId(), activeRecordingsOnly);
|
||||
itemsContainer.getItemsHtml = getLatestRecordingItemsHtml(activeRecordingsOnly);
|
||||
itemsContainer.parentContainer = elem;
|
||||
}
|
||||
|
||||
return {
|
||||
loadLibraryTiles: loadLibraryTiles,
|
||||
getDefaultSection: getDefaultSection,
|
||||
loadSections: loadSections,
|
||||
destroySections: destroySections,
|
||||
pause: pause,
|
||||
resume: resume
|
||||
};
|
||||
});
|
||||
export default {
|
||||
loadLibraryTiles: loadLibraryTiles,
|
||||
getDefaultSection: getDefaultSection,
|
||||
loadSections: loadSections,
|
||||
destroySections: destroySections,
|
||||
pause: pause,
|
||||
resume: resume
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
define(['appSettings', 'browser', 'events'], function (appSettings, browser, events) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
function getSavedVolume() {
|
||||
import appSettings from 'appSettings' ;
|
||||
import browser from 'browser';
|
||||
import events from 'events';
|
||||
|
||||
export function getSavedVolume() {
|
||||
return appSettings.get('volume') || 1;
|
||||
}
|
||||
|
||||
function saveVolume(value) {
|
||||
export function saveVolume(value) {
|
||||
if (value) {
|
||||
appSettings.set('volume', value);
|
||||
}
|
||||
}
|
||||
|
||||
function getCrossOriginValue(mediaSource) {
|
||||
export function getCrossOriginValue(mediaSource) {
|
||||
if (mediaSource.IsRemote) {
|
||||
return null;
|
||||
}
|
||||
@@ -30,34 +33,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
return false;
|
||||
}
|
||||
|
||||
function enableHlsShakaPlayer(item, mediaSource, mediaType) {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
|
||||
|
||||
if (canPlayNativeHls()) {
|
||||
|
||||
if (browser.edge && mediaType === 'Video') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// simple playback should use the native support
|
||||
if (mediaSource.RunTimeTicks) {
|
||||
//if (!browser.edge) {
|
||||
//return false;
|
||||
//}
|
||||
}
|
||||
|
||||
//return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function enableHlsJsPlayer(runTimeTicks, mediaType) {
|
||||
|
||||
export function enableHlsJsPlayer(runTimeTicks, mediaType) {
|
||||
if (window.MediaSource == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -73,7 +49,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
|
||||
if (canPlayNativeHls()) {
|
||||
|
||||
// Having trouble with chrome's native support and transcoded music
|
||||
if (browser.android && mediaType === 'Audio') {
|
||||
return true;
|
||||
@@ -98,8 +73,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
|
||||
var recoverDecodingErrorDate;
|
||||
var recoverSwapAudioCodecDate;
|
||||
function handleHlsJsMediaError(instance, reject) {
|
||||
|
||||
export function handleHlsJsMediaError(instance, reject) {
|
||||
var hlsPlayer = instance._hlsPlayer;
|
||||
|
||||
if (!hlsPlayer) {
|
||||
@@ -134,8 +108,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
}
|
||||
|
||||
function onErrorInternal(instance, type) {
|
||||
|
||||
export function onErrorInternal(instance, type) {
|
||||
// Needed for video
|
||||
if (instance.destroyCustomTrack) {
|
||||
instance.destroyCustomTrack(instance._mediaElement);
|
||||
@@ -148,7 +121,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
]);
|
||||
}
|
||||
|
||||
function isValidDuration(duration) {
|
||||
export function isValidDuration(duration) {
|
||||
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
||||
return true;
|
||||
}
|
||||
@@ -162,13 +135,10 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
}
|
||||
|
||||
function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
|
||||
|
||||
export function seekOnPlaybackStart(instance, element, ticks, onMediaReady) {
|
||||
var seconds = (ticks || 0) / 10000000;
|
||||
|
||||
if (seconds) {
|
||||
var src = (instance.currentSrc() || '').toLowerCase();
|
||||
|
||||
// Appending #t=xxx to the query string doesn't seem to work with HLS
|
||||
// For plain video files, not all browsers support it either
|
||||
|
||||
@@ -200,12 +170,9 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
}
|
||||
|
||||
function applySrc(elem, src, options) {
|
||||
|
||||
export function applySrc(elem, src, options) {
|
||||
if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
|
||||
|
||||
return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) {
|
||||
|
||||
var playlist = new Windows.Media.Playback.MediaPlaybackList();
|
||||
|
||||
var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file);
|
||||
@@ -214,9 +181,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true });
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
elem.src = src;
|
||||
}
|
||||
|
||||
@@ -224,18 +189,15 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
|
||||
function onSuccessfulPlay(elem, onErrorFn) {
|
||||
|
||||
elem.addEventListener('error', onErrorFn);
|
||||
}
|
||||
|
||||
function playWithPromise(elem, onErrorFn) {
|
||||
|
||||
export function playWithPromise(elem, onErrorFn) {
|
||||
try {
|
||||
var promise = elem.play();
|
||||
if (promise && promise.then) {
|
||||
// Chrome now returns a promise
|
||||
return promise.catch(function (e) {
|
||||
|
||||
var errorName = (e.name || '').toLowerCase();
|
||||
// safari uses aborterror
|
||||
if (errorName === 'notallowederror' ||
|
||||
@@ -256,8 +218,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
}
|
||||
|
||||
function destroyCastPlayer(instance) {
|
||||
|
||||
export function destroyCastPlayer(instance) {
|
||||
var player = instance._castPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
@@ -270,20 +231,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
}
|
||||
|
||||
function destroyShakaPlayer(instance) {
|
||||
var player = instance._shakaPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
player.destroy();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
instance._shakaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function destroyHlsPlayer(instance) {
|
||||
export function destroyHlsPlayer(instance) {
|
||||
var player = instance._hlsPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
@@ -296,7 +244,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
}
|
||||
|
||||
function destroyFlvPlayer(instance) {
|
||||
export function destroyFlvPlayer(instance) {
|
||||
var player = instance._flvPlayer;
|
||||
if (player) {
|
||||
try {
|
||||
@@ -311,11 +259,9 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
}
|
||||
|
||||
function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
|
||||
|
||||
export function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||
playWithPromise(elem, onErrorFn).then(resolve, function () {
|
||||
|
||||
if (reject) {
|
||||
reject();
|
||||
reject = null;
|
||||
@@ -324,14 +270,12 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
});
|
||||
|
||||
hls.on(Hls.Events.ERROR, function (event, data) {
|
||||
|
||||
console.error('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false));
|
||||
|
||||
switch (data.type) {
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
// try to recover network error
|
||||
if (data.response && data.response.code && data.response.code >= 400) {
|
||||
|
||||
console.debug('hls.js response error code: ' + data.response.code);
|
||||
|
||||
// Trigger failure differently depending on whether this is prior to start of playback, or after
|
||||
@@ -345,7 +289,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -358,7 +301,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
|
||||
if (data.response && data.response.code === 0) {
|
||||
|
||||
// This could be a CORS error related to access control response headers
|
||||
|
||||
console.debug('hls.js response error code: ' + data.response.code);
|
||||
@@ -403,8 +345,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
});
|
||||
}
|
||||
|
||||
function onEndedInternal(instance, elem, onErrorFn) {
|
||||
|
||||
export function onEndedInternal(instance, elem, onErrorFn) {
|
||||
elem.removeEventListener('error', onErrorFn);
|
||||
|
||||
elem.src = '';
|
||||
@@ -413,7 +354,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
|
||||
destroyHlsPlayer(instance);
|
||||
destroyFlvPlayer(instance);
|
||||
destroyShakaPlayer(instance);
|
||||
destroyCastPlayer(instance);
|
||||
|
||||
var stopInfo = {
|
||||
@@ -427,8 +367,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
instance._currentPlayOptions = null;
|
||||
}
|
||||
|
||||
function getBufferedRanges(instance, elem) {
|
||||
|
||||
export function getBufferedRanges(instance, elem) {
|
||||
var ranges = [];
|
||||
var seekable = elem.buffered || [];
|
||||
|
||||
@@ -441,7 +380,6 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
offset = offset || 0;
|
||||
|
||||
for (var i = 0, length = seekable.length; i < length; i++) {
|
||||
|
||||
var start = seekable.start(i);
|
||||
var end = seekable.end(i);
|
||||
|
||||
@@ -462,23 +400,4 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve
|
||||
return ranges;
|
||||
}
|
||||
|
||||
return {
|
||||
getSavedVolume: getSavedVolume,
|
||||
saveVolume: saveVolume,
|
||||
enableHlsJsPlayer: enableHlsJsPlayer,
|
||||
enableHlsShakaPlayer: enableHlsShakaPlayer,
|
||||
handleHlsJsMediaError: handleHlsJsMediaError,
|
||||
isValidDuration: isValidDuration,
|
||||
onErrorInternal: onErrorInternal,
|
||||
seekOnPlaybackStart: seekOnPlaybackStart,
|
||||
applySrc: applySrc,
|
||||
playWithPromise: playWithPromise,
|
||||
destroyHlsPlayer: destroyHlsPlayer,
|
||||
destroyFlvPlayer: destroyFlvPlayer,
|
||||
destroyCastPlayer: destroyCastPlayer,
|
||||
bindEventsToHlsPlayer: bindEventsToHlsPlayer,
|
||||
onEndedInternal: onEndedInternal,
|
||||
getCrossOriginValue: getCrossOriginValue,
|
||||
getBufferedRanges: getBufferedRanges
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,37 @@
|
||||
define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader', 'browser', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'emby-checkbox', 'paper-icon-button-light', 'emby-button', 'formDialogStyle', 'cardStyle'], function (dom, loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import loading from 'loading';
|
||||
import appHost from 'apphost';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import imageLoader from 'imageLoader';
|
||||
import browser from 'browser';
|
||||
import layoutManager from 'layoutManager';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-checkbox';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-button';
|
||||
import 'formDialogStyle';
|
||||
import 'cardStyle';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
/* eslint-disable indent */
|
||||
|
||||
var currentItemId;
|
||||
var currentItemType;
|
||||
var currentResolve;
|
||||
var currentReject;
|
||||
var hasChanges = false;
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItemId;
|
||||
let currentItemType;
|
||||
let currentResolve;
|
||||
let currentReject;
|
||||
let hasChanges = false;
|
||||
|
||||
// These images can be large and we're seeing memory problems in safari
|
||||
var browsableImagePageSize = browser.slow ? 6 : 30;
|
||||
const browsableImagePageSize = browser.slow ? 6 : 30;
|
||||
|
||||
var browsableImageStartIndex = 0;
|
||||
var browsableImageType = 'Primary';
|
||||
var selectedProvider;
|
||||
let browsableImageStartIndex = 0;
|
||||
let browsableImageType = 'Primary';
|
||||
let selectedProvider;
|
||||
|
||||
function getBaseRemoteOptions() {
|
||||
|
||||
var options = {};
|
||||
const options = {};
|
||||
|
||||
options.itemId = currentItemId;
|
||||
|
||||
@@ -26,58 +39,53 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
function reloadBrowsableImages(page, apiClient) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var options = getBaseRemoteOptions();
|
||||
const options = getBaseRemoteOptions();
|
||||
|
||||
options.type = browsableImageType;
|
||||
options.startIndex = browsableImageStartIndex;
|
||||
options.limit = browsableImagePageSize;
|
||||
options.IncludeAllLanguages = page.querySelector('#chkAllLanguages').checked;
|
||||
|
||||
var provider = selectedProvider || '';
|
||||
const provider = selectedProvider || '';
|
||||
|
||||
if (provider) {
|
||||
options.ProviderName = provider;
|
||||
}
|
||||
|
||||
apiClient.getAvailableRemoteImages(options).then(function (result) {
|
||||
|
||||
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit);
|
||||
|
||||
page.querySelector('#selectBrowsableImageType').value = browsableImageType;
|
||||
|
||||
var providersHtml = result.Providers.map(function (p) {
|
||||
const providersHtml = result.Providers.map(function (p) {
|
||||
return '<option value="' + p + '">' + p + '</option>';
|
||||
});
|
||||
|
||||
var selectImageProvider = page.querySelector('#selectImageProvider');
|
||||
const selectImageProvider = page.querySelector('#selectImageProvider');
|
||||
selectImageProvider.innerHTML = '<option value="">' + globalize.translate('All') + '</option>' + providersHtml;
|
||||
selectImageProvider.value = provider;
|
||||
|
||||
loading.hide();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function renderRemoteImages(page, apiClient, imagesResult, imageType, startIndex, limit) {
|
||||
|
||||
page.querySelector('.availableImagesPaging').innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
|
||||
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = imagesResult.Images.length; i < length; i++) {
|
||||
let html = '';
|
||||
|
||||
for (let i = 0, length = imagesResult.Images.length; i < length; i++) {
|
||||
html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
|
||||
}
|
||||
|
||||
var availableImagesList = page.querySelector('.availableImagesList');
|
||||
const availableImagesList = page.querySelector('.availableImagesList');
|
||||
availableImagesList.innerHTML = html;
|
||||
imageLoader.lazyChildren(availableImagesList);
|
||||
|
||||
var btnNextPage = page.querySelector('.btnNextPage');
|
||||
var btnPreviousPage = page.querySelector('.btnPreviousPage');
|
||||
const btnNextPage = page.querySelector('.btnNextPage');
|
||||
const btnPreviousPage = page.querySelector('.btnPreviousPage');
|
||||
|
||||
if (btnNextPage) {
|
||||
btnNextPage.addEventListener('click', function () {
|
||||
@@ -92,23 +100,21 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getPagingHtml(startIndex, limit, totalRecordCount) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
|
||||
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
const recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||
|
||||
// 20 is the minimum page size
|
||||
var showControls = totalRecordCount > limit;
|
||||
const showControls = totalRecordCount > limit;
|
||||
|
||||
html += '<div class="listPaging">';
|
||||
|
||||
html += '<span style="margin-right: 10px;">';
|
||||
|
||||
var startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
|
||||
const startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
|
||||
html += globalize.translate('ListPaging', startAtDisplay, recordsEnd, totalRecordCount);
|
||||
|
||||
html += '</span>';
|
||||
@@ -127,7 +133,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
function downloadRemoteImage(page, apiClient, url, type, provider) {
|
||||
var options = getBaseRemoteOptions();
|
||||
const options = getBaseRemoteOptions();
|
||||
|
||||
options.Type = type;
|
||||
options.ImageUrl = url;
|
||||
@@ -136,9 +142,8 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
loading.show();
|
||||
|
||||
apiClient.downloadRemoteImage(options).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
var dlg = dom.parentWithClass(page, 'dialog');
|
||||
const dlg = dom.parentWithClass(page, 'dialog');
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
@@ -148,17 +153,17 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
function getRemoteImageHtml(image, imageType, apiClient) {
|
||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
||||
var enableFooterButtons = !layoutManager.tv;
|
||||
const tagName = layoutManager.tv ? 'button' : 'div';
|
||||
const enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
var cssClass = 'card scalableCard imageEditorCard';
|
||||
var cardBoxCssClass = 'cardBox visualCardBox';
|
||||
let cssClass = 'card scalableCard imageEditorCard';
|
||||
const cardBoxCssClass = 'cardBox visualCardBox';
|
||||
|
||||
var shape = 'backdrop';
|
||||
let shape;
|
||||
if (imageType === 'Backdrop' || imageType === 'Art' || imageType === 'Thumb' || imageType === 'Logo') {
|
||||
shape = 'backdrop';
|
||||
} else if (imageType === 'Banner') {
|
||||
@@ -166,7 +171,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
} else if (imageType === 'Disc') {
|
||||
shape = 'square';
|
||||
} else {
|
||||
|
||||
if (currentItemType === 'Episode') {
|
||||
shape = 'backdrop';
|
||||
} else if (currentItemType === 'MusicAlbum' || currentItemType === 'MusicArtist') {
|
||||
@@ -217,19 +221,16 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
html += '<div class="cardText cardTextCentered">' + image.ProviderName + '</div>';
|
||||
|
||||
if (image.Width || image.Height || image.Language) {
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
|
||||
if (image.Width && image.Height) {
|
||||
html += image.Width + ' x ' + image.Height;
|
||||
|
||||
if (image.Language) {
|
||||
|
||||
html += ' • ' + image.Language;
|
||||
}
|
||||
} else {
|
||||
if (image.Language) {
|
||||
|
||||
html += image.Language;
|
||||
}
|
||||
}
|
||||
@@ -238,13 +239,11 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
if (image.CommunityRating != null) {
|
||||
|
||||
html += '<div class="cardText cardText-secondary cardTextCentered">';
|
||||
|
||||
if (image.RatingType === 'Likes') {
|
||||
html += image.CommunityRating + (image.CommunityRating === 1 ? ' like' : ' likes');
|
||||
} else {
|
||||
|
||||
if (image.CommunityRating) {
|
||||
html += image.CommunityRating.toFixed(1);
|
||||
|
||||
@@ -270,7 +269,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
// end footer
|
||||
|
||||
html += '</div>';
|
||||
//html += '</div>';
|
||||
|
||||
html += '</' + tagName + '>';
|
||||
|
||||
@@ -287,7 +285,6 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
});
|
||||
|
||||
page.querySelector('#selectImageProvider').addEventListener('change', function () {
|
||||
|
||||
browsableImageStartIndex = 0;
|
||||
selectedProvider = this.value;
|
||||
|
||||
@@ -295,22 +292,20 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
});
|
||||
|
||||
page.querySelector('#chkAllLanguages').addEventListener('change', function () {
|
||||
|
||||
browsableImageStartIndex = 0;
|
||||
|
||||
reloadBrowsableImages(page, apiClient);
|
||||
});
|
||||
|
||||
page.addEventListener('click', function (e) {
|
||||
|
||||
var btnDownloadRemoteImage = dom.parentWithClass(e.target, 'btnDownloadRemoteImage');
|
||||
const btnDownloadRemoteImage = dom.parentWithClass(e.target, 'btnDownloadRemoteImage');
|
||||
if (btnDownloadRemoteImage) {
|
||||
var card = dom.parentWithClass(btnDownloadRemoteImage, 'card');
|
||||
const card = dom.parentWithClass(btnDownloadRemoteImage, 'card');
|
||||
downloadRemoteImage(page, apiClient, card.getAttribute('data-imageurl'), card.getAttribute('data-imagetype'), card.getAttribute('data-imageprovider'));
|
||||
return;
|
||||
}
|
||||
|
||||
var btnImageCard = dom.parentWithClass(e.target, 'btnImageCard');
|
||||
const btnImageCard = dom.parentWithClass(e.target, 'btnImageCard');
|
||||
if (btnImageCard) {
|
||||
downloadRemoteImage(page, apiClient, btnImageCard.getAttribute('data-imageurl'), btnImageCard.getAttribute('data-imagetype'), btnImageCard.getAttribute('data-imageprovider'));
|
||||
}
|
||||
@@ -320,14 +315,13 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
function showEditor(itemId, serverId, itemType) {
|
||||
loading.show();
|
||||
|
||||
require(['text!./imageDownloader.template.html'], function (template) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
import('text!./imageDownloader.template.html').then(({default: template}) => {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
currentItemId = itemId;
|
||||
currentItemType = itemType;
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true
|
||||
};
|
||||
|
||||
@@ -337,9 +331,9 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.innerHTML = globalize.translateDocument(template, 'core');
|
||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg, false);
|
||||
@@ -350,11 +344,10 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
var editorContent = dlg.querySelector('.formDialogContent');
|
||||
const editorContent = dlg.querySelector('.formDialogContent');
|
||||
initEditor(editorContent, apiClient);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
@@ -363,7 +356,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
var dlg = this;
|
||||
const dlg = this;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
@@ -377,18 +370,20 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (itemId, serverId, itemType, imageType) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
hasChanges = false;
|
||||
browsableImageStartIndex = 0;
|
||||
browsableImageType = imageType || 'Primary';
|
||||
selectedProvider = null;
|
||||
export function show(itemId, serverId, itemType, imageType) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
hasChanges = false;
|
||||
browsableImageStartIndex = 0;
|
||||
browsableImageType = imageType || 'Primary';
|
||||
selectedProvider = null;
|
||||
showEditor(itemId, serverId, itemType);
|
||||
});
|
||||
}
|
||||
|
||||
showEditor(itemId, serverId, itemType);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
define(['globalize', 'dom', 'dialogHelper', 'emby-checkbox', 'emby-select', 'emby-input'], function (globalize, dom, dialogHelper) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for image Options Editor.
|
||||
* @module components/imageOptionsEditor/imageOptionsEditor
|
||||
*/
|
||||
|
||||
import globalize from 'globalize';
|
||||
import dom from 'dom';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-select';
|
||||
import 'emby-input';
|
||||
|
||||
function getDefaultImageConfig(itemType, type) {
|
||||
return {
|
||||
Type: type,
|
||||
MinWidth: 0,
|
||||
Limit: 'Primary' === type ? 1 : 0
|
||||
Limit: type === 'Primary' ? 1 : 0
|
||||
};
|
||||
}
|
||||
|
||||
function findImageOptions(imageOptions, type) {
|
||||
return imageOptions.filter(function (i) {
|
||||
return imageOptions.filter(i => {
|
||||
return i.Type == type;
|
||||
})[0];
|
||||
}
|
||||
@@ -31,14 +42,14 @@ define(['globalize', 'dom', 'dialogHelper', 'emby-checkbox', 'emby-select', 'emb
|
||||
}
|
||||
|
||||
function loadValues(context, itemType, options, availableOptions) {
|
||||
var supportedImageTypes = availableOptions.SupportedImageTypes || [];
|
||||
setVisibilityOfBackdrops(context.querySelector('.backdropFields'), -1 != supportedImageTypes.indexOf('Backdrop'));
|
||||
setVisibilityOfBackdrops(context.querySelector('.screenshotFields'), -1 != supportedImageTypes.indexOf('Screenshot'));
|
||||
Array.prototype.forEach.call(context.querySelectorAll('.imageType'), function (i) {
|
||||
var imageType = i.getAttribute('data-imagetype');
|
||||
var container = dom.parentWithTag(i, 'LABEL');
|
||||
const supportedImageTypes = availableOptions.SupportedImageTypes || [];
|
||||
setVisibilityOfBackdrops(context.querySelector('.backdropFields'), supportedImageTypes.includes('Backdrop'));
|
||||
setVisibilityOfBackdrops(context.querySelector('.screenshotFields'), supportedImageTypes.includes('Screenshot'));
|
||||
Array.prototype.forEach.call(context.querySelectorAll('.imageType'), i => {
|
||||
const imageType = i.getAttribute('data-imagetype');
|
||||
const container = dom.parentWithTag(i, 'LABEL');
|
||||
|
||||
if (-1 == supportedImageTypes.indexOf(imageType)) {
|
||||
if (!supportedImageTypes.includes(imageType)) {
|
||||
container.classList.add('hide');
|
||||
} else {
|
||||
container.classList.remove('hide');
|
||||
@@ -50,16 +61,16 @@ define(['globalize', 'dom', 'dialogHelper', 'emby-checkbox', 'emby-select', 'emb
|
||||
i.checked = false;
|
||||
}
|
||||
});
|
||||
var backdropConfig = getImageConfig(options, availableOptions, 'Backdrop', itemType);
|
||||
const backdropConfig = getImageConfig(options, availableOptions, 'Backdrop', itemType);
|
||||
context.querySelector('#txtMaxBackdrops').value = backdropConfig.Limit;
|
||||
context.querySelector('#txtMinBackdropDownloadWidth').value = backdropConfig.MinWidth;
|
||||
var screenshotConfig = getImageConfig(options, availableOptions, 'Screenshot', itemType);
|
||||
const screenshotConfig = getImageConfig(options, availableOptions, 'Screenshot', itemType);
|
||||
context.querySelector('#txtMaxScreenshots').value = screenshotConfig.Limit;
|
||||
context.querySelector('#txtMinScreenshotDownloadWidth').value = screenshotConfig.MinWidth;
|
||||
}
|
||||
|
||||
function saveValues(context, options) {
|
||||
options.ImageOptions = Array.prototype.map.call(context.querySelectorAll('.imageType:not(.hide)'), function (c) {
|
||||
options.ImageOptions = Array.prototype.map.call(context.querySelectorAll('.imageType:not(.hide)'), c => {
|
||||
return {
|
||||
Type: c.getAttribute('data-imagetype'),
|
||||
Limit: c.checked ? 1 : 0,
|
||||
@@ -78,35 +89,36 @@ define(['globalize', 'dom', 'dialogHelper', 'emby-checkbox', 'emby-select', 'emb
|
||||
});
|
||||
}
|
||||
|
||||
function editor() {
|
||||
this.show = function (itemType, options, availableOptions) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'components/imageOptionsEditor/imageOptionsEditor.template.html', true);
|
||||
async function showEditor(itemType, options, availableOptions) {
|
||||
const response = await fetch('components/imageOptionsEditor/imageOptionsEditor.template.html');
|
||||
const template = await response.text();
|
||||
|
||||
xhr.onload = function (e) {
|
||||
var template = this.response;
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.innerHTML = globalize.translateDocument(template);
|
||||
dlg.addEventListener('close', function () {
|
||||
saveValues(dlg, options);
|
||||
});
|
||||
loadValues(dlg, itemType, options, availableOptions);
|
||||
dialogHelper.open(dlg).then(resolve, resolve);
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
};
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.innerHTML = globalize.translateHtml(template);
|
||||
dlg.addEventListener('close', function () {
|
||||
saveValues(dlg, options);
|
||||
});
|
||||
loadValues(dlg, itemType, options, availableOptions);
|
||||
dialogHelper.open(dlg).then(() => {
|
||||
return;
|
||||
}).catch(() => {
|
||||
return;
|
||||
});
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
||||
return editor;
|
||||
});
|
||||
export class editor {
|
||||
constructor() {
|
||||
this.show = showEditor;
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default editor;
|
||||
|
||||
@@ -15,41 +15,41 @@
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Primary" />
|
||||
<span>${OptionDownloadPrimaryImage}</span>
|
||||
<span>${Primary}</span>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Art" />
|
||||
<span>${OptionDownloadArtImage}</span>
|
||||
<span>${Art}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="BoxRear" />
|
||||
<span>${OptionDownloadBackImage}</span>
|
||||
<span>${Back}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Banner" />
|
||||
<span>${OptionDownloadBannerImage}</span>
|
||||
<span>${Banner}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Box" />
|
||||
<span>${OptionDownloadBoxImage}</span>
|
||||
<span>${Box}</span>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Disc" />
|
||||
<span>${OptionDownloadDiscImage}</span>
|
||||
<span>${Disc}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Logo" />
|
||||
<span>${OptionDownloadLogoImage}</span>
|
||||
<span>${Logo}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Menu" />
|
||||
<span>${OptionDownloadMenuImage}</span>
|
||||
<span>${Menu}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="imageType" data-imagetype="Thumb" />
|
||||
<span>${OptionDownloadThumbImage}</span>
|
||||
<span>${Thumb}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', 'layoutManager', 'globalize', 'require', 'emby-button', 'emby-select', 'formDialogStyle', 'css!./style'], function (dialogHelper, connectionManager, dom, loading, scrollHelper, layoutManager, globalize, require) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
var currentItemId;
|
||||
var currentServerId;
|
||||
var currentFile;
|
||||
var hasChanges = false;
|
||||
/**
|
||||
* Module for imageUploader.
|
||||
* @module components/imageUploader/imageUploader
|
||||
*/
|
||||
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import dom from 'dom';
|
||||
import loading from 'loading';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-button';
|
||||
import 'emby-select';
|
||||
import 'formDialogStyle';
|
||||
import 'css!./style';
|
||||
|
||||
let currentItemId;
|
||||
let currentServerId;
|
||||
let currentFile;
|
||||
let hasChanges = false;
|
||||
|
||||
function onFileReaderError(evt) {
|
||||
|
||||
loading.hide();
|
||||
|
||||
switch (evt.target.error.code) {
|
||||
case evt.target.error.NOT_FOUND_ERR:
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('MessageFileReadError'));
|
||||
});
|
||||
break;
|
||||
case evt.target.error.ABORT_ERR:
|
||||
break; // noop
|
||||
default:
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('MessageFileReadError'));
|
||||
});
|
||||
break;
|
||||
@@ -27,8 +41,7 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
|
||||
}
|
||||
|
||||
function setFiles(page, files) {
|
||||
|
||||
var file = files[0];
|
||||
const file = files[0];
|
||||
|
||||
if (!file || !file.type.match('image.*')) {
|
||||
page.querySelector('#imageOutput').innerHTML = '';
|
||||
@@ -39,25 +52,25 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
|
||||
|
||||
currentFile = file;
|
||||
|
||||
var reader = new FileReader();
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onerror = onFileReaderError;
|
||||
reader.onloadstart = function () {
|
||||
reader.onloadstart = () => {
|
||||
page.querySelector('#fldUpload').classList.add('hide');
|
||||
};
|
||||
reader.onabort = function () {
|
||||
reader.onabort = () => {
|
||||
loading.hide();
|
||||
console.debug('File read cancelled');
|
||||
};
|
||||
|
||||
// Closure to capture the file information.
|
||||
reader.onload = (function (theFile) {
|
||||
return function (e) {
|
||||
|
||||
reader.onload = (theFile => {
|
||||
return e => {
|
||||
// Render thumbnail.
|
||||
var html = ['<img style="max-width:100%;max-height:100%;" src="', e.target.result, '" title="', escape(theFile.name), '"/>'].join('');
|
||||
const 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('#dropImageText').classList.add('hide');
|
||||
page.querySelector('#fldUpload').classList.remove('hide');
|
||||
};
|
||||
})(file);
|
||||
@@ -67,15 +80,14 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
var file = currentFile;
|
||||
const file = currentFile;
|
||||
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file.type.startsWith('image/')) {
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('MessageImageFileTypeAllowed'));
|
||||
});
|
||||
e.preventDefault();
|
||||
@@ -84,19 +96,18 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
|
||||
|
||||
loading.show();
|
||||
|
||||
var dlg = dom.parentWithClass(this, 'dialog');
|
||||
const dlg = dom.parentWithClass(this, 'dialog');
|
||||
|
||||
var imageType = dlg.querySelector('#selectImageType').value;
|
||||
const imageType = dlg.querySelector('#selectImageType').value;
|
||||
if (imageType === 'None') {
|
||||
require(['toast'], function(toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('MessageImageTypeNotSelected'));
|
||||
});
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(function () {
|
||||
|
||||
window.connectionManager.getApiClient(currentServerId).uploadItemImage(currentItemId, imageType, file).then(() => {
|
||||
dlg.querySelector('#uploadImage').value = '';
|
||||
|
||||
loading.hide();
|
||||
@@ -109,28 +120,25 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
|
||||
}
|
||||
|
||||
function initEditor(page) {
|
||||
|
||||
page.querySelector('form').addEventListener('submit', onSubmit);
|
||||
|
||||
page.querySelector('#uploadImage').addEventListener('change', function () {
|
||||
setFiles(page, this.files);
|
||||
});
|
||||
|
||||
page.querySelector('.btnBrowse').addEventListener('click', function () {
|
||||
page.querySelector('.btnBrowse').addEventListener('click', () => {
|
||||
page.querySelector('#uploadImage').click();
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(options, resolve, reject) {
|
||||
|
||||
function showEditor(options, resolve) {
|
||||
options = options || {};
|
||||
|
||||
require(['text!./imageUploader.template.html'], function (template) {
|
||||
|
||||
return import('text!./imageUploader.template.html').then(({default: template}) => {
|
||||
currentItemId = options.itemId;
|
||||
currentServerId = options.serverId;
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true
|
||||
};
|
||||
|
||||
@@ -140,19 +148,18 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
dlg.innerHTML = globalize.translateDocument(template, 'core');
|
||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg, false);
|
||||
}
|
||||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
dlg.addEventListener('close', () => {
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
@@ -167,22 +174,21 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
|
||||
|
||||
dlg.querySelector('#selectImageType').value = options.imageType || 'Primary';
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (options) {
|
||||
export function show(options) {
|
||||
return new Promise(resolve => {
|
||||
hasChanges = false;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
showEditor(options, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
showEditor(options, resolve, reject);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', 'focusManager', 'globalize', 'scrollHelper', 'imageLoader', 'require', 'browser', 'apphost', 'cardStyle', 'formDialogStyle', 'emby-button', 'paper-icon-button-light', 'css!./imageeditor'], function (dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
import focusManager from 'focusManager';
|
||||
import globalize from 'globalize';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import imageLoader from 'imageLoader';
|
||||
import browser from 'browser';
|
||||
import appHost from 'apphost';
|
||||
import 'cardStyle';
|
||||
import 'formDialogStyle';
|
||||
import 'emby-button';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./imageeditor';
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
/* eslint-disable indent */
|
||||
|
||||
var currentItem;
|
||||
var hasChanges = false;
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItem;
|
||||
let hasChanges = false;
|
||||
|
||||
function getBaseRemoteOptions() {
|
||||
|
||||
var options = {};
|
||||
const options = {};
|
||||
|
||||
options.itemId = currentItem.Id;
|
||||
|
||||
@@ -16,17 +30,15 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function reload(page, item, focusContext) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var apiClient;
|
||||
let apiClient;
|
||||
|
||||
if (item) {
|
||||
apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
reloadItem(page, item, apiClient, focusContext);
|
||||
} else {
|
||||
|
||||
apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function (item) {
|
||||
reloadItem(page, item, apiClient, focusContext);
|
||||
});
|
||||
@@ -34,9 +46,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function addListeners(container, className, eventName, fn) {
|
||||
|
||||
container.addEventListener(eventName, function (e) {
|
||||
var elem = dom.parentWithClass(e.target, className);
|
||||
const elem = dom.parentWithClass(e.target, className);
|
||||
if (elem) {
|
||||
fn.call(elem, e);
|
||||
}
|
||||
@@ -44,14 +55,11 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function reloadItem(page, item, apiClient, focusContext) {
|
||||
|
||||
currentItem = item;
|
||||
|
||||
apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) {
|
||||
|
||||
var btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages');
|
||||
for (var i = 0, length = btnBrowseAllImages.length; i < length; i++) {
|
||||
|
||||
if (providers.length) {
|
||||
btnBrowseAllImages[i].classList.remove('hide');
|
||||
} else {
|
||||
@@ -60,7 +68,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
apiClient.getItemImageInfos(currentItem.Id).then(function (imageInfos) {
|
||||
|
||||
renderStandardImages(page, apiClient, item, imageInfos, providers);
|
||||
renderBackdrops(page, apiClient, item, imageInfos, providers);
|
||||
renderScreenshots(page, apiClient, item, imageInfos, providers);
|
||||
@@ -74,7 +81,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function getImageUrl(item, apiClient, type, index, options) {
|
||||
|
||||
options = options || {};
|
||||
options.type = type;
|
||||
options.index = index;
|
||||
@@ -94,13 +100,12 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
var cssClass = 'card scalableCard imageEditorCard';
|
||||
var cardBoxCssClass = 'cardBox visualCardBox';
|
||||
let cssClass = 'card scalableCard imageEditorCard';
|
||||
const cardBoxCssClass = 'cardBox visualCardBox';
|
||||
|
||||
cssClass += ' backdropCard backdropCard-scalable';
|
||||
|
||||
@@ -130,7 +135,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
|
||||
html += '<div class="cardContent">';
|
||||
|
||||
var imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
|
||||
const imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
|
||||
|
||||
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center center;background-size:contain;"></div>';
|
||||
|
||||
@@ -153,7 +158,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
html += '<div class="cardText cardTextCentered">';
|
||||
|
||||
if (image.ImageType === 'Backdrop' || image.ImageType === 'Screenshot') {
|
||||
|
||||
if (index > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate('MoveLeft') + '"><span class="material-icons chevron_left"></span></button>';
|
||||
} else {
|
||||
@@ -183,13 +187,10 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function deleteImage(context, itemId, type, index, apiClient, enableConfirmation) {
|
||||
|
||||
var afterConfirm = function () {
|
||||
const afterConfirm = function () {
|
||||
apiClient.deleteItemImage(itemId, type, index).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(context);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
@@ -198,8 +199,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
return;
|
||||
}
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
import('confirm').then(({default: confirm}) => {
|
||||
confirm({
|
||||
|
||||
text: globalize.translate('ConfirmDeleteImage'),
|
||||
@@ -211,36 +211,30 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) {
|
||||
|
||||
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(context, null, focusContext);
|
||||
}, function () {
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
alert(globalize.translate('DefaultErrorMessage'));
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(globalize.translate('ErrorDefault'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderImages(page, item, apiClient, images, imageProviders, elem) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
|
||||
var imageSize = 300;
|
||||
var windowSize = dom.getWindowSize();
|
||||
let imageSize = 300;
|
||||
const windowSize = dom.getWindowSize();
|
||||
if (windowSize.innerWidth >= 1280) {
|
||||
imageSize = Math.round(windowSize.innerWidth / 4);
|
||||
}
|
||||
|
||||
var tagName = layoutManager.tv ? 'button' : 'div';
|
||||
var enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
for (var i = 0, length = images.length; i < length; i++) {
|
||||
|
||||
var image = images[i];
|
||||
const tagName = layoutManager.tv ? 'button' : 'div';
|
||||
const enableFooterButtons = !layoutManager.tv;
|
||||
|
||||
for (let i = 0, length = images.length; i < length; i++) {
|
||||
const image = images[i];
|
||||
html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons);
|
||||
}
|
||||
|
||||
@@ -249,8 +243,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function renderStandardImages(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType !== 'Screenshot' && i.ImageType !== 'Backdrop' && i.ImageType !== 'Chapter';
|
||||
});
|
||||
|
||||
@@ -258,10 +251,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function renderBackdrops(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType === 'Backdrop';
|
||||
|
||||
}).sort(function (a, b) {
|
||||
return a.ImageIndex - b.ImageIndex;
|
||||
});
|
||||
@@ -275,10 +266,8 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function renderScreenshots(page, apiClient, item, imageInfos, imageProviders) {
|
||||
|
||||
var images = imageInfos.filter(function (i) {
|
||||
const images = imageInfos.filter(function (i) {
|
||||
return i.ImageType === 'Screenshot';
|
||||
|
||||
}).sort(function (a, b) {
|
||||
return a.ImageIndex - b.ImageIndex;
|
||||
});
|
||||
@@ -292,32 +281,26 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
function showImageDownloader(page, imageType) {
|
||||
|
||||
require(['imageDownloader'], function (ImageDownloader) {
|
||||
|
||||
import('imageDownloader').then(({default: ImageDownloader}) => {
|
||||
ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function () {
|
||||
|
||||
hasChanges = true;
|
||||
reload(page);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function showActionSheet(context, imageCard) {
|
||||
const itemId = imageCard.getAttribute('data-id');
|
||||
const serverId = imageCard.getAttribute('data-serverid');
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
var itemId = imageCard.getAttribute('data-id');
|
||||
var serverId = imageCard.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const type = imageCard.getAttribute('data-imagetype');
|
||||
const index = parseInt(imageCard.getAttribute('data-index'));
|
||||
const providerCount = parseInt(imageCard.getAttribute('data-providers'));
|
||||
const numImages = parseInt(imageCard.getAttribute('data-numimages'));
|
||||
|
||||
var type = imageCard.getAttribute('data-imagetype');
|
||||
var index = parseInt(imageCard.getAttribute('data-index'));
|
||||
var providerCount = parseInt(imageCard.getAttribute('data-providers'));
|
||||
var numImages = parseInt(imageCard.getAttribute('data-numimages'));
|
||||
|
||||
require(['actionsheet'], function (actionSheet) {
|
||||
|
||||
var commands = [];
|
||||
import('actionsheet').then(({default: actionSheet}) => {
|
||||
const commands = [];
|
||||
|
||||
commands.push({
|
||||
name: globalize.translate('Delete'),
|
||||
@@ -353,9 +336,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
positionTo: imageCard
|
||||
|
||||
}).then(function (id) {
|
||||
|
||||
switch (id) {
|
||||
|
||||
case 'delete':
|
||||
deleteImage(context, itemId, type, index, apiClient, false);
|
||||
break;
|
||||
@@ -371,16 +352,14 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initEditor(context, options) {
|
||||
|
||||
var uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
|
||||
var isFileInputSupported = appHost.supports('fileinput');
|
||||
for (var i = 0, length = uploadButtons.length; i < length; i++) {
|
||||
const uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
|
||||
const isFileInputSupported = appHost.supports('fileinput');
|
||||
for (let i = 0, length = uploadButtons.length; i < length; i++) {
|
||||
if (isFileInputSupported) {
|
||||
uploadButtons[i].classList.remove('hide');
|
||||
} else {
|
||||
@@ -389,10 +368,9 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
}
|
||||
|
||||
addListeners(context, 'btnOpenUploadMenu', 'click', function () {
|
||||
var imageType = this.getAttribute('data-imagetype');
|
||||
|
||||
require(['imageUploader'], function (imageUploader) {
|
||||
const imageType = this.getAttribute('data-imagetype');
|
||||
|
||||
import('imageUploader').then(({default: imageUploader}) => {
|
||||
imageUploader.show({
|
||||
|
||||
theme: options.theme,
|
||||
@@ -401,7 +379,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
serverId: currentItem.ServerId
|
||||
|
||||
}).then(function (hasChanged) {
|
||||
|
||||
if (hasChanged) {
|
||||
hasChanges = true;
|
||||
reload(context);
|
||||
@@ -423,34 +400,32 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
});
|
||||
|
||||
addListeners(context, 'btnDeleteImage', 'click', function () {
|
||||
var type = this.getAttribute('data-imagetype');
|
||||
var index = this.getAttribute('data-index');
|
||||
const type = this.getAttribute('data-imagetype');
|
||||
let index = this.getAttribute('data-index');
|
||||
index = index === 'null' ? null : parseInt(index);
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
deleteImage(context, currentItem.Id, type, index, apiClient, true);
|
||||
});
|
||||
|
||||
addListeners(context, 'btnMoveImage', 'click', function () {
|
||||
var type = this.getAttribute('data-imagetype');
|
||||
var index = this.getAttribute('data-index');
|
||||
var newIndex = this.getAttribute('data-newindex');
|
||||
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
|
||||
const type = this.getAttribute('data-imagetype');
|
||||
const index = this.getAttribute('data-index');
|
||||
const newIndex = this.getAttribute('data-newindex');
|
||||
const apiClient = window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, 'itemsContainer'));
|
||||
});
|
||||
}
|
||||
|
||||
function showEditor(options, resolve, reject) {
|
||||
|
||||
var itemId = options.itemId;
|
||||
var serverId = options.serverId;
|
||||
const itemId = options.itemId;
|
||||
const serverId = options.serverId;
|
||||
|
||||
loading.show();
|
||||
|
||||
require(['text!./imageeditor.template.html'], function (template) {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
import('text!./imageeditor.template.html').then(({default: template}) => {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true
|
||||
};
|
||||
|
||||
@@ -460,11 +435,11 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
dlg.innerHTML = globalize.translateDocument(template, 'core');
|
||||
dlg.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.on(dlg, false);
|
||||
@@ -474,7 +449,6 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
|
||||
// Has to be assigned a z-index after the call to .open()
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
scrollHelper.centerFocus.off(dlg, false);
|
||||
}
|
||||
@@ -493,22 +467,21 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
||||
reload(dlg, item);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (options) {
|
||||
export function show (options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
hasChanges = false;
|
||||
showEditor(options, resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
export default {
|
||||
show
|
||||
};
|
||||
|
||||
hasChanges = false;
|
||||
|
||||
showEditor(options, resolve, reject);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as lazyLoader from 'lazyLoader';
|
||||
import * as userSettings from 'userSettings';
|
||||
import * as blurhash from 'blurhash';
|
||||
import 'css!./style';
|
||||
/* eslint-disable indent */
|
||||
|
||||
@@ -11,47 +12,96 @@ import 'css!./style';
|
||||
fillImageElement(elem, source);
|
||||
}
|
||||
|
||||
function itemBlurhashing(target, blurhashstr) {
|
||||
if (blurhash.isBlurhashValid(blurhashstr)) {
|
||||
// Although the default values recommended by Blurhash developers is 32x32, a size of 18x18 seems to be the sweet spot for us,
|
||||
// improving the performance and reducing the memory usage, while retaining almost full blur quality.
|
||||
// Lower values had more visible pixelation
|
||||
const width = 18;
|
||||
const height = 18;
|
||||
let pixels;
|
||||
try {
|
||||
pixels = blurhash.decode(blurhashstr, width, height);
|
||||
} catch (err) {
|
||||
console.error('Blurhash decode error: ', err);
|
||||
target.classList.add('non-blurhashable');
|
||||
return;
|
||||
}
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
const imgData = ctx.createImageData(width, height);
|
||||
|
||||
imgData.data.set(pixels);
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
canvas.classList.add('blurhash-canvas');
|
||||
if (userSettings.enableFastFadein()) {
|
||||
canvas.classList.add('lazy-blurhash-fadein-fast');
|
||||
} else {
|
||||
canvas.classList.add('lazy-blurhash-fadein');
|
||||
}
|
||||
|
||||
target.parentNode.insertBefore(canvas, target);
|
||||
target.classList.add('blurhashed');
|
||||
target.removeAttribute('data-blurhash');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function fillImage(entry) {
|
||||
if (!entry) {
|
||||
throw new Error('entry cannot be null');
|
||||
}
|
||||
|
||||
const target = entry.target;
|
||||
var source = undefined;
|
||||
if (entry.target) {
|
||||
source = entry.target.getAttribute('data-src');
|
||||
|
||||
if (target) {
|
||||
source = target.getAttribute('data-src');
|
||||
} else {
|
||||
source = entry;
|
||||
}
|
||||
|
||||
if (entry.intersectionRatio > 0) {
|
||||
if (source) fillImageElement(entry.target, source);
|
||||
if (source) fillImageElement(target, source);
|
||||
} else if (!source) {
|
||||
emptyImageElement(entry.target);
|
||||
requestAnimationFrame(() => {
|
||||
emptyImageElement(target);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function fillImageElement(elem, url) {
|
||||
if (url === undefined) {
|
||||
throw new Error('url cannot be undefined');
|
||||
throw new TypeError('url cannot be undefined');
|
||||
}
|
||||
|
||||
let preloaderImg = new Image();
|
||||
const preloaderImg = new Image();
|
||||
preloaderImg.src = url;
|
||||
|
||||
elem.classList.add('lazy-hidden');
|
||||
|
||||
preloaderImg.addEventListener('load', () => {
|
||||
if (elem.tagName !== 'IMG') {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
} else {
|
||||
elem.setAttribute('src', url);
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
if (elem.tagName !== 'IMG') {
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
if (elem.classList.contains('blurhashed')) {
|
||||
elem.style.backgroundColor = '#fff';
|
||||
}
|
||||
} else {
|
||||
elem.setAttribute('src', url);
|
||||
}
|
||||
elem.removeAttribute('data-src');
|
||||
|
||||
if (userSettings.enableFastFadein()) {
|
||||
elem.classList.add('lazy-image-fadein-fast');
|
||||
} else {
|
||||
elem.classList.add('lazy-image-fadein');
|
||||
}
|
||||
|
||||
elem.removeAttribute('data-src');
|
||||
elem.classList.remove('lazy-hidden');
|
||||
if (userSettings.enableFastFadein()) {
|
||||
elem.classList.add('lazy-image-fadein-fast');
|
||||
} else {
|
||||
elem.classList.add('lazy-image-fadein');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,27 +111,35 @@ import 'css!./style';
|
||||
if (elem.tagName !== 'IMG') {
|
||||
url = elem.style.backgroundImage.slice(4, -1).replace(/"/g, '');
|
||||
elem.style.backgroundImage = 'none';
|
||||
elem.style.backgroundColor = null;
|
||||
} else {
|
||||
url = elem.getAttribute('src');
|
||||
elem.setAttribute('src', '');
|
||||
}
|
||||
|
||||
elem.setAttribute('data-src', url);
|
||||
|
||||
elem.classList.remove('lazy-image-fadein-fast');
|
||||
elem.classList.remove('lazy-image-fadein');
|
||||
elem.classList.remove('lazy-image-fadein-fast', 'lazy-image-fadein');
|
||||
elem.classList.add('lazy-hidden');
|
||||
}
|
||||
|
||||
export function lazyChildren(elem) {
|
||||
if (userSettings.enableBlurhash()) {
|
||||
for (const lazyElem of elem.querySelectorAll('.lazy')) {
|
||||
const blurhashstr = lazyElem.getAttribute('data-blurhash');
|
||||
if (!lazyElem.classList.contains('blurhashed', 'non-blurhashable') && blurhashstr) {
|
||||
itemBlurhashing(lazyElem, blurhashstr);
|
||||
} else if (!blurhashstr && !lazyElem.classList.contains('blurhashed')) {
|
||||
lazyElem.classList.add('non-blurhashable');
|
||||
}
|
||||
}
|
||||
}
|
||||
lazyLoader.lazyChildren(elem, fillImage);
|
||||
}
|
||||
|
||||
export function getPrimaryImageAspectRatio(items) {
|
||||
|
||||
var values = [];
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var ratio = items[i].PrimaryImageAspectRatio || 0;
|
||||
|
||||
if (!ratio) {
|
||||
@@ -137,15 +195,21 @@ import 'css!./style';
|
||||
}
|
||||
|
||||
export function fillImages(elems) {
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
var elem = elems[0];
|
||||
fillImage(elem);
|
||||
}
|
||||
}
|
||||
|
||||
export function setLazyImage(element, url) {
|
||||
element.classList.add('lazy');
|
||||
element.setAttribute('data-src', url);
|
||||
lazyImage(element);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
setLazyImage: setLazyImage,
|
||||
fillImages: fillImages,
|
||||
fillImage: fillImage,
|
||||
lazyImage: lazyImage,
|
||||
|
||||
@@ -1,13 +1,42 @@
|
||||
.cardImageContainer.lazy {
|
||||
.lazy-image-fadein {
|
||||
opacity: 1;
|
||||
transition: opacity 0.5s;
|
||||
}
|
||||
|
||||
.lazy-image-fadein-fast {
|
||||
opacity: 1;
|
||||
transition: opacity 0.1s;
|
||||
}
|
||||
|
||||
.lazy-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cardImageContainer.lazy.lazy-image-fadein {
|
||||
opacity: 1;
|
||||
transition: opacity 0.7s;
|
||||
@keyframes fadein {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.cardImageContainer.lazy.lazy-image-fadein-fast {
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s;
|
||||
.lazy-blurhash-fadein-fast {
|
||||
animation: fadein 0.1s;
|
||||
}
|
||||
|
||||
.lazy-blurhash-fadein {
|
||||
animation: fadein 0.4s;
|
||||
}
|
||||
|
||||
.blurhash-canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ export function enablePlayedIndicator(item) {
|
||||
|
||||
export function getPlayedIndicatorHtml(item) {
|
||||
if (enablePlayedIndicator(item)) {
|
||||
let userData = item.UserData || {};
|
||||
const userData = item.UserData || {};
|
||||
if (userData.UnplayedItemCount) {
|
||||
return '<div class="countIndicator indicator">' + userData.UnplayedItemCount + '</div>';
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter', 'playbackManager', 'loading', 'appSettings', 'browser', 'actionsheet'], function (appHost, globalize, connectionManager, itemHelper, appRouter, playbackManager, loading, appSettings, browser, actionsheet) {
|
||||
'use strict';
|
||||
import appHost from 'apphost';
|
||||
import globalize from 'globalize';
|
||||
import itemHelper from 'itemHelper';
|
||||
import appRouter from 'appRouter';
|
||||
import playbackManager from 'playbackManager';
|
||||
import browser from 'browser';
|
||||
import actionsheet from 'actionsheet';
|
||||
|
||||
function getCommands(options) {
|
||||
var item = options.item;
|
||||
var user = options.user;
|
||||
/* eslint-disable indent */
|
||||
export function getCommands(options) {
|
||||
const item = options.item;
|
||||
const user = options.user;
|
||||
|
||||
var canPlay = playbackManager.canPlay(item);
|
||||
var restrictOptions = (browser.operaTv || browser.web0s) && !user.Policy.IsAdministrator;
|
||||
const canPlay = playbackManager.canPlay(item);
|
||||
const restrictOptions = (browser.operaTv || browser.web0s) && !user.Policy.IsAdministrator;
|
||||
|
||||
var commands = [];
|
||||
const commands = [];
|
||||
|
||||
if (canPlay && item.MediaType !== 'Photo') {
|
||||
if (options.play !== false) {
|
||||
@@ -28,6 +34,23 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
}
|
||||
|
||||
if (playbackManager.getCurrentPlayer() !== null) {
|
||||
if (options.stopPlayback) {
|
||||
commands.push({
|
||||
name: globalize.translate('StopPlayback'),
|
||||
id: 'stopPlayback',
|
||||
icon: 'stop'
|
||||
});
|
||||
}
|
||||
if (options.clearQueue) {
|
||||
commands.push({
|
||||
name: globalize.translate('ClearQueue'),
|
||||
id: 'clearQueue',
|
||||
icon: 'clear_all'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (playbackManager.canQueue(item)) {
|
||||
if (options.queue !== false) {
|
||||
commands.push({
|
||||
@@ -44,13 +67,6 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
icon: 'playlist_add'
|
||||
});
|
||||
}
|
||||
|
||||
//if (options.queueAllFromHere) {
|
||||
// commands.push({
|
||||
// name: globalize.translate("QueueAllFromHere"),
|
||||
// id: "queueallfromhere"
|
||||
// });
|
||||
//}
|
||||
}
|
||||
|
||||
if (item.IsFolder || item.Type === 'MusicArtist' || item.Type === 'MusicGenre') {
|
||||
@@ -124,7 +140,6 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
if (item.CanDelete && options.deleteItem !== false) {
|
||||
|
||||
if (item.Type === 'Playlist' || item.Type === 'BoxSet') {
|
||||
commands.push({
|
||||
name: globalize.translate('Delete'),
|
||||
@@ -161,10 +176,10 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
});
|
||||
}
|
||||
|
||||
var canEdit = itemHelper.canEdit(user, item);
|
||||
const canEdit = itemHelper.canEdit(user, item);
|
||||
if (canEdit) {
|
||||
if (options.edit !== false && item.Type !== 'SeriesTimer') {
|
||||
var text = (item.Type === 'Timer' || item.Type === 'SeriesTimer') ? globalize.translate('Edit') : globalize.translate('EditMetadata');
|
||||
const text = (item.Type === 'Timer' || item.Type === 'SeriesTimer') ? globalize.translate('Edit') : globalize.translate('EditMetadata');
|
||||
commands.push({
|
||||
name: text,
|
||||
id: 'edit',
|
||||
@@ -288,10 +303,11 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
icon: 'album'
|
||||
});
|
||||
}
|
||||
|
||||
if (options.openArtist !== false && item.ArtistItems && item.ArtistItems.length) {
|
||||
// Show Album Artist by default, as a song can have multiple artists, which specific one would this option refer to?
|
||||
// Although some albums can have multiple artists, it's not as common as songs.
|
||||
if (options.openArtist !== false && item.AlbumArtists && item.AlbumArtists.length) {
|
||||
commands.push({
|
||||
name: globalize.translate('ViewArtist'),
|
||||
name: globalize.translate('ViewAlbumArtist'),
|
||||
id: 'artist',
|
||||
icon: 'person'
|
||||
});
|
||||
@@ -311,31 +327,31 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function executeCommand(item, id, options) {
|
||||
var itemId = item.Id;
|
||||
var serverId = item.ServerId;
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const itemId = item.Id;
|
||||
const serverId = item.ServerId;
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
switch (id) {
|
||||
case 'addtocollection':
|
||||
require(['collectionEditor'], function (collectionEditor) {
|
||||
new collectionEditor().show({
|
||||
import('collectionEditor').then(({default: collectionEditor}) => {
|
||||
new collectionEditor({
|
||||
items: [itemId],
|
||||
serverId: serverId
|
||||
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'addtoplaylist':
|
||||
require(['playlistEditor'], function (playlistEditor) {
|
||||
new playlistEditor().show({
|
||||
import('playlistEditor').then(({default: playlistEditor}) => {
|
||||
new playlistEditor({
|
||||
items: [itemId],
|
||||
serverId: serverId
|
||||
}).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'download':
|
||||
require(['fileDownloader'], function (fileDownloader) {
|
||||
var downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
import('fileDownloader').then((fileDownloader) => {
|
||||
const downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
fileDownloader.download([{
|
||||
url: downloadHref,
|
||||
itemId: itemId,
|
||||
@@ -346,17 +362,17 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
getResolveFunction(getResolveFunction(resolve, id), id)();
|
||||
});
|
||||
break;
|
||||
case 'copy-stream':
|
||||
var downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
var textAreaCopy = function () {
|
||||
var textArea = document.createElement('textarea');
|
||||
case 'copy-stream': {
|
||||
const downloadHref = apiClient.getItemDownloadUrl(itemId);
|
||||
const textAreaCopy = function () {
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = downloadHref;
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
if (document.execCommand('copy')) {
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('CopyStreamURLSuccess'));
|
||||
});
|
||||
} else {
|
||||
@@ -371,7 +387,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
} else {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.clipboard.writeText(downloadHref).then(function () {
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('CopyStreamURLSuccess'));
|
||||
});
|
||||
}).catch(function () {
|
||||
@@ -380,8 +396,9 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
}
|
||||
case 'editsubtitles':
|
||||
require(['subtitleEditor'], function (subtitleEditor) {
|
||||
import('subtitleEditor').then(({default: subtitleEditor}) => {
|
||||
subtitleEditor.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
@@ -389,7 +406,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
editItem(apiClient, item).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
break;
|
||||
case 'editimages':
|
||||
require(['imageEditor'], function (imageEditor) {
|
||||
import('imageEditor').then(({default: imageEditor}) => {
|
||||
imageEditor.show({
|
||||
itemId: itemId,
|
||||
serverId: serverId
|
||||
@@ -397,13 +414,13 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
});
|
||||
break;
|
||||
case 'identify':
|
||||
require(['itemIdentifier'], function (itemIdentifier) {
|
||||
import('itemIdentifier').then(({default: itemIdentifier}) => {
|
||||
itemIdentifier.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'moremediainfo':
|
||||
require(['itemMediaInfo'], function (itemMediaInfo) {
|
||||
itemMediaInfo.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
import('itemMediaInfo').then(({default: itemMediaInfo}) => {
|
||||
itemMediaInfo.show(itemId, serverId).then(getResolveFunction(resolve, id), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
case 'refresh':
|
||||
@@ -430,8 +447,14 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
play(item, false, true, true);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'stopPlayback':
|
||||
playbackManager.stop();
|
||||
break;
|
||||
case 'clearQueue':
|
||||
playbackManager.clearQueue();
|
||||
break;
|
||||
case 'record':
|
||||
require(['recordingCreator'], function (recordingCreator) {
|
||||
import('recordingCreator').then(({default: recordingCreator}) => {
|
||||
recordingCreator.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id));
|
||||
});
|
||||
break;
|
||||
@@ -458,7 +481,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'artist':
|
||||
appRouter.showItem(item.ArtistItems[0].Id, item.ServerId);
|
||||
appRouter.showItem(item.AlbumArtists[0].Id, item.ServerId);
|
||||
getResolveFunction(resolve, id)();
|
||||
break;
|
||||
case 'playallfromhere':
|
||||
@@ -502,8 +525,8 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function deleteTimer(apiClient, item, resolve, command) {
|
||||
require(['recordingHelper'], function (recordingHelper) {
|
||||
var timerId = item.TimerId || item.Id;
|
||||
import('recordingHelper').then(({default: recordingHelper}) => {
|
||||
const timerId = item.TimerId || item.Id;
|
||||
recordingHelper.cancelTimerWithConfirmation(timerId, item.ServerId).then(function () {
|
||||
getResolveFunction(resolve, command, true)();
|
||||
});
|
||||
@@ -511,7 +534,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function deleteSeriesTimer(apiClient, item, resolve, command) {
|
||||
require(['recordingHelper'], function (recordingHelper) {
|
||||
import('recordingHelper').then(({default: recordingHelper}) => {
|
||||
recordingHelper.cancelSeriesTimerWithConfirmation(item.Id, item.ServerId).then(function () {
|
||||
getResolveFunction(resolve, command, true)();
|
||||
});
|
||||
@@ -519,9 +542,9 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function play(item, resume, queue, queueNext) {
|
||||
var method = queue ? (queueNext ? 'queueNext' : 'queue') : 'play';
|
||||
const method = queue ? (queueNext ? 'queueNext' : 'queue') : 'play';
|
||||
|
||||
var startPosition = 0;
|
||||
let startPosition = 0;
|
||||
if (resume && item.UserData && item.UserData.PlaybackPositionTicks) {
|
||||
startPosition = item.UserData.PlaybackPositionTicks;
|
||||
}
|
||||
@@ -542,18 +565,18 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
|
||||
function editItem(apiClient, item) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
const serverId = apiClient.serverInfo().Id;
|
||||
|
||||
if (item.Type === 'Timer') {
|
||||
require(['recordingEditor'], function (recordingEditor) {
|
||||
import('recordingEditor').then(({default: recordingEditor}) => {
|
||||
recordingEditor.show(item.Id, serverId).then(resolve, reject);
|
||||
});
|
||||
} else if (item.Type === 'SeriesTimer') {
|
||||
require(['seriesRecordingEditor'], function (recordingEditor) {
|
||||
import('seriesRecordingEditor').then(({default: recordingEditor}) => {
|
||||
recordingEditor.show(item.Id, serverId).then(resolve, reject);
|
||||
});
|
||||
} else {
|
||||
require(['metadataEditor'], function (metadataEditor) {
|
||||
import('metadataEditor').then(({default: metadataEditor}) => {
|
||||
metadataEditor.show(item.Id, serverId).then(resolve, reject);
|
||||
});
|
||||
}
|
||||
@@ -562,7 +585,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
|
||||
function deleteItem(apiClient, item) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['deleteHelper'], function (deleteHelper) {
|
||||
import('deleteHelper').then(({default: deleteHelper}) => {
|
||||
deleteHelper.deleteItem({
|
||||
item: item,
|
||||
navigate: false
|
||||
@@ -574,7 +597,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
}
|
||||
|
||||
function refresh(apiClient, item) {
|
||||
require(['refreshDialog'], function (refreshDialog) {
|
||||
import('refreshDialog').then(({default: refreshDialog}) => {
|
||||
new refreshDialog({
|
||||
itemIds: [item.Id],
|
||||
serverId: apiClient.serverInfo().Id,
|
||||
@@ -583,8 +606,8 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
});
|
||||
}
|
||||
|
||||
function show(options) {
|
||||
var commands = getCommands(options);
|
||||
export function show(options) {
|
||||
const commands = getCommands(options);
|
||||
if (!commands.length) {
|
||||
return Promise.reject();
|
||||
}
|
||||
@@ -598,8 +621,9 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
getCommands: getCommands,
|
||||
show: show
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
getCommands: getCommands,
|
||||
show: show
|
||||
};
|
||||
|
||||
+311
-326
@@ -1,365 +1,350 @@
|
||||
define(['apphost', 'globalize'], function (appHost, globalize) {
|
||||
'use strict';
|
||||
import appHost from 'apphost';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function getDisplayName(item, options) {
|
||||
export function getDisplayName(item, options = {}) {
|
||||
if (!item) {
|
||||
throw new Error('null item passed into getDisplayName');
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
throw new Error('null item passed into getDisplayName');
|
||||
if (item.Type === 'Timer') {
|
||||
item = item.ProgramInfo || item;
|
||||
}
|
||||
|
||||
let name = ((item.Type === 'Program' || item.Type === 'Recording') && (item.IsSeries || item.EpisodeTitle) ? item.EpisodeTitle : item.Name) || '';
|
||||
|
||||
if (item.Type === 'TvChannel') {
|
||||
if (item.ChannelNumber) {
|
||||
return item.ChannelNumber + ' ' + name;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (item.Type === 'Timer') {
|
||||
item = item.ProgramInfo || item;
|
||||
}
|
||||
|
||||
var name = ((item.Type === 'Program' || item.Type === 'Recording') && (item.IsSeries || item.EpisodeTitle) ? item.EpisodeTitle : item.Name) || '';
|
||||
|
||||
if (item.Type === 'TvChannel') {
|
||||
if (item.ChannelNumber) {
|
||||
return item.ChannelNumber + ' ' + name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
if (item.Type === 'Episode' && item.ParentIndexNumber === 0) {
|
||||
name = globalize.translate('ValueSpecialEpisodeName', name);
|
||||
} else if ((item.Type === 'Episode' || item.Type === 'Program') && item.IndexNumber != null && item.ParentIndexNumber != null && options.includeIndexNumber !== false) {
|
||||
|
||||
var displayIndexNumber = item.IndexNumber;
|
||||
|
||||
var number = displayIndexNumber;
|
||||
var nameSeparator = ' - ';
|
||||
|
||||
if (options.includeParentInfo !== false) {
|
||||
number = 'S' + item.ParentIndexNumber + ':E' + number;
|
||||
} else {
|
||||
nameSeparator = '. ';
|
||||
}
|
||||
|
||||
if (item.IndexNumberEnd) {
|
||||
|
||||
displayIndexNumber = item.IndexNumberEnd;
|
||||
number += '-' + displayIndexNumber;
|
||||
}
|
||||
|
||||
if (number) {
|
||||
name = name ? (number + nameSeparator + name) : number;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
if (item.Type === 'Episode' && item.ParentIndexNumber === 0) {
|
||||
name = globalize.translate('ValueSpecialEpisodeName', name);
|
||||
} else if ((item.Type === 'Episode' || item.Type === 'Program') && item.IndexNumber != null && item.ParentIndexNumber != null && options.includeIndexNumber !== false) {
|
||||
let displayIndexNumber = item.IndexNumber;
|
||||
|
||||
function supportsAddingToCollection(item) {
|
||||
let number = displayIndexNumber;
|
||||
let nameSeparator = ' - ';
|
||||
|
||||
var invalidTypes = ['Genre', 'MusicGenre', 'Studio', 'UserView', 'CollectionFolder', 'Audio', 'Program', 'Timer', 'SeriesTimer'];
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
if (options.includeParentInfo !== false) {
|
||||
number = 'S' + item.ParentIndexNumber + ':E' + number;
|
||||
} else {
|
||||
nameSeparator = '. ';
|
||||
}
|
||||
|
||||
return !item.CollectionType && invalidTypes.indexOf(item.Type) === -1 && item.MediaType !== 'Photo' && !isLocalItem(item);
|
||||
if (item.IndexNumberEnd) {
|
||||
displayIndexNumber = item.IndexNumberEnd;
|
||||
number += '-' + displayIndexNumber;
|
||||
}
|
||||
|
||||
if (number) {
|
||||
name = name ? (number + nameSeparator + name) : number;
|
||||
}
|
||||
}
|
||||
|
||||
function supportsAddingToPlaylist(item) {
|
||||
return name;
|
||||
}
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
}
|
||||
export function supportsAddingToCollection(item) {
|
||||
const invalidTypes = ['Genre', 'MusicGenre', 'Studio', 'UserView', 'CollectionFolder', 'Audio', 'Program', 'Timer', 'SeriesTimer'];
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
if (item.CollectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.MediaType || item.IsFolder || item.Type === 'Genre' || item.Type === 'MusicGenre' || item.Type === 'MusicArtist';
|
||||
}
|
||||
|
||||
function canEdit(user, item) {
|
||||
return !item.CollectionType && invalidTypes.indexOf(item.Type) === -1 && item.MediaType !== 'Photo' && !isLocalItem(item);
|
||||
}
|
||||
|
||||
var itemType = item.Type;
|
||||
|
||||
if (itemType === 'UserRootFolder' || itemType === 'UserView') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.Policy.IsAdministrator;
|
||||
export function supportsAddingToPlaylist(item) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isLocalItem(item) {
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (item && item.Id && item.Id.indexOf('local') === 0) {
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
if (item.CollectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.MediaType || item.IsFolder || item.Type === 'Genre' || item.Type === 'MusicGenre' || item.Type === 'MusicArtist';
|
||||
}
|
||||
|
||||
export function canEdit(user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (itemType === 'UserRootFolder' || itemType === 'UserView') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.Policy.IsAdministrator;
|
||||
}
|
||||
|
||||
export function isLocalItem(item) {
|
||||
if (item && item.Id && item.Id.indexOf('local') === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function canIdentify (user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (itemType === 'Movie' ||
|
||||
itemType === 'Trailer' ||
|
||||
itemType === 'Series' ||
|
||||
itemType === 'BoxSet' ||
|
||||
itemType === 'Person' ||
|
||||
itemType === 'Book' ||
|
||||
itemType === 'MusicAlbum' ||
|
||||
itemType === 'MusicArtist' ||
|
||||
itemType === 'MusicVideo') {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function canEditImages (user, item) {
|
||||
const itemType = item.Type;
|
||||
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'UserView') {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return {
|
||||
getDisplayName: getDisplayName,
|
||||
supportsAddingToCollection: supportsAddingToCollection,
|
||||
supportsAddingToPlaylist: supportsAddingToPlaylist,
|
||||
isLocalItem: isLocalItem,
|
||||
|
||||
canIdentify: function (user, item) {
|
||||
|
||||
var itemType = item.Type;
|
||||
|
||||
if (itemType === 'Movie' ||
|
||||
itemType === 'Trailer' ||
|
||||
itemType === 'Series' ||
|
||||
itemType === 'BoxSet' ||
|
||||
itemType === 'Person' ||
|
||||
itemType === 'Book' ||
|
||||
itemType === 'MusicAlbum' ||
|
||||
itemType === 'MusicArtist' ||
|
||||
itemType === 'MusicVideo') {
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
canEdit: canEdit,
|
||||
return itemType !== 'Timer' && itemType !== 'SeriesTimer' && canEdit(user, item) && !isLocalItem(item);
|
||||
}
|
||||
|
||||
canEditImages: function (user, item) {
|
||||
export function canSync (user, item) {
|
||||
if (user && !user.Policy.EnableContentDownloading) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var itemType = item.Type;
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.MediaType === 'Photo') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemType === 'UserView') {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return itemType !== 'Timer' && itemType !== 'SeriesTimer' && canEdit(user, item) && !isLocalItem(item);
|
||||
},
|
||||
|
||||
canSync: function (user, item) {
|
||||
|
||||
if (user && !user.Policy.EnableContentDownloading) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.SupportsSync;
|
||||
},
|
||||
|
||||
canShare: function (item, user) {
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
return user.Policy.EnablePublicSharing && appHost.supports('sharing');
|
||||
},
|
||||
|
||||
enableDateAddedDisplay: function (item) {
|
||||
return !item.IsFolder && item.MediaType && item.Type !== 'Program' && item.Type !== 'TvChannel' && item.Type !== 'Trailer';
|
||||
},
|
||||
|
||||
canMarkPlayed: function (item) {
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.MediaType === 'Video') {
|
||||
if (item.Type !== 'TvChannel') {
|
||||
return true;
|
||||
}
|
||||
} else if (item.MediaType === 'Audio') {
|
||||
if (item.Type === 'AudioPodcast') {
|
||||
return true;
|
||||
}
|
||||
if (item.Type === 'AudioBook') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Series' ||
|
||||
item.Type === 'Season' ||
|
||||
item.Type === 'BoxSet' ||
|
||||
item.MediaType === 'Book' ||
|
||||
item.MediaType === 'Recording') {
|
||||
return true;
|
||||
}
|
||||
return item.SupportsSync;
|
||||
}
|
||||
|
||||
export function canShare (item, user) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Timer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'Recording') {
|
||||
if (item.Status !== 'Completed') {
|
||||
return false;
|
||||
},
|
||||
}
|
||||
}
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
return user.Policy.EnablePublicSharing && appHost.supports('sharing');
|
||||
}
|
||||
|
||||
canRate: function (item) {
|
||||
export function enableDateAddedDisplay (item) {
|
||||
return !item.IsFolder && item.MediaType && item.Type !== 'Program' && item.Type !== 'TvChannel' && item.Type !== 'Trailer';
|
||||
}
|
||||
|
||||
if (item.Type === 'Program'
|
||||
|| item.Type === 'Timer'
|
||||
|| item.Type === 'SeriesTimer'
|
||||
|| item.Type === 'CollectionFolder'
|
||||
|| item.Type === 'UserView'
|
||||
|| item.Type === 'Channel'
|
||||
|| !item.UserData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
canConvert: function (item, user) {
|
||||
|
||||
if (!user.Policy.EnableMediaConversion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var mediaType = item.MediaType;
|
||||
if (mediaType === 'Book' || mediaType === 'Photo' || mediaType === 'Audio') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var type = item.Type;
|
||||
if (type === 'Channel' || type === 'Person' || type === 'Year' || type === 'Program' || type === 'Timer' || type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.LocationType === 'Virtual' && !item.IsFolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.IsPlaceHolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
canRefreshMetadata: function (item, user) {
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
||||
var collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && item.Type !== 'TvChannel' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
|
||||
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
supportsMediaSourceSelection: function (item) {
|
||||
|
||||
if (item.MediaType !== 'Video') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (!item.MediaSources || (item.MediaSources.length === 1 && item.MediaSources[0].Type === 'Placeholder')) {
|
||||
return false;
|
||||
}
|
||||
if (item.EnableMediaSourceDisplay === false) {
|
||||
return false;
|
||||
}
|
||||
if (item.EnableMediaSourceDisplay == null && item.SourceType && item.SourceType !== 'Library') {
|
||||
return false;
|
||||
}
|
||||
export function canMarkPlayed (item) {
|
||||
if (item.Type === 'Program') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.MediaType === 'Video') {
|
||||
if (item.Type !== 'TvChannel') {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
} else if (item.MediaType === 'Audio') {
|
||||
if (item.Type === 'AudioPodcast') {
|
||||
return true;
|
||||
}
|
||||
if (item.Type === 'AudioBook') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'Series' ||
|
||||
item.Type === 'Season' ||
|
||||
item.Type === 'BoxSet' ||
|
||||
item.MediaType === 'Book' ||
|
||||
item.MediaType === 'Recording') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function canRate (item) {
|
||||
if (item.Type === 'Program'
|
||||
|| item.Type === 'Timer'
|
||||
|| item.Type === 'SeriesTimer'
|
||||
|| item.Type === 'CollectionFolder'
|
||||
|| item.Type === 'UserView'
|
||||
|| item.Type === 'Channel'
|
||||
|| !item.UserData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function canConvert (item, user) {
|
||||
if (!user.Policy.EnableMediaConversion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLocalItem(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const mediaType = item.MediaType;
|
||||
if (mediaType === 'Book' || mediaType === 'Photo' || mediaType === 'Audio') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const type = item.Type;
|
||||
if (type === 'Channel' || type === 'Person' || type === 'Year' || type === 'Program' || type === 'Timer' || type === 'SeriesTimer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.LocationType === 'Virtual' && !item.IsFolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.IsPlaceHolder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function canRefreshMetadata (item, user) {
|
||||
if (user.Policy.IsAdministrator) {
|
||||
const collectionType = item.CollectionType;
|
||||
if (collectionType === 'livetv') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.Type !== 'Timer' && item.Type !== 'SeriesTimer' && item.Type !== 'Program' && item.Type !== 'TvChannel' && !(item.Type === 'Recording' && item.Status !== 'Completed')) {
|
||||
if (!isLocalItem(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function supportsMediaSourceSelection (item) {
|
||||
if (item.MediaType !== 'Video') {
|
||||
return false;
|
||||
}
|
||||
if (item.Type === 'TvChannel') {
|
||||
return false;
|
||||
}
|
||||
if (!item.MediaSources || (item.MediaSources.length === 1 && item.MediaSources[0].Type === 'Placeholder')) {
|
||||
return false;
|
||||
}
|
||||
if (item.EnableMediaSourceDisplay === false) {
|
||||
return false;
|
||||
}
|
||||
if (item.EnableMediaSourceDisplay == null && item.SourceType && item.SourceType !== 'Library') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export default {
|
||||
getDisplayName: getDisplayName,
|
||||
supportsAddingToCollection: supportsAddingToCollection,
|
||||
supportsAddingToPlaylist: supportsAddingToPlaylist,
|
||||
isLocalItem: isLocalItem,
|
||||
canIdentify: canIdentify,
|
||||
canEdit: canEdit,
|
||||
canEditImages: canEditImages,
|
||||
canSync: canSync,
|
||||
canShare: canShare,
|
||||
enableDateAddedDisplay: enableDateAddedDisplay,
|
||||
canMarkPlayed: canMarkPlayed,
|
||||
canRate: canRate,
|
||||
canConvert: canConvert,
|
||||
canRefreshMetadata: canRefreshMetadata,
|
||||
supportsMediaSourceSelection: supportsMediaSourceSelection
|
||||
};
|
||||
|
||||
@@ -1,44 +1,74 @@
|
||||
define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', 'connectionManager', 'loading', 'focusManager', 'dom', 'apphost', 'emby-select', 'listViewStyle', 'paper-icon-button-light', 'css!./../formdialog', 'material-icons', 'emby-button', 'flexStyles'], function (dialogHelper, require, layoutManager, globalize, userSettings, connectionManager, loading, focusManager, dom, appHost) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for display media info.
|
||||
* @module components/itemMediaInfo/itemMediaInfo
|
||||
*/
|
||||
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import loading from 'loading';
|
||||
import 'emby-select';
|
||||
import 'listViewStyle';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./../formdialog';
|
||||
import 'material-icons';
|
||||
import 'emby-button';
|
||||
import 'flexStyles';
|
||||
|
||||
function setMediaInfo(user, page, item) {
|
||||
var html = item.MediaSources.map(function (version) {
|
||||
let html = item.MediaSources.map(version => {
|
||||
return getMediaSourceHtml(user, item, version);
|
||||
}).join('<div style="border-top:1px solid #444;margin: 1em 0;"></div>');
|
||||
if (item.MediaSources.length > 1) {
|
||||
html = '<br/>' + html;
|
||||
html = `<br/>${html}`;
|
||||
}
|
||||
var mediaInfoContent = page.querySelector('#mediaInfoContent');
|
||||
const mediaInfoContent = page.querySelector('#mediaInfoContent');
|
||||
mediaInfoContent.innerHTML = html;
|
||||
}
|
||||
|
||||
function getMediaSourceHtml(user, item, version) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
if (version.Name) {
|
||||
html += '<div><h2 class="mediaInfoStreamType">' + version.Name + '</h2></div>';
|
||||
html += `<div><h2 class="mediaInfoStreamType">${version.Name}</h2></div>`;
|
||||
}
|
||||
if (version.Container) {
|
||||
html += createAttribute(globalize.translate('MediaInfoContainer'), version.Container) + '<br/>';
|
||||
html += `${createAttribute(globalize.translate('MediaInfoContainer'), version.Container)}<br/>`;
|
||||
}
|
||||
if (version.Formats && version.Formats.length) {
|
||||
html += createAttribute(globalize.translate('MediaInfoFormat'), version.Formats.join(',')) + '<br/>';
|
||||
html += `${createAttribute(globalize.translate('MediaInfoFormat'), version.Formats.join(','))}<br/>`;
|
||||
}
|
||||
if (version.Path && user && user.Policy.IsAdministrator) {
|
||||
html += createAttribute(globalize.translate('MediaInfoPath'), version.Path) + '<br/>';
|
||||
html += `${createAttribute(globalize.translate('MediaInfoPath'), version.Path)}<br/>`;
|
||||
}
|
||||
if (version.Size) {
|
||||
var size = (version.Size / (1024 * 1024)).toFixed(0) + ' MB';
|
||||
html += createAttribute(globalize.translate('MediaInfoSize'), size) + '<br/>';
|
||||
const size = `${(version.Size / (1024 * 1024)).toFixed(0)} MB`;
|
||||
html += `${createAttribute(globalize.translate('MediaInfoSize'), size)}<br/>`;
|
||||
}
|
||||
for (var i = 0, length = version.MediaStreams.length; i < length; i++) {
|
||||
var stream = version.MediaStreams[i];
|
||||
for (let i = 0, length = version.MediaStreams.length; i < length; i++) {
|
||||
const stream = version.MediaStreams[i];
|
||||
if (stream.Type === 'Data') {
|
||||
continue;
|
||||
}
|
||||
|
||||
html += '<div class="mediaInfoStream">';
|
||||
var displayType = globalize.translate('MediaInfoStreamType' + stream.Type);
|
||||
html += '<h2 class="mediaInfoStreamType">' + displayType + '</h2>';
|
||||
var attributes = [];
|
||||
let translateString;
|
||||
switch (stream.Type) {
|
||||
case 'Audio':
|
||||
case 'Data':
|
||||
case 'Subtitle':
|
||||
case 'Video':
|
||||
translateString = stream.Type;
|
||||
break;
|
||||
case 'EmbeddedImage':
|
||||
translateString = 'Image';
|
||||
break;
|
||||
}
|
||||
|
||||
const displayType = globalize.translate(translateString);
|
||||
html += `<h2 class="mediaInfoStreamType">${displayType}</h2>`;
|
||||
const attributes = [];
|
||||
if (stream.DisplayTitle) {
|
||||
attributes.push(createAttribute('Title', stream.DisplayTitle));
|
||||
}
|
||||
@@ -61,7 +91,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoLevel'), stream.Level));
|
||||
}
|
||||
if (stream.Width || stream.Height) {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoResolution'), stream.Width + 'x' + stream.Height));
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoResolution'), `${stream.Width}x${stream.Height}`));
|
||||
}
|
||||
if (stream.AspectRatio && stream.Codec !== 'mjpeg') {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoAspectRatio'), stream.AspectRatio));
|
||||
@@ -79,16 +109,16 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoLayout'), stream.ChannelLayout));
|
||||
}
|
||||
if (stream.Channels) {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoChannels'), stream.Channels + ' ch'));
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoChannels'), `${stream.Channels} ch`));
|
||||
}
|
||||
if (stream.BitRate && stream.Codec !== 'mjpeg') {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoBitrate'), (parseInt(stream.BitRate / 1000)) + ' kbps'));
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoBitrate'), `${parseInt(stream.BitRate / 1000)} kbps`));
|
||||
}
|
||||
if (stream.SampleRate) {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoSampleRate'), stream.SampleRate + ' Hz'));
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoSampleRate'), `${stream.SampleRate} Hz`));
|
||||
}
|
||||
if (stream.BitDepth) {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoBitDepth'), stream.BitDepth + ' bit'));
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoBitDepth'), `${stream.BitDepth} bit`));
|
||||
}
|
||||
if (stream.PixelFormat) {
|
||||
attributes.push(createAttribute(globalize.translate('MediaInfoPixelFormat'), stream.PixelFormat));
|
||||
@@ -116,13 +146,13 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
|
||||
}
|
||||
|
||||
function createAttribute(label, value) {
|
||||
return '<span class="mediaInfoLabel">' + label + '</span><span class="mediaInfoAttribute">' + value + '</span>';
|
||||
return `<span class="mediaInfoLabel">${label}</span><span class="mediaInfoAttribute">${value}</span>`;
|
||||
}
|
||||
|
||||
function showMediaInfoMore(itemId, serverId, template) {
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||
var dialogOptions = {
|
||||
function loadMediaInfo(itemId, serverId, template) {
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(item => {
|
||||
const dialogOptions = {
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
@@ -130,35 +160,35 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings',
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
}
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
dlg.classList.add('formDialog');
|
||||
var html = '';
|
||||
html += globalize.translateDocument(template, 'core');
|
||||
let html = '';
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
dlg.innerHTML = html;
|
||||
if (layoutManager.tv) {
|
||||
dlg.querySelector('.formDialogContent');
|
||||
}
|
||||
dialogHelper.open(dlg);
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
apiClient.getCurrentUser().then(user => {
|
||||
setMediaInfo(user, dlg, item);
|
||||
});
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function showMediaInfo(itemId, serverId) {
|
||||
export function show(itemId, serverId) {
|
||||
loading.show();
|
||||
return new Promise(function (resolve, reject) {
|
||||
require(['text!./itemMediaInfo.template.html'], function (template) {
|
||||
showMediaInfoMore(itemId, serverId, template).then(resolve, reject);
|
||||
return import('text!./itemMediaInfo.template.html').then(({default: template}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
loadMediaInfo(itemId, serverId, template).then(resolve, reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: showMediaInfo
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1">
|
||||
<span class="material-icons arrow_back"></span>
|
||||
</button>
|
||||
<h3 class="formDialogHeaderTitle">${HeaderMediaInfo}</h3>
|
||||
<h3 class="formDialogHeaderTitle">${MoreMediaInfo}</h3>
|
||||
</div>
|
||||
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
|
||||
@@ -1,36 +1,51 @@
|
||||
define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize', 'scrollHelper', 'layoutManager', 'focusManager', 'browser', 'emby-input', 'emby-checkbox', 'paper-icon-button-light', 'css!./../formdialog', 'material-icons', 'cardStyle'], function (dialogHelper, loading, connectionManager, require, globalize, scrollHelper, layoutManager, focusManager, browser) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
var enableFocusTransform = !browser.slow && !browser.edge;
|
||||
/**
|
||||
* Module for itemidentifier media item.
|
||||
* @module components/itemidentifier/itemidentifier
|
||||
*/
|
||||
|
||||
var currentItem;
|
||||
var currentItemType;
|
||||
var currentServerId;
|
||||
var currentResolve;
|
||||
var currentReject;
|
||||
var hasChanges = false;
|
||||
var currentSearchResult;
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import loading from 'loading';
|
||||
import globalize from 'globalize';
|
||||
import scrollHelper from 'scrollHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import focusManager from 'focusManager';
|
||||
import browser from 'browser';
|
||||
import 'emby-input';
|
||||
import 'emby-checkbox';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./../formdialog';
|
||||
import 'material-icons';
|
||||
import 'cardStyle';
|
||||
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItem;
|
||||
let currentItemType;
|
||||
let currentServerId;
|
||||
let currentResolve;
|
||||
let currentReject;
|
||||
let hasChanges = false;
|
||||
let currentSearchResult;
|
||||
|
||||
function getApiClient() {
|
||||
return connectionManager.getApiClient(currentServerId);
|
||||
return window.connectionManager.getApiClient(currentServerId);
|
||||
}
|
||||
|
||||
function searchForIdentificationResults(page) {
|
||||
|
||||
var lookupInfo = {
|
||||
let lookupInfo = {
|
||||
ProviderIds: {}
|
||||
};
|
||||
|
||||
var i;
|
||||
var length;
|
||||
var identifyField = page.querySelectorAll('.identifyField');
|
||||
var value;
|
||||
let i;
|
||||
let length;
|
||||
const identifyField = page.querySelectorAll('.identifyField');
|
||||
let value;
|
||||
for (i = 0, length = identifyField.length; i < length; i++) {
|
||||
|
||||
value = identifyField[i].value;
|
||||
|
||||
if (value) {
|
||||
|
||||
if (identifyField[i].type === 'number') {
|
||||
value = parseInt(value);
|
||||
}
|
||||
@@ -39,11 +54,10 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
}
|
||||
|
||||
var hasId = false;
|
||||
let hasId = false;
|
||||
|
||||
var txtLookupId = page.querySelectorAll('.txtLookupId');
|
||||
const txtLookupId = page.querySelectorAll('.txtLookupId');
|
||||
for (i = 0, length = txtLookupId.length; i < length; i++) {
|
||||
|
||||
value = txtLookupId[i].value;
|
||||
|
||||
if (value) {
|
||||
@@ -53,7 +67,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
|
||||
if (!hasId && !lookupInfo.Name) {
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('PleaseEnterNameOrId'));
|
||||
});
|
||||
return;
|
||||
@@ -71,60 +85,54 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
|
||||
loading.show();
|
||||
|
||||
var apiClient = getApiClient();
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.ajax({
|
||||
type: 'POST',
|
||||
url: apiClient.getUrl('Items/RemoteSearch/' + currentItemType),
|
||||
url: apiClient.getUrl(`Items/RemoteSearch/${currentItemType}`),
|
||||
data: JSON.stringify(lookupInfo),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json'
|
||||
|
||||
}).then(function (results) {
|
||||
|
||||
}).then(results => {
|
||||
loading.hide();
|
||||
showIdentificationSearchResults(page, results);
|
||||
});
|
||||
}
|
||||
|
||||
function showIdentificationSearchResults(page, results) {
|
||||
|
||||
var identificationSearchResults = page.querySelector('.identificationSearchResults');
|
||||
const identificationSearchResults = page.querySelector('.identificationSearchResults');
|
||||
|
||||
page.querySelector('.popupIdentifyForm').classList.add('hide');
|
||||
identificationSearchResults.classList.remove('hide');
|
||||
page.querySelector('.identifyOptionsForm').classList.add('hide');
|
||||
page.querySelector('.dialogContentInner').classList.remove('dialog-content-centered');
|
||||
|
||||
var html = '';
|
||||
var i;
|
||||
var length;
|
||||
let html = '';
|
||||
let i;
|
||||
let length;
|
||||
for (i = 0, length = results.length; i < length; i++) {
|
||||
|
||||
var result = results[i];
|
||||
const result = results[i];
|
||||
html += getSearchResultHtml(result, i);
|
||||
}
|
||||
|
||||
var elem = page.querySelector('.identificationSearchResultList');
|
||||
const elem = page.querySelector('.identificationSearchResultList');
|
||||
elem.innerHTML = html;
|
||||
|
||||
function onSearchImageClick() {
|
||||
var index = parseInt(this.getAttribute('data-index'));
|
||||
const index = parseInt(this.getAttribute('data-index'));
|
||||
|
||||
var currentResult = results[index];
|
||||
const currentResult = results[index];
|
||||
|
||||
if (currentItem != null) {
|
||||
|
||||
showIdentifyOptions(page, currentResult);
|
||||
} else {
|
||||
|
||||
finishFindNewDialog(page, currentResult);
|
||||
}
|
||||
}
|
||||
|
||||
var searchImages = elem.querySelectorAll('.card');
|
||||
const searchImages = elem.querySelectorAll('.card');
|
||||
for (i = 0, length = searchImages.length; i < length; i++) {
|
||||
|
||||
searchImages[i].addEventListener('click', onSearchImageClick);
|
||||
}
|
||||
|
||||
@@ -142,8 +150,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
|
||||
function showIdentifyOptions(page, identifyResult) {
|
||||
|
||||
var identifyOptionsForm = page.querySelector('.identifyOptionsForm');
|
||||
const identifyOptionsForm = page.querySelector('.identifyOptionsForm');
|
||||
|
||||
page.querySelector('.popupIdentifyForm').classList.add('hide');
|
||||
page.querySelector('.identificationSearchResults').classList.add('hide');
|
||||
@@ -153,19 +160,19 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
|
||||
currentSearchResult = identifyResult;
|
||||
|
||||
var lines = [];
|
||||
const lines = [];
|
||||
lines.push(identifyResult.Name);
|
||||
|
||||
if (identifyResult.ProductionYear) {
|
||||
lines.push(identifyResult.ProductionYear);
|
||||
}
|
||||
|
||||
var resultHtml = lines.join('<br/>');
|
||||
let resultHtml = lines.join('<br/>');
|
||||
|
||||
if (identifyResult.ImageUrl) {
|
||||
var displayUrl = getSearchImageDisplayUrl(identifyResult.ImageUrl, identifyResult.SearchProviderName);
|
||||
const displayUrl = getSearchImageDisplayUrl(identifyResult.ImageUrl, identifyResult.SearchProviderName);
|
||||
|
||||
resultHtml = '<div style="display:flex;align-items:center;"><img src="' + displayUrl + '" style="max-height:240px;" /><div style="margin-left:1em;">' + resultHtml + '</div>';
|
||||
resultHtml = `<div style="display:flex;align-items:center;"><img src="${displayUrl}" style="max-height:240px;" /><div style="margin-left:1em;">${resultHtml}</div>`;
|
||||
}
|
||||
|
||||
page.querySelector('.selectedSearchResult').innerHTML = resultHtml;
|
||||
@@ -174,13 +181,12 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
|
||||
function getSearchResultHtml(result, index) {
|
||||
|
||||
// TODO move card creation code to Card component
|
||||
|
||||
var html = '';
|
||||
var cssClass = 'card scalableCard';
|
||||
var cardBoxCssClass = 'cardBox';
|
||||
var padderClass;
|
||||
let html = '';
|
||||
let cssClass = 'card scalableCard';
|
||||
let cardBoxCssClass = 'cardBox';
|
||||
let padderClass;
|
||||
|
||||
if (currentItemType === 'Episode') {
|
||||
cssClass += ' backdropCard backdropCard-scalable';
|
||||
@@ -203,30 +209,31 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
|
||||
cardBoxCssClass += ' cardBox-bottompadded';
|
||||
|
||||
html += '<button type="button" class="' + cssClass + '" data-index="' + index + '">';
|
||||
html += '<div class="' + cardBoxCssClass + '">';
|
||||
html += `<button type="button" class="${cssClass}" data-index="${index}">`;
|
||||
html += `<div class="${cardBoxCssClass}">`;
|
||||
html += '<div class="cardScalable">';
|
||||
html += '<div class="' + padderClass + '"></div>';
|
||||
html += `<div class="${padderClass}"></div>`;
|
||||
|
||||
html += '<div class="cardContent searchImage">';
|
||||
|
||||
if (result.ImageUrl) {
|
||||
var displayUrl = getSearchImageDisplayUrl(result.ImageUrl, result.SearchProviderName);
|
||||
const displayUrl = getSearchImageDisplayUrl(result.ImageUrl, result.SearchProviderName);
|
||||
|
||||
html += '<div class="cardImageContainer coveredImage" style="background-image:url(\'' + displayUrl + '\');"></div>';
|
||||
html += `<div class="cardImageContainer coveredImage" style="background-image:url('${displayUrl}');"></div>`;
|
||||
} else {
|
||||
|
||||
html += '<div class="cardImageContainer coveredImage defaultCardBackground defaultCardBackground1"><div class="cardText cardCenteredText">' + result.Name + '</div></div>';
|
||||
html += `<div class="cardImageContainer coveredImage defaultCardBackground defaultCardBackground1"><div class="cardText cardCenteredText">${result.Name}</div></div>`;
|
||||
}
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
var numLines = 2;
|
||||
let numLines = 3;
|
||||
if (currentItemType === 'MusicAlbum') {
|
||||
numLines++;
|
||||
}
|
||||
|
||||
var lines = [result.Name];
|
||||
const lines = [result.Name];
|
||||
|
||||
lines.push(result.SearchProviderName);
|
||||
|
||||
if (result.AlbumArtist) {
|
||||
lines.push(result.AlbumArtist.Name);
|
||||
@@ -235,8 +242,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
lines.push(result.ProductionYear);
|
||||
}
|
||||
|
||||
for (var i = 0; i < numLines; i++) {
|
||||
|
||||
for (let i = 0; i < numLines; i++) {
|
||||
if (i === 0) {
|
||||
html += '<div class="cardText cardText-first cardTextCentered">';
|
||||
} else {
|
||||
@@ -252,36 +258,32 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
|
||||
function getSearchImageDisplayUrl(url, provider) {
|
||||
var apiClient = getApiClient();
|
||||
const apiClient = getApiClient();
|
||||
|
||||
return apiClient.getUrl('Items/RemoteSearch/Image', { imageUrl: url, ProviderName: provider });
|
||||
}
|
||||
|
||||
function submitIdentficationResult(page) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
ReplaceAllImages: page.querySelector('#chkIdentifyReplaceImages').checked
|
||||
};
|
||||
|
||||
var apiClient = getApiClient();
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.ajax({
|
||||
type: 'POST',
|
||||
url: apiClient.getUrl('Items/RemoteSearch/Apply/' + currentItem.Id, options),
|
||||
url: apiClient.getUrl(`Items/RemoteSearch/Apply/${currentItem.Id}`, options),
|
||||
data: JSON.stringify(currentSearchResult),
|
||||
contentType: 'application/json'
|
||||
|
||||
}).then(function () {
|
||||
|
||||
}).then(() => {
|
||||
hasChanges = true;
|
||||
loading.hide();
|
||||
|
||||
dialogHelper.close(page);
|
||||
|
||||
}, function () {
|
||||
|
||||
}, () => {
|
||||
loading.hide();
|
||||
|
||||
dialogHelper.close(page);
|
||||
@@ -289,29 +291,26 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
|
||||
function showIdentificationForm(page, item) {
|
||||
const apiClient = getApiClient();
|
||||
|
||||
var apiClient = getApiClient();
|
||||
apiClient.getJSON(apiClient.getUrl(`Items/${item.Id}/ExternalIdInfos`)).then(idList => {
|
||||
let html = '';
|
||||
|
||||
apiClient.getJSON(apiClient.getUrl('Items/' + item.Id + '/ExternalIdInfos')).then(function (idList) {
|
||||
for (let i = 0, length = idList.length; i < length; i++) {
|
||||
const idInfo = idList[i];
|
||||
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = idList.length; i < length; i++) {
|
||||
|
||||
var idInfo = idList[i];
|
||||
|
||||
var id = 'txtLookup' + idInfo.Key;
|
||||
const id = `txtLookup${idInfo.Key}`;
|
||||
|
||||
html += '<div class="inputContainer">';
|
||||
|
||||
var fullName = idInfo.Name;
|
||||
let fullName = idInfo.Name;
|
||||
if (idInfo.Type) {
|
||||
fullName = idInfo.Name + ' ' + globalize.translate(idInfo.Type);
|
||||
fullName = `${idInfo.Name} ${globalize.translate(idInfo.Type)}`;
|
||||
}
|
||||
|
||||
var idLabel = globalize.translate('LabelDynamicExternalId', fullName);
|
||||
const idLabel = globalize.translate('LabelDynamicExternalId', fullName);
|
||||
|
||||
html += '<input is="emby-input" class="txtLookupId" data-providerkey="' + idInfo.Key + '" id="' + id + '" label="' + idLabel + '"/>';
|
||||
html += `<input is="emby-input" class="txtLookupId" data-providerkey="${idInfo.Key}" id="${id}" label="${idLabel}"/>`;
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -319,11 +318,9 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
page.querySelector('#txtLookupName').value = '';
|
||||
|
||||
if (item.Type === 'Person' || item.Type === 'BoxSet') {
|
||||
|
||||
page.querySelector('.fldLookupYear').classList.add('hide');
|
||||
page.querySelector('#txtLookupYear').value = '';
|
||||
} else {
|
||||
|
||||
page.querySelector('.fldLookupYear').classList.remove('hide');
|
||||
page.querySelector('#txtLookupYear').value = '';
|
||||
}
|
||||
@@ -335,19 +332,16 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
|
||||
function showEditor(itemId) {
|
||||
|
||||
loading.show();
|
||||
|
||||
require(['text!./itemidentifier.template.html'], function (template) {
|
||||
|
||||
var apiClient = getApiClient();
|
||||
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
|
||||
return import('text!./itemidentifier.template.html').then(({default: template}) => {
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(item => {
|
||||
currentItem = item;
|
||||
currentItemType = currentItem.Type;
|
||||
|
||||
var dialogOptions = {
|
||||
const dialogOptions = {
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
@@ -357,13 +351,13 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
dialogOptions.size = 'fullscreen';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('recordingDialog');
|
||||
|
||||
var html = '';
|
||||
html += globalize.translateDocument(template, 'core');
|
||||
let html = '';
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
@@ -384,22 +378,19 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', function (e) {
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', e => {
|
||||
e.preventDefault();
|
||||
searchForIdentificationResults(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.querySelector('.identifyOptionsForm').addEventListener('submit', function (e) {
|
||||
|
||||
dlg.querySelector('.identifyOptionsForm').addEventListener('submit', e => {
|
||||
e.preventDefault();
|
||||
submitIdentficationResult(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
@@ -412,7 +403,6 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
|
||||
function onDialogClosed() {
|
||||
|
||||
loading.hide();
|
||||
if (hasChanges) {
|
||||
currentResolve();
|
||||
@@ -421,14 +411,13 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
}
|
||||
|
||||
// TODO investigate where this was used
|
||||
function showEditorFindNew(itemName, itemYear, itemType, resolveFunc) {
|
||||
|
||||
currentItem = null;
|
||||
currentItemType = itemType;
|
||||
|
||||
require(['text!./itemidentifier.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
return import('text!./itemidentifier.template.html').then(({default: template}) => {
|
||||
const dialogOptions = {
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
@@ -438,13 +427,13 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
dialogOptions.size = 'fullscreen';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.classList.add('recordingDialog');
|
||||
|
||||
var html = '';
|
||||
html += globalize.translateDocument(template, 'core');
|
||||
let html = '';
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
@@ -454,22 +443,19 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', function (e) {
|
||||
|
||||
dlg.querySelector('.popupIdentifyForm').addEventListener('submit', e => {
|
||||
e.preventDefault();
|
||||
searchForIdentificationResults(dlg);
|
||||
return false;
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
dlg.addEventListener('close', () => {
|
||||
loading.hide();
|
||||
var foundItem = hasChanges ? currentSearchResult : null;
|
||||
const foundItem = hasChanges ? currentSearchResult : null;
|
||||
|
||||
resolveFunc(foundItem);
|
||||
});
|
||||
@@ -481,16 +467,12 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
}
|
||||
|
||||
function showIdentificationFormFindNew(dlg, itemName, itemYear, itemType) {
|
||||
|
||||
dlg.querySelector('#txtLookupName').value = itemName;
|
||||
|
||||
if (itemType === 'Person' || itemType === 'BoxSet') {
|
||||
|
||||
dlg.querySelector('.fldLookupYear').classList.add('hide');
|
||||
dlg.querySelector('#txtLookupYear').value = '';
|
||||
|
||||
} else {
|
||||
|
||||
dlg.querySelector('.fldLookupYear').classList.remove('hide');
|
||||
dlg.querySelector('#txtLookupYear').value = itemYear;
|
||||
}
|
||||
@@ -498,29 +480,28 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
||||
dlg.querySelector('.formDialogHeaderTitle').innerHTML = globalize.translate('Search');
|
||||
}
|
||||
|
||||
return {
|
||||
show: function (itemId, serverId) {
|
||||
export function show(itemId, serverId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
currentServerId = serverId;
|
||||
hasChanges = false;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
showEditor(itemId);
|
||||
});
|
||||
}
|
||||
|
||||
currentResolve = resolve;
|
||||
currentReject = reject;
|
||||
currentServerId = serverId;
|
||||
hasChanges = false;
|
||||
export function showFindNew(itemName, itemYear, itemType, serverId) {
|
||||
return new Promise((resolve) => {
|
||||
currentServerId = serverId;
|
||||
|
||||
showEditor(itemId);
|
||||
});
|
||||
},
|
||||
hasChanges = false;
|
||||
showEditorFindNew(itemName, itemYear, itemType, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
showFindNew: function (itemName, itemYear, itemType, serverId) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
currentServerId = serverId;
|
||||
|
||||
hasChanges = false;
|
||||
showEditorFindNew(itemName, itemYear, itemType, resolve);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
show: show,
|
||||
showFindNew: showFindNew
|
||||
};
|
||||
|
||||
+156
-187
@@ -1,149 +1,130 @@
|
||||
define(['playbackManager', 'serverNotifications', 'events'], function (playbackManager, serverNotifications, events) {
|
||||
'use strict';
|
||||
import playbackManager from 'playbackManager';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import events from 'events';
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
const instance = this;
|
||||
|
||||
var instance = this;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function getEventsToMonitor(instance) {
|
||||
|
||||
var options = instance.options;
|
||||
var monitor = options ? options.monitorEvents : null;
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onSeriesTimerCreated(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
var instance = this;
|
||||
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
|
||||
var instance = this;
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
var itemsAdded = data.ItemsAdded || [];
|
||||
var itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = instance.options || {};
|
||||
var parentId = options.parentId;
|
||||
if (parentId) {
|
||||
var foldersAddedTo = data.FoldersAddedTo || [];
|
||||
var foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
var collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
function getEventsToMonitor(instance) {
|
||||
const options = instance.options;
|
||||
const monitor = options ? options.monitorEvents : null;
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
var instance = this;
|
||||
return [];
|
||||
}
|
||||
|
||||
var state = stopInfo.state;
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
const instance = this;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
function onSeriesTimerCreated(e, apiClient, data) {
|
||||
const instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
const instance = this;
|
||||
|
||||
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
if (getEventsToMonitor(instance).indexOf('timers') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
const instance = this;
|
||||
if (getEventsToMonitor(instance).indexOf('seriestimers') !== -1) {
|
||||
instance.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
const instance = this;
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
const itemsAdded = data.ItemsAdded || [];
|
||||
const itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = instance.options || {};
|
||||
const parentId = options.parentId;
|
||||
if (parentId) {
|
||||
const foldersAddedTo = data.FoldersAddedTo || [];
|
||||
const foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
const collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
instance.notifyRefreshNeeded();
|
||||
}
|
||||
|
||||
var localHandler = handler.bind(instance);
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
const instance = this;
|
||||
|
||||
const state = stopInfo.state;
|
||||
|
||||
const eventsToMonitor = getEventsToMonitor(instance);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
||||
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
instance.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
const localHandler = handler.bind(instance);
|
||||
owner = owner || serverNotifications;
|
||||
events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
const handler = instance['event_' + name];
|
||||
if (handler) {
|
||||
owner = owner || serverNotifications;
|
||||
events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
events.off(owner, name, handler);
|
||||
instance['event_' + name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
|
||||
var handler = instance['event_' + name];
|
||||
if (handler) {
|
||||
owner = owner || serverNotifications;
|
||||
events.off(owner, name, handler);
|
||||
instance['event_' + name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function ItemsRefresher(options) {
|
||||
|
||||
class ItemsRefresher {
|
||||
constructor(options) {
|
||||
this.options = options || {};
|
||||
|
||||
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
|
||||
@@ -155,25 +136,20 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
|
||||
}
|
||||
|
||||
ItemsRefresher.prototype.pause = function () {
|
||||
|
||||
pause() {
|
||||
clearRefreshInterval(this, true);
|
||||
|
||||
this.paused = true;
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.resume = function (options) {
|
||||
}
|
||||
|
||||
resume(options) {
|
||||
this.paused = false;
|
||||
|
||||
var refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
const refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
if (refreshIntervalEndTime) {
|
||||
|
||||
var remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
const remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
if (remainingMs > 0 && !this.needsRefresh) {
|
||||
|
||||
resetRefreshInterval(this, remainingMs);
|
||||
|
||||
} else {
|
||||
this.needsRefresh = true;
|
||||
this.refreshIntervalEndTime = null;
|
||||
@@ -185,10 +161,9 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.refreshItems = function () {
|
||||
}
|
||||
|
||||
refreshItems() {
|
||||
if (!this.fetchData) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -201,16 +176,15 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
this.needsRefresh = false;
|
||||
|
||||
return this.fetchData().then(onDataFetched.bind(this));
|
||||
};
|
||||
|
||||
ItemsRefresher.prototype.notifyRefreshNeeded = function (isInForeground) {
|
||||
}
|
||||
|
||||
notifyRefreshNeeded(isInForeground) {
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var timeout = this.refreshTimeout;
|
||||
const timeout = this.refreshTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
@@ -220,49 +194,9 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
} else {
|
||||
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
|
||||
}
|
||||
};
|
||||
|
||||
function clearRefreshInterval(instance, isPausing) {
|
||||
|
||||
if (instance.refreshInterval) {
|
||||
|
||||
clearInterval(instance.refreshInterval);
|
||||
instance.refreshInterval = null;
|
||||
|
||||
if (!isPausing) {
|
||||
instance.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(instance, intervalMs) {
|
||||
|
||||
clearRefreshInterval(instance);
|
||||
|
||||
if (!intervalMs) {
|
||||
var options = instance.options;
|
||||
if (options) {
|
||||
intervalMs = options.refreshIntervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
if (intervalMs) {
|
||||
instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs);
|
||||
instance.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
|
||||
resetRefreshInterval(this);
|
||||
|
||||
if (this.afterRefresh) {
|
||||
this.afterRefresh(result);
|
||||
}
|
||||
}
|
||||
|
||||
ItemsRefresher.prototype.destroy = function () {
|
||||
|
||||
destroy() {
|
||||
clearRefreshInterval(this);
|
||||
|
||||
removeNotificationEvent(this, 'UserDataChanged');
|
||||
@@ -275,7 +209,42 @@ define(['playbackManager', 'serverNotifications', 'events'], function (playbackM
|
||||
|
||||
this.fetchData = null;
|
||||
this.options = null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return ItemsRefresher;
|
||||
});
|
||||
function clearRefreshInterval(instance, isPausing) {
|
||||
if (instance.refreshInterval) {
|
||||
clearInterval(instance.refreshInterval);
|
||||
instance.refreshInterval = null;
|
||||
|
||||
if (!isPausing) {
|
||||
instance.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(instance, intervalMs) {
|
||||
clearRefreshInterval(instance);
|
||||
|
||||
if (!intervalMs) {
|
||||
const options = instance.options;
|
||||
if (options) {
|
||||
intervalMs = options.refreshIntervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
if (intervalMs) {
|
||||
instance.refreshInterval = setInterval(instance.notifyRefreshNeeded.bind(instance), intervalMs);
|
||||
instance.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
resetRefreshInterval(this);
|
||||
|
||||
if (this.afterRefresh) {
|
||||
this.afterRefresh(result);
|
||||
}
|
||||
}
|
||||
|
||||
export default ItemsRefresher;
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
define(['browser', 'appSettings', 'events'], function (browser, appSettings, events) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
import appSettings from 'appSettings';
|
||||
import events from 'events';
|
||||
|
||||
function setLayout(instance, layout, selectedLayout) {
|
||||
if (layout === selectedLayout) {
|
||||
instance[layout] = true;
|
||||
document.documentElement.classList.add('layout-' + layout);
|
||||
} else {
|
||||
instance[layout] = false;
|
||||
document.documentElement.classList.remove('layout-' + layout);
|
||||
}
|
||||
function setLayout(instance, layout, selectedLayout) {
|
||||
if (layout === selectedLayout) {
|
||||
instance[layout] = true;
|
||||
document.documentElement.classList.add('layout-' + layout);
|
||||
} else {
|
||||
instance[layout] = false;
|
||||
document.documentElement.classList.remove('layout-' + layout);
|
||||
}
|
||||
}
|
||||
|
||||
function LayoutManager() {
|
||||
|
||||
}
|
||||
|
||||
LayoutManager.prototype.setLayout = function (layout, save) {
|
||||
|
||||
class LayoutManager {
|
||||
setLayout(layout, save) {
|
||||
if (!layout || layout === 'auto') {
|
||||
this.autoLayout();
|
||||
|
||||
@@ -34,14 +31,13 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
||||
}
|
||||
|
||||
events.trigger(this, 'modechange');
|
||||
};
|
||||
}
|
||||
|
||||
LayoutManager.prototype.getSavedLayout = function (layout) {
|
||||
getSavedLayout(layout) {
|
||||
return appSettings.get('layout');
|
||||
};
|
||||
|
||||
LayoutManager.prototype.autoLayout = function () {
|
||||
}
|
||||
|
||||
autoLayout() {
|
||||
// Take a guess at initial layout. The consuming app can override
|
||||
if (browser.mobile) {
|
||||
this.setLayout('mobile', false);
|
||||
@@ -50,16 +46,16 @@ define(['browser', 'appSettings', 'events'], function (browser, appSettings, eve
|
||||
} else {
|
||||
this.setLayout(this.defaultLayout || 'tv', false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LayoutManager.prototype.init = function () {
|
||||
var saved = this.getSavedLayout();
|
||||
init() {
|
||||
const saved = this.getSavedLayout();
|
||||
if (saved) {
|
||||
this.setLayout(saved, false);
|
||||
} else {
|
||||
this.autoLayout();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new LayoutManager();
|
||||
});
|
||||
export default new LayoutManager();
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
(entries) => {
|
||||
entries.forEach(entry => {
|
||||
callback(entry);
|
||||
},
|
||||
{rootMargin: '50%'});
|
||||
});
|
||||
});
|
||||
},
|
||||
{rootMargin: '25%'});
|
||||
|
||||
this.observer = observer;
|
||||
}
|
||||
|
||||
@@ -1,63 +1,73 @@
|
||||
define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], function(globalize, dom) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for library options editor.
|
||||
* @module components/libraryoptionseditor/libraryoptionseditor
|
||||
*/
|
||||
|
||||
import globalize from 'globalize';
|
||||
import dom from 'dom';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-select';
|
||||
import 'emby-input';
|
||||
|
||||
function populateLanguages(parent) {
|
||||
return ApiClient.getCultures().then(function(languages) {
|
||||
return ApiClient.getCultures().then(languages => {
|
||||
populateLanguagesIntoSelect(parent.querySelector('#selectLanguage'), languages);
|
||||
populateLanguagesIntoList(parent.querySelector('.subtitleDownloadLanguages'), languages);
|
||||
});
|
||||
}
|
||||
|
||||
function populateLanguagesIntoSelect(select, languages) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
html += "<option value=''></option>";
|
||||
for (var i = 0; i < languages.length; i++) {
|
||||
var culture = languages[i];
|
||||
html += "<option value='" + culture.TwoLetterISOLanguageName + "'>" + culture.DisplayName + '</option>';
|
||||
for (let i = 0; i < languages.length; i++) {
|
||||
const culture = languages[i];
|
||||
html += `<option value='${culture.TwoLetterISOLanguageName}'>${culture.DisplayName}</option>`;
|
||||
}
|
||||
select.innerHTML = html;
|
||||
}
|
||||
|
||||
function populateLanguagesIntoList(element, languages) {
|
||||
var html = '';
|
||||
for (var i = 0; i < languages.length; i++) {
|
||||
var culture = languages[i];
|
||||
html += '<label><input type="checkbox" is="emby-checkbox" class="chkSubtitleLanguage" data-lang="' + culture.ThreeLetterISOLanguageName.toLowerCase() + '" /><span>' + culture.DisplayName + '</span></label>';
|
||||
let html = '';
|
||||
for (let i = 0; i < languages.length; i++) {
|
||||
const culture = languages[i];
|
||||
html += `<label><input type="checkbox" is="emby-checkbox" class="chkSubtitleLanguage" data-lang="${culture.ThreeLetterISOLanguageName.toLowerCase()}" /><span>${culture.DisplayName}</span></label>`;
|
||||
}
|
||||
element.innerHTML = html;
|
||||
}
|
||||
|
||||
function populateCountries(select) {
|
||||
return ApiClient.getCountries().then(function(allCountries) {
|
||||
var html = '';
|
||||
return ApiClient.getCountries().then(allCountries => {
|
||||
let html = '';
|
||||
html += "<option value=''></option>";
|
||||
for (var i = 0; i < allCountries.length; i++) {
|
||||
var culture = allCountries[i];
|
||||
html += "<option value='" + culture.TwoLetterISORegionName + "'>" + culture.DisplayName + '</option>';
|
||||
for (let i = 0; i < allCountries.length; i++) {
|
||||
const culture = allCountries[i];
|
||||
html += `<option value='${culture.TwoLetterISORegionName}'>${culture.DisplayName}</option>`;
|
||||
}
|
||||
select.innerHTML = html;
|
||||
});
|
||||
}
|
||||
|
||||
function populateRefreshInterval(select) {
|
||||
var html = '';
|
||||
html += "<option value='0'>" + globalize.translate('Never') + '</option>';
|
||||
html += [30, 60, 90].map(function(val) {
|
||||
return "<option value='" + val + "'>" + globalize.translate('EveryNDays', val) + '</option>';
|
||||
let html = '';
|
||||
html += `<option value='0'>${globalize.translate('Never')}</option>`;
|
||||
html += [30, 60, 90].map(val => {
|
||||
return `<option value='${val}'>${globalize.translate('EveryNDays', val)}</option>`;
|
||||
}).join('');
|
||||
select.innerHTML = html;
|
||||
}
|
||||
|
||||
function renderMetadataReaders(page, plugins) {
|
||||
var html = '';
|
||||
var elem = page.querySelector('.metadataReaders');
|
||||
let html = '';
|
||||
const elem = page.querySelector('.metadataReaders');
|
||||
|
||||
if (plugins.length < 1) return elem.innerHTML = '', elem.classList.add('hide'), !1;
|
||||
html += '<h3 class="checkboxListLabel">' + globalize.translate('LabelMetadataReaders') + '</h3>';
|
||||
html += `<h3 class="checkboxListLabel">${globalize.translate('LabelMetadataReaders')}</h3>`;
|
||||
html += '<div class="checkboxList paperList checkboxList-paperList">';
|
||||
for (var i = 0; i < plugins.length; i++) {
|
||||
var plugin = plugins[i];
|
||||
html += '<div class="listItem localReaderOption sortableOption" data-pluginname="' + plugin.Name + '">';
|
||||
for (let i = 0; i < plugins.length; i++) {
|
||||
const plugin = plugins[i];
|
||||
html += `<div class="listItem localReaderOption sortableOption" data-pluginname="${plugin.Name}">`;
|
||||
html += '<span class="listItemIcon material-icons live_tv"></span>';
|
||||
html += '<div class="listItemBody">';
|
||||
html += '<h3 class="listItemBodyText">';
|
||||
@@ -65,14 +75,14 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Up')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
} else if (plugins.length > 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Down')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '<div class="fieldDescription">' + globalize.translate('LabelMetadataReadersHelp') + '</div>';
|
||||
html += `<div class="fieldDescription">${globalize.translate('LabelMetadataReadersHelp')}</div>`;
|
||||
if (plugins.length < 2) {
|
||||
elem.classList.add('hide');
|
||||
} else {
|
||||
@@ -83,25 +93,25 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
}
|
||||
|
||||
function renderMetadataSavers(page, metadataSavers) {
|
||||
var html = '';
|
||||
var elem = page.querySelector('.metadataSavers');
|
||||
let html = '';
|
||||
const elem = page.querySelector('.metadataSavers');
|
||||
if (!metadataSavers.length) return elem.innerHTML = '', elem.classList.add('hide'), false;
|
||||
html += '<h3 class="checkboxListLabel">' + globalize.translate('LabelMetadataSavers') + '</h3>';
|
||||
html += `<h3 class="checkboxListLabel">${globalize.translate('LabelMetadataSavers')}</h3>`;
|
||||
html += '<div class="checkboxList paperList checkboxList-paperList">';
|
||||
for (var i = 0; i < metadataSavers.length; i++) {
|
||||
var plugin = metadataSavers[i];
|
||||
html += '<label><input type="checkbox" data-defaultenabled="' + plugin.DefaultEnabled + '" is="emby-checkbox" class="chkMetadataSaver" data-pluginname="' + plugin.Name + '" ' + false + '><span>' + plugin.Name + '</span></label>';
|
||||
for (let i = 0; i < metadataSavers.length; i++) {
|
||||
const plugin = metadataSavers[i];
|
||||
html += `<label><input type="checkbox" data-defaultenabled="${plugin.DefaultEnabled}" is="emby-checkbox" class="chkMetadataSaver" data-pluginname="${plugin.Name}" ${false}><span>${plugin.Name}</span></label>`;
|
||||
}
|
||||
html += '</div>';
|
||||
html += '<div class="fieldDescription" style="margin-top:.25em;">' + globalize.translate('LabelMetadataSaversHelp') + '</div>';
|
||||
html += `<div class="fieldDescription" style="margin-top:.25em;">${globalize.translate('LabelMetadataSaversHelp')}</div>`;
|
||||
elem.innerHTML = html;
|
||||
elem.classList.remove('hide');
|
||||
return true;
|
||||
}
|
||||
|
||||
function getMetadataFetchersForTypeHtml(availableTypeOptions, libraryOptionsForType) {
|
||||
var html = '';
|
||||
var plugins = availableTypeOptions.MetadataFetchers;
|
||||
let html = '';
|
||||
let plugins = availableTypeOptions.MetadataFetchers;
|
||||
|
||||
plugins = getOrderedPlugins(plugins, libraryOptionsForType.MetadataFetcherOrder || []);
|
||||
if (!plugins.length) return html;
|
||||
@@ -112,8 +122,8 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
|
||||
plugins.forEach((plugin, index) => {
|
||||
html += '<div class="listItem metadataFetcherItem sortableOption" data-pluginname="' + plugin.Name + '">';
|
||||
var isChecked = libraryOptionsForType.MetadataFetchers ? -1 !== libraryOptionsForType.MetadataFetchers.indexOf(plugin.Name) : plugin.DefaultEnabled;
|
||||
var checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
const isChecked = libraryOptionsForType.MetadataFetchers ? libraryOptionsForType.MetadataFetchers.includes(plugin.Name) : plugin.DefaultEnabled;
|
||||
const checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
html += '<label class="listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" class="chkMetadataFetcher" data-pluginname="' + plugin.Name + '" ' + checkedHtml + '><span></span></label>';
|
||||
html += '<div class="listItemBody">';
|
||||
html += '<h3 class="listItemBodyText">';
|
||||
@@ -121,9 +131,9 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (index > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
} else if (plugins.length > 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + index + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
});
|
||||
@@ -135,19 +145,19 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
}
|
||||
|
||||
function getTypeOptions(allOptions, type) {
|
||||
var allTypeOptions = allOptions.TypeOptions || [];
|
||||
for (var i = 0; i < allTypeOptions.length; i++) {
|
||||
var typeOptions = allTypeOptions[i];
|
||||
const allTypeOptions = allOptions.TypeOptions || [];
|
||||
for (let i = 0; i < allTypeOptions.length; i++) {
|
||||
const typeOptions = allTypeOptions[i];
|
||||
if (typeOptions.Type === type) return typeOptions;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function renderMetadataFetchers(page, availableOptions, libraryOptions) {
|
||||
var html = '';
|
||||
var elem = page.querySelector('.metadataFetchers');
|
||||
for (var i = 0; i < availableOptions.TypeOptions.length; i++) {
|
||||
var availableTypeOptions = availableOptions.TypeOptions[i];
|
||||
let html = '';
|
||||
const elem = page.querySelector('.metadataFetchers');
|
||||
for (let i = 0; i < availableOptions.TypeOptions.length; i++) {
|
||||
const availableTypeOptions = availableOptions.TypeOptions[i];
|
||||
html += getMetadataFetchersForTypeHtml(availableTypeOptions, getTypeOptions(libraryOptions, availableTypeOptions.Type) || {});
|
||||
}
|
||||
elem.innerHTML = html;
|
||||
@@ -166,41 +176,41 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
}
|
||||
|
||||
function renderSubtitleFetchers(page, availableOptions, libraryOptions) {
|
||||
var html = '';
|
||||
var elem = page.querySelector('.subtitleFetchers');
|
||||
let html = '';
|
||||
const elem = page.querySelector('.subtitleFetchers');
|
||||
|
||||
var plugins = availableOptions.SubtitleFetchers;
|
||||
let plugins = availableOptions.SubtitleFetchers;
|
||||
plugins = getOrderedPlugins(plugins, libraryOptions.SubtitleFetcherOrder || []);
|
||||
if (!plugins.length) return html;
|
||||
|
||||
html += '<h3 class="checkboxListLabel">' + globalize.translate('LabelSubtitleDownloaders') + '</h3>';
|
||||
html += `<h3 class="checkboxListLabel">${globalize.translate('LabelSubtitleDownloaders')}</h3>`;
|
||||
html += '<div class="checkboxList paperList checkboxList-paperList">';
|
||||
for (var i = 0; i < plugins.length; i++) {
|
||||
var plugin = plugins[i];
|
||||
html += '<div class="listItem subtitleFetcherItem sortableOption" data-pluginname="' + plugin.Name + '">';
|
||||
var isChecked = libraryOptions.DisabledSubtitleFetchers ? -1 === libraryOptions.DisabledSubtitleFetchers.indexOf(plugin.Name) : plugin.DefaultEnabled;
|
||||
var checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
html += '<label class="listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" class="chkSubtitleFetcher" data-pluginname="' + plugin.Name + '" ' + checkedHtml + '><span></span></label>';
|
||||
for (let i = 0; i < plugins.length; i++) {
|
||||
const plugin = plugins[i];
|
||||
html += `<div class="listItem subtitleFetcherItem sortableOption" data-pluginname="${plugin.Name}">`;
|
||||
const isChecked = libraryOptions.DisabledSubtitleFetchers ? !libraryOptions.DisabledSubtitleFetchers.includes(plugin.Name) : plugin.DefaultEnabled;
|
||||
const checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
html += `<label class="listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" class="chkSubtitleFetcher" data-pluginname="${plugin.Name}" ${checkedHtml}><span></span></label>`;
|
||||
html += '<div class="listItemBody">';
|
||||
html += '<h3 class="listItemBodyText">';
|
||||
html += plugin.Name;
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Up')}" class="btnSortableMoveUp btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_up"></span></button>`;
|
||||
} else if (plugins.length > 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
html += `<button type="button" is="paper-icon-button-light" title="${globalize.translate('Down')}" class="btnSortableMoveDown btnSortable" data-pluginindex="${i}"><span class="material-icons keyboard_arrow_down"></span></button>`;
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '<div class="fieldDescription">' + globalize.translate('SubtitleDownloadersHelp') + '</div>';
|
||||
html += `<div class="fieldDescription">${globalize.translate('SubtitleDownloadersHelp')}</div>`;
|
||||
elem.innerHTML = html;
|
||||
}
|
||||
|
||||
function getImageFetchersForTypeHtml(availableTypeOptions, libraryOptionsForType) {
|
||||
var html = '';
|
||||
var plugins = availableTypeOptions.ImageFetchers;
|
||||
let html = '';
|
||||
let plugins = availableTypeOptions.ImageFetchers;
|
||||
|
||||
plugins = getOrderedPlugins(plugins, libraryOptionsForType.ImageFetcherOrder || []);
|
||||
if (!plugins.length) return html;
|
||||
@@ -208,17 +218,17 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
html += '<div class="imageFetcher" data-type="' + availableTypeOptions.Type + '">';
|
||||
html += '<div class="flex align-items-center" style="margin:1.5em 0 .5em;">';
|
||||
html += '<h3 class="checkboxListLabel" style="margin:0;">' + globalize.translate('HeaderTypeImageFetchers', availableTypeOptions.Type) + '</h3>';
|
||||
var supportedImageTypes = availableTypeOptions.SupportedImageTypes || [];
|
||||
if (supportedImageTypes.length > 1 || 1 === supportedImageTypes.length && 'Primary' !== supportedImageTypes[0]) {
|
||||
const supportedImageTypes = availableTypeOptions.SupportedImageTypes || [];
|
||||
if (supportedImageTypes.length > 1 || supportedImageTypes.length === 1 && supportedImageTypes[0] !== 'Primary') {
|
||||
html += '<button is="emby-button" class="raised btnImageOptionsForType" type="button" style="margin-left:1.5em;font-size:90%;"><span>' + globalize.translate('HeaderFetcherSettings') + '</span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
html += '<div class="checkboxList paperList checkboxList-paperList">';
|
||||
for (var i = 0; i < plugins.length; i++) {
|
||||
var plugin = plugins[i];
|
||||
for (let i = 0; i < plugins.length; i++) {
|
||||
const plugin = plugins[i];
|
||||
html += '<div class="listItem imageFetcherItem sortableOption" data-pluginname="' + plugin.Name + '">';
|
||||
var isChecked = libraryOptionsForType.ImageFetchers ? -1 !== libraryOptionsForType.ImageFetchers.indexOf(plugin.Name) : plugin.DefaultEnabled;
|
||||
var checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
const isChecked = libraryOptionsForType.ImageFetchers ? libraryOptionsForType.ImageFetchers.includes(plugin.Name) : plugin.DefaultEnabled;
|
||||
const checkedHtml = isChecked ? ' checked="checked"' : '';
|
||||
html += '<label class="listItemCheckboxContainer"><input type="checkbox" is="emby-checkbox" class="chkImageFetcher" data-pluginname="' + plugin.Name + '" ' + checkedHtml + '><span></span></label>';
|
||||
html += '<div class="listItemBody">';
|
||||
html += '<h3 class="listItemBodyText">';
|
||||
@@ -226,9 +236,9 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
html += '</h3>';
|
||||
html += '</div>';
|
||||
if (i > 0) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonUp') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Up') + '" class="btnSortableMoveUp btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_up"></span></button>';
|
||||
} else if (plugins.length > 1) {
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('ButtonDown') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
html += '<button type="button" is="paper-icon-button-light" title="' + globalize.translate('Down') + '" class="btnSortableMoveDown btnSortable" data-pluginindex="' + i + '"><span class="material-icons keyboard_arrow_down"></span></button>';
|
||||
}
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -239,10 +249,10 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
}
|
||||
|
||||
function renderImageFetchers(page, availableOptions, libraryOptions) {
|
||||
var html = '';
|
||||
var elem = page.querySelector('.imageFetchers');
|
||||
for (var i = 0; i < availableOptions.TypeOptions.length; i++) {
|
||||
var availableTypeOptions = availableOptions.TypeOptions[i];
|
||||
let html = '';
|
||||
const elem = page.querySelector('.imageFetchers');
|
||||
for (let i = 0; i < availableOptions.TypeOptions.length; i++) {
|
||||
const availableTypeOptions = availableOptions.TypeOptions[i];
|
||||
html += getImageFetchersForTypeHtml(availableTypeOptions, getTypeOptions(libraryOptions, availableTypeOptions.Type) || {});
|
||||
}
|
||||
elem.innerHTML = html;
|
||||
@@ -258,12 +268,12 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
return true;
|
||||
}
|
||||
|
||||
function populateMetadataSettings(parent, contentType, isNewLibrary) {
|
||||
var isNewLibrary = parent.classList.contains('newlibrary');
|
||||
function populateMetadataSettings(parent, contentType) {
|
||||
const isNewLibrary = parent.classList.contains('newlibrary');
|
||||
return ApiClient.getJSON(ApiClient.getUrl('Libraries/AvailableOptions', {
|
||||
LibraryContentType: contentType,
|
||||
IsNewLibrary: isNewLibrary
|
||||
})).then(function(availableOptions) {
|
||||
})).then(availableOptions => {
|
||||
currentAvailableOptions = availableOptions;
|
||||
parent.availableOptions = availableOptions;
|
||||
renderMetadataSavers(parent, availableOptions.MetadataSavers);
|
||||
@@ -272,22 +282,22 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
renderSubtitleFetchers(parent, availableOptions, {});
|
||||
renderImageFetchers(parent, availableOptions, {});
|
||||
availableOptions.SubtitleFetchers.length ? parent.querySelector('.subtitleDownloadSettings').classList.remove('hide') : parent.querySelector('.subtitleDownloadSettings').classList.add('hide');
|
||||
}).catch(function() {
|
||||
}).catch(() => {
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function adjustSortableListElement(elem) {
|
||||
var btnSortable = elem.querySelector('.btnSortable');
|
||||
var inner = btnSortable.querySelector('.material-icons');
|
||||
const btnSortable = elem.querySelector('.btnSortable');
|
||||
const inner = btnSortable.querySelector('.material-icons');
|
||||
if (elem.previousSibling) {
|
||||
btnSortable.title = globalize.translate('ButtonUp');
|
||||
btnSortable.title = globalize.translate('Up');
|
||||
btnSortable.classList.add('btnSortableMoveUp');
|
||||
btnSortable.classList.remove('btnSortableMoveDown');
|
||||
inner.classList.remove('keyboard_arrow_down');
|
||||
inner.classList.add('keyboard_arrow_up');
|
||||
} else {
|
||||
btnSortable.title = globalize.translate('ButtonDown');
|
||||
btnSortable.title = globalize.translate('Down');
|
||||
btnSortable.classList.remove('btnSortableMoveUp');
|
||||
btnSortable.classList.add('btnSortableMoveDown');
|
||||
inner.classList.remove('keyboard_arrow_up');
|
||||
@@ -296,22 +306,22 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
}
|
||||
|
||||
function showImageOptionsForType(type) {
|
||||
require(['imageoptionseditor'], function(ImageOptionsEditor) {
|
||||
var typeOptions = getTypeOptions(currentLibraryOptions, type);
|
||||
import('imageoptionseditor').then(({default: ImageOptionsEditor}) => {
|
||||
let typeOptions = getTypeOptions(currentLibraryOptions, type);
|
||||
if (!typeOptions) {
|
||||
typeOptions = {
|
||||
Type: type
|
||||
};
|
||||
currentLibraryOptions.TypeOptions.push(typeOptions);
|
||||
}
|
||||
var availableOptions = getTypeOptions(currentAvailableOptions || {}, type);
|
||||
var imageOptionsEditor = new ImageOptionsEditor();
|
||||
const availableOptions = getTypeOptions(currentAvailableOptions || {}, type);
|
||||
const imageOptionsEditor = new ImageOptionsEditor();
|
||||
imageOptionsEditor.show(type, typeOptions, availableOptions);
|
||||
});
|
||||
}
|
||||
|
||||
function onImageFetchersContainerClick(e) {
|
||||
var btnImageOptionsForType = dom.parentWithClass(e.target, 'btnImageOptionsForType');
|
||||
const btnImageOptionsForType = dom.parentWithClass(e.target, 'btnImageOptionsForType');
|
||||
if (btnImageOptionsForType) {
|
||||
return void showImageOptionsForType(dom.parentWithClass(btnImageOptionsForType, 'imageFetcher').getAttribute('data-type'));
|
||||
}
|
||||
@@ -319,18 +329,18 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
}
|
||||
|
||||
function onSortableContainerClick(e) {
|
||||
var btnSortable = dom.parentWithClass(e.target, 'btnSortable');
|
||||
const btnSortable = dom.parentWithClass(e.target, 'btnSortable');
|
||||
if (btnSortable) {
|
||||
var li = dom.parentWithClass(btnSortable, 'sortableOption');
|
||||
var list = dom.parentWithClass(li, 'paperList');
|
||||
const li = dom.parentWithClass(btnSortable, 'sortableOption');
|
||||
const list = dom.parentWithClass(li, 'paperList');
|
||||
if (btnSortable.classList.contains('btnSortableMoveDown')) {
|
||||
var next = li.nextSibling;
|
||||
const next = li.nextSibling;
|
||||
if (next) {
|
||||
li.parentNode.removeChild(li);
|
||||
next.parentNode.insertBefore(li, next.nextSibling);
|
||||
}
|
||||
} else {
|
||||
var prev = li.previousSibling;
|
||||
const prev = li.previousSibling;
|
||||
if (prev) {
|
||||
li.parentNode.removeChild(li);
|
||||
prev.parentNode.insertBefore(li, prev);
|
||||
@@ -347,41 +357,35 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
parent.querySelector('.imageFetchers').addEventListener('click', onImageFetchersContainerClick);
|
||||
}
|
||||
|
||||
function embed(parent, contentType, libraryOptions) {
|
||||
export async function embed(parent, contentType, libraryOptions) {
|
||||
currentLibraryOptions = {
|
||||
TypeOptions: []
|
||||
};
|
||||
currentAvailableOptions = null;
|
||||
var isNewLibrary = null === libraryOptions;
|
||||
const isNewLibrary = libraryOptions === null;
|
||||
isNewLibrary && parent.classList.add('newlibrary');
|
||||
return new Promise(function(resolve, reject) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open('GET', 'components/libraryoptionseditor/libraryoptionseditor.template.html', true);
|
||||
xhr.onload = function(e) {
|
||||
var template = this.response;
|
||||
parent.innerHTML = globalize.translateDocument(template);
|
||||
populateRefreshInterval(parent.querySelector('#selectAutoRefreshInterval'));
|
||||
var promises = [populateLanguages(parent), populateCountries(parent.querySelector('#selectCountry'))];
|
||||
Promise.all(promises).then(function() {
|
||||
return setContentType(parent, contentType).then(function() {
|
||||
libraryOptions && setLibraryOptions(parent, libraryOptions);
|
||||
bindEvents(parent);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
xhr.send();
|
||||
const response = await fetch('components/libraryoptionseditor/libraryoptionseditor.template.html');
|
||||
const template = await response.text();
|
||||
parent.innerHTML = globalize.translateHtml(template);
|
||||
populateRefreshInterval(parent.querySelector('#selectAutoRefreshInterval'));
|
||||
const promises = [populateLanguages(parent), populateCountries(parent.querySelector('#selectCountry'))];
|
||||
Promise.all(promises).then(function() {
|
||||
return setContentType(parent, contentType).then(function() {
|
||||
libraryOptions && setLibraryOptions(parent, libraryOptions);
|
||||
bindEvents(parent);
|
||||
return;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setAdvancedVisible(parent, visible) {
|
||||
var elems = parent.querySelectorAll('.advanced');
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
export function setAdvancedVisible(parent, visible) {
|
||||
const elems = parent.querySelectorAll('.advanced');
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
visible ? elems[i].classList.remove('advancedHide') : elems[i].classList.add('advancedHide');
|
||||
}
|
||||
}
|
||||
|
||||
function setContentType(parent, contentType) {
|
||||
export function setContentType(parent, contentType) {
|
||||
if (contentType === 'homevideos' || contentType === 'photos') {
|
||||
parent.querySelector('.chkEnablePhotosContainer').classList.remove('hide');
|
||||
} else {
|
||||
@@ -422,47 +426,47 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
}
|
||||
|
||||
function setSubtitleFetchersIntoOptions(parent, options) {
|
||||
options.DisabledSubtitleFetchers = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkSubtitleFetcher'), function(elem) {
|
||||
options.DisabledSubtitleFetchers = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkSubtitleFetcher'), elem => {
|
||||
return !elem.checked;
|
||||
}), function(elem) {
|
||||
}), elem => {
|
||||
return elem.getAttribute('data-pluginname');
|
||||
});
|
||||
|
||||
options.SubtitleFetcherOrder = Array.prototype.map.call(parent.querySelectorAll('.subtitleFetcherItem'), function(elem) {
|
||||
options.SubtitleFetcherOrder = Array.prototype.map.call(parent.querySelectorAll('.subtitleFetcherItem'), elem => {
|
||||
return elem.getAttribute('data-pluginname');
|
||||
});
|
||||
}
|
||||
|
||||
function setMetadataFetchersIntoOptions(parent, options) {
|
||||
var sections = parent.querySelectorAll('.metadataFetcher');
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
var section = sections[i];
|
||||
var type = section.getAttribute('data-type');
|
||||
var typeOptions = getTypeOptions(options, type);
|
||||
const sections = parent.querySelectorAll('.metadataFetcher');
|
||||
for (let i = 0; i < sections.length; i++) {
|
||||
const section = sections[i];
|
||||
const type = section.getAttribute('data-type');
|
||||
let typeOptions = getTypeOptions(options, type);
|
||||
if (!typeOptions) {
|
||||
typeOptions = {
|
||||
Type: type
|
||||
};
|
||||
options.TypeOptions.push(typeOptions);
|
||||
}
|
||||
typeOptions.MetadataFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll('.chkMetadataFetcher'), function(elem) {
|
||||
typeOptions.MetadataFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll('.chkMetadataFetcher'), elem => {
|
||||
return elem.checked;
|
||||
}), function(elem) {
|
||||
}), elem => {
|
||||
return elem.getAttribute('data-pluginname');
|
||||
});
|
||||
|
||||
typeOptions.MetadataFetcherOrder = Array.prototype.map.call(section.querySelectorAll('.metadataFetcherItem'), function(elem) {
|
||||
typeOptions.MetadataFetcherOrder = Array.prototype.map.call(section.querySelectorAll('.metadataFetcherItem'), elem => {
|
||||
return elem.getAttribute('data-pluginname');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setImageFetchersIntoOptions(parent, options) {
|
||||
var sections = parent.querySelectorAll('.imageFetcher');
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
var section = sections[i];
|
||||
var type = section.getAttribute('data-type');
|
||||
var typeOptions = getTypeOptions(options, type);
|
||||
const sections = parent.querySelectorAll('.imageFetcher');
|
||||
for (let i = 0; i < sections.length; i++) {
|
||||
const section = sections[i];
|
||||
const type = section.getAttribute('data-type');
|
||||
let typeOptions = getTypeOptions(options, type);
|
||||
if (!typeOptions) {
|
||||
typeOptions = {
|
||||
Type: type
|
||||
@@ -470,23 +474,23 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
options.TypeOptions.push(typeOptions);
|
||||
}
|
||||
|
||||
typeOptions.ImageFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll('.chkImageFetcher'), function(elem) {
|
||||
typeOptions.ImageFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll('.chkImageFetcher'), elem => {
|
||||
return elem.checked;
|
||||
}), function(elem) {
|
||||
}), elem => {
|
||||
return elem.getAttribute('data-pluginname');
|
||||
});
|
||||
|
||||
typeOptions.ImageFetcherOrder = Array.prototype.map.call(section.querySelectorAll('.imageFetcherItem'), function(elem) {
|
||||
typeOptions.ImageFetcherOrder = Array.prototype.map.call(section.querySelectorAll('.imageFetcherItem'), elem => {
|
||||
return elem.getAttribute('data-pluginname');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setImageOptionsIntoOptions(parent, options) {
|
||||
var originalTypeOptions = (currentLibraryOptions || {}).TypeOptions || [];
|
||||
for (var i = 0; i < originalTypeOptions.length; i++) {
|
||||
var originalTypeOption = originalTypeOptions[i];
|
||||
var typeOptions = getTypeOptions(options, originalTypeOption.Type);
|
||||
function setImageOptionsIntoOptions(options) {
|
||||
const originalTypeOptions = (currentLibraryOptions || {}).TypeOptions || [];
|
||||
for (let i = 0; i < originalTypeOptions.length; i++) {
|
||||
const originalTypeOption = originalTypeOptions[i];
|
||||
let typeOptions = getTypeOptions(options, originalTypeOption.Type);
|
||||
|
||||
if (!typeOptions) {
|
||||
typeOptions = {
|
||||
@@ -498,8 +502,8 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
}
|
||||
}
|
||||
|
||||
function getLibraryOptions(parent) {
|
||||
var options = {
|
||||
export function getLibraryOptions(parent) {
|
||||
const options = {
|
||||
EnableArchiveMediaFiles: false,
|
||||
EnablePhotos: parent.querySelector('.chkEnablePhotos').checked,
|
||||
EnableRealtimeMonitor: parent.querySelector('.chkEnableRealtimeMonitor').checked,
|
||||
@@ -520,39 +524,39 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
SkipSubtitlesIfAudioTrackMatches: parent.querySelector('#chkSkipIfAudioTrackPresent').checked,
|
||||
SaveSubtitlesWithMedia: parent.querySelector('#chkSaveSubtitlesLocally').checked,
|
||||
RequirePerfectSubtitleMatch: parent.querySelector('#chkRequirePerfectMatch').checked,
|
||||
MetadataSavers: Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkMetadataSaver'), function(elem) {
|
||||
MetadataSavers: Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkMetadataSaver'), elem => {
|
||||
return elem.checked;
|
||||
}), function(elem) {
|
||||
}), elem => {
|
||||
return elem.getAttribute('data-pluginname');
|
||||
}),
|
||||
TypeOptions: []
|
||||
};
|
||||
|
||||
options.LocalMetadataReaderOrder = Array.prototype.map.call(parent.querySelectorAll('.localReaderOption'), function(elem) {
|
||||
options.LocalMetadataReaderOrder = Array.prototype.map.call(parent.querySelectorAll('.localReaderOption'), elem => {
|
||||
return elem.getAttribute('data-pluginname');
|
||||
});
|
||||
options.SubtitleDownloadLanguages = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkSubtitleLanguage'), function(elem) {
|
||||
options.SubtitleDownloadLanguages = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkSubtitleLanguage'), elem => {
|
||||
return elem.checked;
|
||||
}), function(elem) {
|
||||
}), elem => {
|
||||
return elem.getAttribute('data-lang');
|
||||
});
|
||||
setSubtitleFetchersIntoOptions(parent, options);
|
||||
setMetadataFetchersIntoOptions(parent, options);
|
||||
setImageFetchersIntoOptions(parent, options);
|
||||
setImageOptionsIntoOptions(parent, options);
|
||||
setImageOptionsIntoOptions(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function getOrderedPlugins(plugins, configuredOrder) {
|
||||
plugins = plugins.slice(0);
|
||||
plugins.sort(function(a, b) {
|
||||
plugins.sort((a, b) => {
|
||||
return a = configuredOrder.indexOf(a.Name), b = configuredOrder.indexOf(b.Name), a < b ? -1 : a > b ? 1 : 0;
|
||||
});
|
||||
return plugins;
|
||||
}
|
||||
|
||||
function setLibraryOptions(parent, options) {
|
||||
export function setLibraryOptions(parent, options) {
|
||||
currentLibraryOptions = options;
|
||||
currentAvailableOptions = parent.availableOptions;
|
||||
parent.querySelector('#selectLanguage').value = options.PreferredMetadataLanguage || '';
|
||||
@@ -573,11 +577,11 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
parent.querySelector('#chkSaveSubtitlesLocally').checked = options.SaveSubtitlesWithMedia;
|
||||
parent.querySelector('#chkSkipIfAudioTrackPresent').checked = options.SkipSubtitlesIfAudioTrackMatches;
|
||||
parent.querySelector('#chkRequirePerfectMatch').checked = options.RequirePerfectSubtitleMatch;
|
||||
Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), function(elem) {
|
||||
elem.checked = options.MetadataSavers ? -1 !== options.MetadataSavers.indexOf(elem.getAttribute('data-pluginname')) : 'true' === elem.getAttribute('data-defaultenabled');
|
||||
Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), elem => {
|
||||
elem.checked = options.MetadataSavers ? options.MetadataSavers.includes(elem.getAttribute('data-pluginname')) : elem.getAttribute('data-defaultenabled') === 'true';
|
||||
});
|
||||
Array.prototype.forEach.call(parent.querySelectorAll('.chkSubtitleLanguage'), function(elem) {
|
||||
elem.checked = !!options.SubtitleDownloadLanguages && -1 !== options.SubtitleDownloadLanguages.indexOf(elem.getAttribute('data-lang'));
|
||||
Array.prototype.forEach.call(parent.querySelectorAll('.chkSubtitleLanguage'), elem => {
|
||||
elem.checked = !!options.SubtitleDownloadLanguages && options.SubtitleDownloadLanguages.includes(elem.getAttribute('data-lang'));
|
||||
});
|
||||
renderMetadataReaders(parent, getOrderedPlugins(parent.availableOptions.MetadataReaders, options.LocalMetadataReaderOrder || []));
|
||||
renderMetadataFetchers(parent, parent.availableOptions, options);
|
||||
@@ -585,14 +589,14 @@ define(['globalize', 'dom', 'emby-checkbox', 'emby-select', 'emby-input'], funct
|
||||
renderSubtitleFetchers(parent, parent.availableOptions, options);
|
||||
}
|
||||
|
||||
var currentLibraryOptions;
|
||||
var currentAvailableOptions;
|
||||
let currentLibraryOptions;
|
||||
let currentAvailableOptions;
|
||||
|
||||
return {
|
||||
embed: embed,
|
||||
setContentType: setContentType,
|
||||
getLibraryOptions: getLibraryOptions,
|
||||
setLibraryOptions: setLibraryOptions,
|
||||
setAdvancedVisible: setAdvancedVisible
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
embed: embed,
|
||||
setContentType: setContentType,
|
||||
getLibraryOptions: getLibraryOptions,
|
||||
setLibraryOptions: setLibraryOptions,
|
||||
setAdvancedVisible: setAdvancedVisible
|
||||
};
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription chkAutomaticallyGroupSeriesContainer hide advanced">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkAutomaticallyGroupSeries" checked />
|
||||
<input type="checkbox" is="emby-checkbox" class="chkAutomaticallyGroupSeries" />
|
||||
<span>${OptionAutomaticallyGroupSeries}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${OptionAutomaticallyGroupSeriesHelp}</div>
|
||||
@@ -88,7 +88,7 @@
|
||||
<div class="checkboxContainer checkboxContainer-withDescription hide chkImportMissingEpisodesContainer advanced">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="chkImportMissingEpisodes" />
|
||||
<span>${LabelDisplayMissingEpisodesWithinSeasons}</span>
|
||||
<span>${DisplayMissingEpisodesWithinSeasons}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${ImportMissingEpisodesHelp}</div>
|
||||
</div>
|
||||
|
||||
+109
-140
@@ -1,19 +1,31 @@
|
||||
define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutManager', 'globalize', 'datetime', 'apphost', 'css!./listview', 'emby-ratingbutton', 'emby-playstatebutton'], function (itemHelper, mediaInfo, indicators, connectionManager, layoutManager, globalize, datetime, appHost) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for display list view.
|
||||
* @module components/listview/listview
|
||||
*/
|
||||
|
||||
import itemHelper from 'itemHelper';
|
||||
import mediaInfo from 'mediaInfo';
|
||||
import indicators from 'indicators';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import datetime from 'datetime';
|
||||
import cardBuilder from 'cardBuilder';
|
||||
import 'css!./listview';
|
||||
import 'emby-ratingbutton';
|
||||
import 'emby-playstatebutton';
|
||||
|
||||
function getIndex(item, options) {
|
||||
|
||||
if (options.index === 'disc') {
|
||||
|
||||
return item.ParentIndexNumber == null ? '' : globalize.translate('ValueDiscNumber', item.ParentIndexNumber);
|
||||
}
|
||||
|
||||
var sortBy = (options.sortBy || '').toLowerCase();
|
||||
var code;
|
||||
var name;
|
||||
const sortBy = (options.sortBy || '').toLowerCase();
|
||||
let code;
|
||||
let name;
|
||||
|
||||
if (sortBy.indexOf('sortname') === 0) {
|
||||
|
||||
if (item.Type === 'Episode') {
|
||||
return '';
|
||||
}
|
||||
@@ -29,11 +41,9 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
return name.toUpperCase();
|
||||
}
|
||||
if (sortBy.indexOf('officialrating') === 0) {
|
||||
|
||||
return item.OfficialRating || globalize.translate('Unrated');
|
||||
}
|
||||
if (sortBy.indexOf('communityrating') === 0) {
|
||||
|
||||
if (item.CommunityRating == null) {
|
||||
return globalize.translate('Unrated');
|
||||
}
|
||||
@@ -41,7 +51,6 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
return Math.floor(item.CommunityRating);
|
||||
}
|
||||
if (sortBy.indexOf('criticrating') === 0) {
|
||||
|
||||
if (item.CriticRating == null) {
|
||||
return globalize.translate('Unrated');
|
||||
}
|
||||
@@ -49,7 +58,6 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
return Math.floor(item.CriticRating);
|
||||
}
|
||||
if (sortBy.indexOf('albumartist') === 0) {
|
||||
|
||||
// SortName
|
||||
if (!item.AlbumArtist) {
|
||||
return '';
|
||||
@@ -68,73 +76,63 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
|
||||
function getImageUrl(item, width) {
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
let itemId;
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
var options = {
|
||||
maxWidth: width * 2,
|
||||
const options = {
|
||||
maxWidth: width,
|
||||
type: 'Primary'
|
||||
};
|
||||
|
||||
if (item.ImageTags && item.ImageTags.Primary) {
|
||||
|
||||
options.tag = item.ImageTags.Primary;
|
||||
return apiClient.getScaledImageUrl(item.Id, options);
|
||||
}
|
||||
|
||||
if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
itemId = item.Id;
|
||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
return apiClient.getScaledImageUrl(item.AlbumId, options);
|
||||
itemId = item.AlbumId;
|
||||
} else if (item.SeriesId && item.SeriesPrimaryImageTag) {
|
||||
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
return apiClient.getScaledImageUrl(item.SeriesId, options);
|
||||
|
||||
itemId = item.SeriesId;
|
||||
} else if (item.ParentPrimaryImageTag) {
|
||||
|
||||
options.tag = item.ParentPrimaryImageTag;
|
||||
return apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, options);
|
||||
itemId = item.ParentPrimaryImageItemId;
|
||||
}
|
||||
|
||||
if (itemId) {
|
||||
return apiClient.getScaledImageUrl(itemId, options);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getChannelImageUrl(item, width) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(item.ServerId);
|
||||
|
||||
var options = {
|
||||
maxWidth: width * 2,
|
||||
const apiClient = window.connectionManager.getApiClient(item.ServerId);
|
||||
const options = {
|
||||
maxWidth: width,
|
||||
type: 'Primary'
|
||||
};
|
||||
|
||||
if (item.ChannelId && item.ChannelPrimaryImageTag) {
|
||||
|
||||
options.tag = item.ChannelPrimaryImageTag;
|
||||
return apiClient.getScaledImageUrl(item.ChannelId, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
if (item.ChannelId) {
|
||||
return apiClient.getScaledImageUrl(item.ChannelId, options);
|
||||
}
|
||||
}
|
||||
|
||||
function getTextLinesHtml(textlines, isLargeStyle) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
|
||||
var largeTitleTagName = layoutManager.tv ? 'h2' : 'div';
|
||||
|
||||
for (var i = 0, length = textlines.length; i < length; i++) {
|
||||
|
||||
var text = textlines[i];
|
||||
const largeTitleTagName = layoutManager.tv ? 'h2' : 'div';
|
||||
|
||||
for (const [i, text] of textlines.entries()) {
|
||||
if (!text) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
if (isLargeStyle) {
|
||||
html += '<' + largeTitleTagName + ' class="listItemBodyText">';
|
||||
html += `<${largeTitleTagName} class="listItemBodyText">`;
|
||||
} else {
|
||||
html += '<div class="listItemBodyText">';
|
||||
}
|
||||
@@ -143,7 +141,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
html += (textlines[i] || ' ');
|
||||
if (i === 0 && isLargeStyle) {
|
||||
html += '</' + largeTitleTagName + '>';
|
||||
html += `</${largeTitleTagName}>`;
|
||||
} else {
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -153,14 +151,12 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
|
||||
function getRightButtonsHtml(options) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
for (let i = 0, length = options.rightButtons.length; i < length; i++) {
|
||||
const button = options.rightButtons[i];
|
||||
|
||||
for (var i = 0, length = options.rightButtons.length; i < length; i++) {
|
||||
|
||||
var 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;
|
||||
@@ -170,37 +166,33 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
return item.Id;
|
||||
}
|
||||
|
||||
function getListViewHtml(options) {
|
||||
export function getListViewHtml(options) {
|
||||
const items = options.items;
|
||||
|
||||
var items = options.items;
|
||||
let groupTitle = '';
|
||||
const action = options.action || 'link';
|
||||
|
||||
var groupTitle = '';
|
||||
var action = options.action || 'link';
|
||||
const isLargeStyle = options.imageSize === 'large';
|
||||
const enableOverview = options.enableOverview;
|
||||
|
||||
var isLargeStyle = options.imageSize === 'large';
|
||||
var enableOverview = options.enableOverview;
|
||||
const clickEntireItem = layoutManager.tv ? true : false;
|
||||
const outerTagName = clickEntireItem ? 'button' : 'div';
|
||||
const enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : true;
|
||||
|
||||
var clickEntireItem = layoutManager.tv ? true : false;
|
||||
var outerTagName = clickEntireItem ? 'button' : 'div';
|
||||
var enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : true;
|
||||
let outerHtml = '';
|
||||
|
||||
var outerHtml = '';
|
||||
const enableContentWrapper = options.enableOverview && !layoutManager.tv;
|
||||
const containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId);
|
||||
|
||||
var enableContentWrapper = options.enableOverview && !layoutManager.tv;
|
||||
var containerAlbumArtistIds = (options.containerAlbumArtists || []).map(getId);
|
||||
for (let i = 0, length = items.length; i < length; i++) {
|
||||
const item = items[i];
|
||||
|
||||
for (var i = 0, length = items.length; i < length; i++) {
|
||||
|
||||
var item = items[i];
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
if (options.showIndex) {
|
||||
|
||||
var itemGroupTitle = getIndex(item, options);
|
||||
const itemGroupTitle = getIndex(item, options);
|
||||
|
||||
if (itemGroupTitle !== groupTitle) {
|
||||
|
||||
if (html) {
|
||||
html += '</div>';
|
||||
}
|
||||
@@ -219,7 +211,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
}
|
||||
|
||||
var cssClass = 'listItem';
|
||||
let cssClass = 'listItem';
|
||||
|
||||
if (options.border || (options.highlight !== false && !layoutManager.tv)) {
|
||||
cssClass += ' listItem-border';
|
||||
@@ -233,37 +225,33 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
cssClass += ' listItem-focusscale';
|
||||
}
|
||||
|
||||
var downloadWidth = 80;
|
||||
let downloadWidth = 80;
|
||||
|
||||
if (isLargeStyle) {
|
||||
cssClass += ' listItem-largeImage';
|
||||
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 + '"') : '';
|
||||
var collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : '';
|
||||
var playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : '';
|
||||
var mediaTypeData = item.MediaType ? (' data-mediatype="' + item.MediaType + '"') : '';
|
||||
var collectionTypeData = item.CollectionType ? (' data-collectiontype="' + item.CollectionType + '"') : '';
|
||||
var channelIdData = item.ChannelId ? (' data-channelid="' + item.ChannelId + '"') : '';
|
||||
const positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (` data-positionticks="${item.UserData.PlaybackPositionTicks}"`) : '';
|
||||
const collectionIdData = options.collectionId ? (` data-collectionid="${options.collectionId}"`) : '';
|
||||
const playlistIdData = options.playlistId ? (` data-playlistid="${options.playlistId}"`) : '';
|
||||
const mediaTypeData = item.MediaType ? (` data-mediatype="${item.MediaType}"`) : '';
|
||||
const collectionTypeData = item.CollectionType ? (` data-collectiontype="${item.CollectionType}"`) : '';
|
||||
const channelIdData = item.ChannelId ? (` data-channelid="${item.ChannelId}"`) : '';
|
||||
|
||||
if (enableContentWrapper) {
|
||||
|
||||
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) {
|
||||
|
||||
html += '<div class="listItem-content">';
|
||||
}
|
||||
|
||||
if (!clickEntireItem && options.dragHandle) {
|
||||
//html += '<button is="paper-icon-button-light" class="listViewDragHandle listItemButton"><span class="material-icons drag_handle"></span></button>';
|
||||
// Firefox and Edge are not allowing the button to be draggable
|
||||
html += '<span class="listViewDragHandle material-icons listItemIcon listItemIcon-transparent drag_handle"></span>';
|
||||
}
|
||||
|
||||
@@ -275,32 +263,32 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
imageClass += ' listItemImage-large-tv';
|
||||
}
|
||||
|
||||
var playOnImageClick = options.imagePlayButton && !layoutManager.tv;
|
||||
const playOnImageClick = options.imagePlayButton && !layoutManager.tv;
|
||||
|
||||
if (!clickEntireItem) {
|
||||
imageClass += ' itemAction';
|
||||
}
|
||||
|
||||
var imageAction = playOnImageClick ? 'resume' : action;
|
||||
const imageAction = playOnImageClick ? 'link' : action;
|
||||
|
||||
if (imgUrl) {
|
||||
html += '<div data-action="' + imageAction + '" class="' + imageClass + ' lazy" data-src="' + imgUrl + '" item-icon>';
|
||||
} else {
|
||||
html += '<div class="' + imageClass + '">';
|
||||
html += '<div class="' + imageClass + ' cardImageContainer ' + cardBuilder.getDefaultBackgroundClass(item.Name) + '">' + cardBuilder.getDefaultText(item, options);
|
||||
}
|
||||
|
||||
var indicatorsHtml = '';
|
||||
let indicatorsHtml = '';
|
||||
indicatorsHtml += indicators.getPlayedIndicatorHtml(item);
|
||||
|
||||
if (indicatorsHtml) {
|
||||
html += '<div class="indicators listItemIndicators">' + indicatorsHtml + '</div>';
|
||||
html += `<div class="indicators listItemIndicators">${indicatorsHtml}</div>`;
|
||||
}
|
||||
|
||||
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>';
|
||||
}
|
||||
|
||||
var progressHtml = indicators.getProgressBarHtml(item, {
|
||||
const progressHtml = indicators.getProgressBarHtml(item, {
|
||||
containerClass: 'listItemProgressBar'
|
||||
});
|
||||
|
||||
@@ -311,13 +299,12 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
|
||||
if (options.showIndexNumberLeft) {
|
||||
|
||||
html += '<div class="listItem-indexnumberleft">';
|
||||
html += (item.IndexNumber || ' ');
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
var textlines = [];
|
||||
const textlines = [];
|
||||
|
||||
if (options.showProgramDateTime) {
|
||||
textlines.push(datetime.toLocaleString(datetime.parseISO8601Date(item.StartDate), {
|
||||
@@ -340,7 +327,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
}
|
||||
|
||||
var parentTitle = null;
|
||||
let parentTitle = null;
|
||||
|
||||
if (options.showParentTitle) {
|
||||
if (item.Type === 'Episode') {
|
||||
@@ -350,18 +337,16 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
}
|
||||
|
||||
var displayName = itemHelper.getDisplayName(item, {
|
||||
let displayName = itemHelper.getDisplayName(item, {
|
||||
includeParentInfo: options.includeParentInfoInTitle
|
||||
});
|
||||
|
||||
if (options.showIndexNumber && item.IndexNumber != null) {
|
||||
displayName = item.IndexNumber + '. ' + displayName;
|
||||
displayName = `${item.IndexNumber}. ${displayName}`;
|
||||
}
|
||||
|
||||
if (options.showParentTitle && options.parentTitleWithTitle) {
|
||||
|
||||
if (displayName) {
|
||||
|
||||
if (parentTitle) {
|
||||
parentTitle += ' - ';
|
||||
}
|
||||
@@ -379,29 +364,15 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
|
||||
if (item.IsFolder) {
|
||||
if (options.artist !== false) {
|
||||
|
||||
if (item.AlbumArtist && item.Type === 'MusicAlbum') {
|
||||
textlines.push(item.AlbumArtist);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
var showArtist = options.artist === true;
|
||||
var artistItems = item.ArtistItems;
|
||||
|
||||
if (!showArtist && options.artist !== false) {
|
||||
|
||||
if (!artistItems || !artistItems.length) {
|
||||
showArtist = true;
|
||||
} else if (artistItems.length > 1 || containerAlbumArtistIds.indexOf(artistItems[0].Id) === -1) {
|
||||
showArtist = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (showArtist) {
|
||||
|
||||
if (options.artist) {
|
||||
const artistItems = item.ArtistItems;
|
||||
if (artistItems && item.Type !== 'MusicAlbum') {
|
||||
textlines.push(artistItems.map(function (a) {
|
||||
textlines.push(artistItems.map(a => {
|
||||
return a.Name;
|
||||
}).join(', '));
|
||||
}
|
||||
@@ -409,7 +380,6 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
|
||||
if (item.Type === 'TvChannel') {
|
||||
|
||||
if (item.CurrentProgram) {
|
||||
textlines.push(itemHelper.getDisplayName(item.CurrentProgram));
|
||||
}
|
||||
@@ -424,23 +394,22 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
cssClass += ' listItemBody-noleftpadding';
|
||||
}
|
||||
|
||||
html += '<div class="' + cssClass + '">';
|
||||
|
||||
const moreIcon = 'more_vert';
|
||||
html += `<div class="${cssClass}">`;
|
||||
|
||||
html += getTextLinesHtml(textlines, isLargeStyle);
|
||||
|
||||
if (options.mediaInfo !== false) {
|
||||
if (!enableSideMediaInfo) {
|
||||
const mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText';
|
||||
|
||||
var mediaInfoClass = 'secondary listItemMediaInfo listItemBodyText';
|
||||
|
||||
html += '<div class="' + mediaInfoClass + '">' + mediaInfo.getPrimaryMediaInfoHtml(item, {
|
||||
html += `<div class="${mediaInfoClass}">`;
|
||||
html += mediaInfo.getPrimaryMediaInfoHtml(item, {
|
||||
episodeTitle: false,
|
||||
originalAirDate: false,
|
||||
subtitles: false
|
||||
|
||||
}) + '</div>';
|
||||
});
|
||||
html += '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,7 +423,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
|
||||
if (options.mediaInfo !== false) {
|
||||
if (enableSideMediaInfo) {
|
||||
html += '<div class="secondary listItemMediaInfo">' + mediaInfo.getPrimaryMediaInfoHtml(item, {
|
||||
html += '<div class="secondary listItemMediaInfo">';
|
||||
html += mediaInfo.getPrimaryMediaInfoHtml(item, {
|
||||
|
||||
year: false,
|
||||
container: false,
|
||||
@@ -462,7 +432,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
criticRating: false,
|
||||
endsAt: false
|
||||
|
||||
}) + '</div>';
|
||||
});
|
||||
html += '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,15 +444,10 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
html += '<div class="listViewUserDataButtons">';
|
||||
|
||||
if (!clickEntireItem) {
|
||||
|
||||
if (options.addToListButton) {
|
||||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="addtoplaylist"><span class="material-icons playlist_add"></span></button>';
|
||||
}
|
||||
|
||||
if (options.moreButton !== false) {
|
||||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="menu"><span class="material-icons ' + moreIcon + '"></span></button>';
|
||||
}
|
||||
|
||||
if (options.infoButton) {
|
||||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="link"><span class="material-icons info_outline"></span></button>';
|
||||
}
|
||||
@@ -491,18 +457,21 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
|
||||
if (options.enableUserDataButtons !== false) {
|
||||
const userData = item.UserData || {};
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
var userData = item.UserData || {};
|
||||
var likes = userData.Likes == null ? '' : userData.Likes;
|
||||
|
||||
if (itemHelper.canMarkPlayed(item)) {
|
||||
if (itemHelper.canMarkPlayed(item) && options.enablePlayedButton !== false) {
|
||||
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) && options.enableRatingButton !== false) {
|
||||
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>';
|
||||
}
|
||||
}
|
||||
|
||||
if (options.moreButton !== false) {
|
||||
html += '<button is="paper-icon-button-light" class="listItemButton itemAction" data-action="menu"><span class="material-icons more_vert"></span></button>';
|
||||
}
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
@@ -516,7 +485,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
}
|
||||
}
|
||||
|
||||
html += '</' + outerTagName + '>';
|
||||
html += `</${outerTagName}>`;
|
||||
|
||||
outerHtml += html;
|
||||
}
|
||||
@@ -524,7 +493,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan
|
||||
return outerHtml;
|
||||
}
|
||||
|
||||
return {
|
||||
getListViewHtml: getListViewHtml
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
getListViewHtml: getListViewHtml
|
||||
};
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,84 +1,74 @@
|
||||
define(['components/loading/loadingLegacy', 'browser', 'css!./loading'], function (loadingLegacy, browser) {
|
||||
'use strict';
|
||||
import 'css!./loading';
|
||||
|
||||
if (browser.tizen || browser.operaTv || browser.chromecast || browser.orsay || browser.web0s || browser.ps4) {
|
||||
return loadingLegacy;
|
||||
let loadingElem;
|
||||
let layer1;
|
||||
let layer2;
|
||||
let layer3;
|
||||
let layer4;
|
||||
let circleLefts;
|
||||
let circleRights;
|
||||
|
||||
export function show() {
|
||||
let elem = loadingElem;
|
||||
|
||||
if (!elem) {
|
||||
elem = document.createElement('div');
|
||||
loadingElem = elem;
|
||||
|
||||
elem.classList.add('docspinner');
|
||||
elem.classList.add('mdl-spinner');
|
||||
|
||||
elem.innerHTML = '<div class="mdl-spinner__layer mdl-spinner__layer-1"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-2"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-3"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-4"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div>';
|
||||
|
||||
document.body.appendChild(elem);
|
||||
|
||||
layer1 = elem.querySelector('.mdl-spinner__layer-1');
|
||||
layer2 = elem.querySelector('.mdl-spinner__layer-2');
|
||||
layer3 = elem.querySelector('.mdl-spinner__layer-3');
|
||||
layer4 = elem.querySelector('.mdl-spinner__layer-4');
|
||||
|
||||
circleLefts = elem.querySelectorAll('.mdl-spinner__circleLeft');
|
||||
circleRights = elem.querySelectorAll('.mdl-spinner__circleRight');
|
||||
}
|
||||
|
||||
var loadingElem;
|
||||
var layer1;
|
||||
var layer2;
|
||||
var layer3;
|
||||
var layer4;
|
||||
var circleLefts;
|
||||
var circleRights;
|
||||
elem.classList.add('mdlSpinnerActive');
|
||||
|
||||
return {
|
||||
show: function () {
|
||||
var elem = loadingElem;
|
||||
layer1.classList.add('mdl-spinner__layer-1-active');
|
||||
layer2.classList.add('mdl-spinner__layer-2-active');
|
||||
layer3.classList.add('mdl-spinner__layer-3-active');
|
||||
layer4.classList.add('mdl-spinner__layer-4-active');
|
||||
|
||||
if (!elem) {
|
||||
for (let i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.add('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
|
||||
elem = document.createElement('div');
|
||||
loadingElem = elem;
|
||||
for (let i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.add('mdl-spinner__circleRight-active');
|
||||
}
|
||||
}
|
||||
|
||||
elem.classList.add('docspinner');
|
||||
elem.classList.add('mdl-spinner');
|
||||
export function hide() {
|
||||
const elem = loadingElem;
|
||||
|
||||
elem.innerHTML = '<div class="mdl-spinner__layer mdl-spinner__layer-1"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-2"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-3"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div><div class="mdl-spinner__layer mdl-spinner__layer-4"><div class="mdl-spinner__circle-clipper mdl-spinner__left"><div class="mdl-spinner__circle mdl-spinner__circleLeft"></div></div><div class="mdl-spinner__circle-clipper mdl-spinner__right"><div class="mdl-spinner__circle mdl-spinner__circleRight"></div></div></div>';
|
||||
if (elem) {
|
||||
elem.classList.remove('mdlSpinnerActive');
|
||||
|
||||
document.body.appendChild(elem);
|
||||
elem.classList.remove('mdl-spinner__layer-1-active');
|
||||
elem.classList.remove('mdl-spinner__layer-2-active');
|
||||
elem.classList.remove('mdl-spinner__layer-3-active');
|
||||
elem.classList.remove('mdl-spinner__layer-4-active');
|
||||
|
||||
layer1 = elem.querySelector('.mdl-spinner__layer-1');
|
||||
layer2 = elem.querySelector('.mdl-spinner__layer-2');
|
||||
layer3 = elem.querySelector('.mdl-spinner__layer-3');
|
||||
layer4 = elem.querySelector('.mdl-spinner__layer-4');
|
||||
|
||||
circleLefts = elem.querySelectorAll('.mdl-spinner__circleLeft');
|
||||
circleRights = elem.querySelectorAll('.mdl-spinner__circleRight');
|
||||
}
|
||||
|
||||
elem.classList.add('mdlSpinnerActive');
|
||||
|
||||
layer1.classList.add('mdl-spinner__layer-1-active');
|
||||
layer2.classList.add('mdl-spinner__layer-2-active');
|
||||
layer3.classList.add('mdl-spinner__layer-3-active');
|
||||
layer4.classList.add('mdl-spinner__layer-4-active');
|
||||
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.add('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
|
||||
for (i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.add('mdl-spinner__circleRight-active');
|
||||
}
|
||||
},
|
||||
hide: function () {
|
||||
var elem = loadingElem;
|
||||
|
||||
if (elem) {
|
||||
|
||||
elem.classList.remove('mdlSpinnerActive');
|
||||
|
||||
elem.classList.remove('mdl-spinner__layer-1-active');
|
||||
elem.classList.remove('mdl-spinner__layer-2-active');
|
||||
elem.classList.remove('mdl-spinner__layer-3-active');
|
||||
elem.classList.remove('mdl-spinner__layer-4-active');
|
||||
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.remove('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
|
||||
for (i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.remove('mdl-spinner__circleRight-active');
|
||||
}
|
||||
}
|
||||
for (let i = 0, length = circleLefts.length; i < length; i++) {
|
||||
circleLefts[i].classList.remove('mdl-spinner__circleLeft-active');
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
for (let i = 0, length = circleRights.length; i < length; i++) {
|
||||
circleRights[i].classList.remove('mdl-spinner__circleRight-active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
show: show,
|
||||
hide: hide
|
||||
};
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
.loading-spinner {
|
||||
margin-top: -3em;
|
||||
margin-left: -3em;
|
||||
width: 6em;
|
||||
height: 6em;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 9999999;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
define(['require', 'css!./loadingLegacy'], function (require) {
|
||||
'use strict';
|
||||
|
||||
var loadingElem;
|
||||
|
||||
return {
|
||||
show: function () {
|
||||
var elem = loadingElem;
|
||||
if (!elem) {
|
||||
elem = document.createElement('img');
|
||||
elem.src = require.toUrl('.').split('?')[0] + '/loader.gif';
|
||||
|
||||
loadingElem = elem;
|
||||
elem.classList.add('loading-spinner');
|
||||
|
||||
document.body.appendChild(elem);
|
||||
}
|
||||
|
||||
elem.classList.remove('hide');
|
||||
},
|
||||
hide: function () {
|
||||
var elem = loadingElem;
|
||||
if (elem) {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -1,192 +0,0 @@
|
||||
define(['pluginManager'], function (pluginManager) {
|
||||
|
||||
return function () {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.name = 'Logo ScreenSaver';
|
||||
self.type = 'screensaver';
|
||||
self.id = 'logoscreensaver';
|
||||
self.supportsAnonymous = true;
|
||||
|
||||
var interval;
|
||||
|
||||
function animate() {
|
||||
|
||||
var animations = [
|
||||
|
||||
bounceInLeft,
|
||||
bounceInRight,
|
||||
swing,
|
||||
tada,
|
||||
wobble,
|
||||
rotateIn,
|
||||
rotateOut
|
||||
];
|
||||
|
||||
var elem = document.querySelector('.logoScreenSaverImage');
|
||||
|
||||
if (elem && elem.animate) {
|
||||
var random = getRandomInt(0, animations.length - 1);
|
||||
|
||||
animations[random](elem, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
function bounceInLeft(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 },
|
||||
{ transform: 'translate3d(25px, 0, 0)', opacity: '1', offset: 0.6 },
|
||||
{ transform: 'translate3d(-100px, 0, 0)', offset: 0.75 },
|
||||
{ transform: 'translate3d(5px, 0, 0)', offset: 0.9 },
|
||||
{ transform: 'none', opacity: '1', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function bounceInRight(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate3d(3000px, 0, 0)', opacity: '0', offset: 0 },
|
||||
{ transform: 'translate3d(-25px, 0, 0)', opacity: '1', offset: 0.6 },
|
||||
{ transform: 'translate3d(100px, 0, 0)', offset: 0.75 },
|
||||
{ transform: 'translate3d(-5px, 0, 0)', offset: 0.9 },
|
||||
{ transform: 'none', opacity: '1', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function shake(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate3d(0, 0, 0)', offset: 0 },
|
||||
{ transform: 'translate3d(-10px, 0, 0)', offset: 0.1 },
|
||||
{ transform: 'translate3d(10px, 0, 0)', offset: 0.2 },
|
||||
{ transform: 'translate3d(-10px, 0, 0)', offset: 0.3 },
|
||||
{ transform: 'translate3d(10px, 0, 0)', offset: 0.4 },
|
||||
{ transform: 'translate3d(-10px, 0, 0)', offset: 0.5 },
|
||||
{ transform: 'translate3d(10px, 0, 0)', offset: 0.6 },
|
||||
{ transform: 'translate3d(-10px, 0, 0)', offset: 0.7 },
|
||||
{ transform: 'translate3d(10px, 0, 0)', offset: 0.8 },
|
||||
{ transform: 'translate3d(-10px, 0, 0)', offset: 0.9 },
|
||||
{ transform: 'translate3d(0, 0, 0)', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function swing(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate(0%)', offset: 0 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 },
|
||||
{ transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 },
|
||||
{ transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function tada(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'scale3d(1, 1, 1)', offset: 0 },
|
||||
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.1 },
|
||||
{ transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.2 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.3 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.4 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.5 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.6 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.7 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.8 },
|
||||
{ transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.9 },
|
||||
{ transform: 'scale3d(1, 1, 1)', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function wobble(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ transform: 'translate(0%)', offset: 0 },
|
||||
{ transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', offset: 0.15 },
|
||||
{ transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', offset: 0.45 },
|
||||
{ transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', offset: 0.6 },
|
||||
{ transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', offset: 0.75 },
|
||||
{ transform: 'translateX(0%)', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function rotateIn(elem, iterations) {
|
||||
var transformOrigin = elem.style['transform-origin'];
|
||||
var keyframes = [{ transform: 'rotate3d(0, 0, 1, -200deg)', opacity: '0', transformOrigin: 'center', offset: 0 },
|
||||
{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function rotateOut(elem, iterations) {
|
||||
var transformOrigin = elem.style['transform-origin'];
|
||||
var keyframes = [{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 0 },
|
||||
{ transform: 'rotate3d(0, 0, 1, 200deg)', opacity: '0', transformOrigin: 'center', offset: 1 }];
|
||||
var timing = { duration: 900, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
|
||||
}
|
||||
|
||||
function fadeOut(elem, iterations) {
|
||||
var keyframes = [
|
||||
{ opacity: '1', offset: 0 },
|
||||
{ opacity: '0', offset: 1 }];
|
||||
var timing = { duration: 400, iterations: iterations };
|
||||
return elem.animate(keyframes, timing);
|
||||
}
|
||||
|
||||
function stopInterval() {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
}
|
||||
}
|
||||
|
||||
self.show = function () {
|
||||
|
||||
require(['css!' + pluginManager.mapPath(self, 'style.css')], function () {
|
||||
|
||||
var elem = document.querySelector('.logoScreenSaver');
|
||||
|
||||
if (!elem) {
|
||||
elem = document.createElement('div');
|
||||
elem.classList.add('logoScreenSaver');
|
||||
document.body.appendChild(elem);
|
||||
|
||||
elem.innerHTML = '<img class="logoScreenSaverImage" src="assets/img/banner-light.png" />';
|
||||
}
|
||||
|
||||
stopInterval();
|
||||
interval = setInterval(animate, 3000);
|
||||
});
|
||||
};
|
||||
|
||||
self.hide = function () {
|
||||
|
||||
stopInterval();
|
||||
|
||||
var elem = document.querySelector('.logoScreenSaver');
|
||||
|
||||
if (elem) {
|
||||
|
||||
var onAnimationFinish = function () {
|
||||
elem.parentNode.removeChild(elem);
|
||||
};
|
||||
|
||||
if (elem.animate) {
|
||||
var animation = fadeOut(elem, 1);
|
||||
animation.onfinish = onAnimationFinish;
|
||||
} else {
|
||||
onAnimationFinish();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
@@ -1,31 +1,17 @@
|
||||
define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom, browser, events) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import browser from 'browser';
|
||||
import events from 'events';
|
||||
import 'emby-tabs';
|
||||
import 'emby-button';
|
||||
|
||||
var tabOwnerView;
|
||||
var queryScope = document.querySelector('.skinHeader');
|
||||
var footerTabsContainer;
|
||||
var headerTabsContainer;
|
||||
var tabsElem;
|
||||
/* eslint-disable indent */
|
||||
|
||||
function enableTabsInFooter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getTabsContainerElem() {
|
||||
}
|
||||
|
||||
function ensureElements(enableInFooter) {
|
||||
|
||||
if (enableInFooter) {
|
||||
if (!footerTabsContainer) {
|
||||
footerTabsContainer = document.createElement('div');
|
||||
footerTabsContainer.classList.add('footerTabs');
|
||||
footerTabsContainer.classList.add('sectionTabs');
|
||||
footerTabsContainer.classList.add('hide');
|
||||
//appFooter.add(footerTabsContainer);
|
||||
}
|
||||
}
|
||||
let tabOwnerView;
|
||||
const queryScope = document.querySelector('.skinHeader');
|
||||
let headerTabsContainer;
|
||||
let tabsElem;
|
||||
|
||||
function ensureElements() {
|
||||
if (!headerTabsContainer) {
|
||||
headerTabsContainer = queryScope.querySelector('.headerTabs');
|
||||
}
|
||||
@@ -37,14 +23,12 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
}
|
||||
|
||||
function allowSwipe(target) {
|
||||
|
||||
function allowSwipeOn(elem) {
|
||||
|
||||
if (dom.parentWithTag(elem, 'input')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var classList = elem.classList;
|
||||
const classList = elem.classList;
|
||||
if (classList) {
|
||||
return !classList.contains('scrollX') && !classList.contains('animatedScrollX');
|
||||
}
|
||||
@@ -52,7 +36,7 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
return true;
|
||||
}
|
||||
|
||||
var parent = target;
|
||||
let parent = target;
|
||||
while (parent != null) {
|
||||
if (!allowSwipeOn(parent)) {
|
||||
return false;
|
||||
@@ -64,28 +48,25 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
}
|
||||
|
||||
function configureSwipeTabs(view, tabsElem, getTabContainersFn) {
|
||||
|
||||
if (!browser.touch) {
|
||||
return;
|
||||
}
|
||||
|
||||
// implement without hammer
|
||||
var pageCount = getTabContainersFn().length;
|
||||
var onSwipeLeft = function (e, target) {
|
||||
const onSwipeLeft = function (e, target) {
|
||||
if (allowSwipe(target) && view.contains(target)) {
|
||||
tabsElem.selectNext();
|
||||
}
|
||||
};
|
||||
|
||||
var onSwipeRight = function (e, target) {
|
||||
const onSwipeRight = function (e, target) {
|
||||
if (allowSwipe(target) && view.contains(target)) {
|
||||
tabsElem.selectPrevious();
|
||||
}
|
||||
};
|
||||
|
||||
require(['touchHelper'], function (TouchHelper) {
|
||||
|
||||
var touchHelper = new TouchHelper(view.parentNode.parentNode);
|
||||
import('touchHelper').then(({default: TouchHelper}) => {
|
||||
const touchHelper = new TouchHelper(view.parentNode.parentNode);
|
||||
|
||||
events.on(touchHelper, 'swipeleft', onSwipeLeft);
|
||||
events.on(touchHelper, 'swiperight', onSwipeRight);
|
||||
@@ -96,29 +77,20 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
});
|
||||
}
|
||||
|
||||
function setTabs(view, selectedIndex, getTabsFn, getTabContainersFn, onBeforeTabChange, onTabChange, setSelectedIndex) {
|
||||
|
||||
var enableInFooter = enableTabsInFooter();
|
||||
|
||||
export function setTabs(view, selectedIndex, getTabsFn, getTabContainersFn, onBeforeTabChange, onTabChange, setSelectedIndex) {
|
||||
if (!view) {
|
||||
if (tabOwnerView) {
|
||||
|
||||
if (!headerTabsContainer) {
|
||||
headerTabsContainer = queryScope.querySelector('.headerTabs');
|
||||
}
|
||||
|
||||
ensureElements(enableInFooter);
|
||||
ensureElements();
|
||||
|
||||
document.body.classList.remove('withSectionTabs');
|
||||
|
||||
headerTabsContainer.innerHTML = '';
|
||||
headerTabsContainer.classList.add('hide');
|
||||
|
||||
if (footerTabsContainer) {
|
||||
footerTabsContainer.innerHTML = '';
|
||||
footerTabsContainer.classList.add('hide');
|
||||
}
|
||||
|
||||
tabOwnerView = null;
|
||||
}
|
||||
return {
|
||||
@@ -127,28 +99,26 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
};
|
||||
}
|
||||
|
||||
ensureElements(enableInFooter);
|
||||
ensureElements();
|
||||
|
||||
var tabsContainerElem = enableInFooter ? footerTabsContainer : headerTabsContainer;
|
||||
const tabsContainerElem = headerTabsContainer;
|
||||
|
||||
if (!tabOwnerView) {
|
||||
tabsContainerElem.classList.remove('hide');
|
||||
}
|
||||
|
||||
if (tabOwnerView !== view) {
|
||||
let index = 0;
|
||||
|
||||
var index = 0;
|
||||
|
||||
var indexAttribute = selectedIndex == null ? '' : (' data-index="' + selectedIndex + '"');
|
||||
var tabsHtml = '<div is="emby-tabs"' + indexAttribute + ' class="tabs-viewmenubar"><div class="emby-tabs-slider" style="white-space:nowrap;">' + getTabsFn().map(function (t) {
|
||||
|
||||
var tabClass = 'emby-tab-button';
|
||||
const indexAttribute = selectedIndex == null ? '' : (' data-index="' + selectedIndex + '"');
|
||||
const tabsHtml = '<div is="emby-tabs"' + indexAttribute + ' class="tabs-viewmenubar"><div class="emby-tabs-slider" style="white-space:nowrap;">' + getTabsFn().map(function (t) {
|
||||
let tabClass = 'emby-tab-button';
|
||||
|
||||
if (t.enabled === false) {
|
||||
tabClass += ' hide';
|
||||
}
|
||||
|
||||
var tabHtml;
|
||||
let tabHtml;
|
||||
|
||||
if (t.cssClass) {
|
||||
tabClass += ' ' + t.cssClass;
|
||||
@@ -162,7 +132,6 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
|
||||
index++;
|
||||
return tabHtml;
|
||||
|
||||
}).join('') + '</div></div>';
|
||||
|
||||
tabsContainerElem.innerHTML = tabsHtml;
|
||||
@@ -176,23 +145,15 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
configureSwipeTabs(view, tabsElem, getTabContainersFn);
|
||||
|
||||
tabsElem.addEventListener('beforetabchange', function (e) {
|
||||
|
||||
var tabContainers = getTabContainersFn();
|
||||
const tabContainers = getTabContainersFn();
|
||||
if (e.detail.previousIndex != null) {
|
||||
|
||||
var previousPanel = tabContainers[e.detail.previousIndex];
|
||||
const previousPanel = tabContainers[e.detail.previousIndex];
|
||||
if (previousPanel) {
|
||||
previousPanel.classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
var newPanel = tabContainers[e.detail.selectedTabIndex];
|
||||
|
||||
//if (e.detail.previousIndex != null && e.detail.previousIndex != e.detail.selectedTabIndex) {
|
||||
// if (newPanel.animate && (animateTabs || []).indexOf(e.detail.selectedTabIndex) != -1) {
|
||||
// fadeInRight(newPanel);
|
||||
// }
|
||||
//}
|
||||
const newPanel = tabContainers[e.detail.selectedTabIndex];
|
||||
|
||||
if (newPanel) {
|
||||
newPanel.classList.add('is-active');
|
||||
@@ -210,16 +171,11 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
if (tabsElem.selectedIndex) {
|
||||
tabsElem.selectedIndex(selectedIndex);
|
||||
} else {
|
||||
|
||||
tabsElem.readySelectedIndex = selectedIndex;
|
||||
tabsElem.addEventListener('ready', onViewTabsReady);
|
||||
}
|
||||
}
|
||||
|
||||
//if (enableSwipe !== false) {
|
||||
// libraryBrowser.configureSwipeTabs(ownerpage, tabs);
|
||||
//}
|
||||
|
||||
return {
|
||||
tabsContainer: tabsContainerElem,
|
||||
tabs: tabsContainerElem.querySelector('[is="emby-tabs"]'),
|
||||
@@ -241,9 +197,8 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
};
|
||||
}
|
||||
|
||||
function selectedTabIndex(index) {
|
||||
|
||||
var tabsContainerElem = headerTabsContainer;
|
||||
export function selectedTabIndex(index) {
|
||||
const tabsContainerElem = headerTabsContainer;
|
||||
|
||||
if (!tabsElem) {
|
||||
tabsElem = tabsContainerElem.querySelector('[is="emby-tabs"]');
|
||||
@@ -256,13 +211,8 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom,
|
||||
}
|
||||
}
|
||||
|
||||
function getTabsElement() {
|
||||
export function getTabsElement() {
|
||||
return document.querySelector('.tabs-viewmenubar');
|
||||
}
|
||||
|
||||
return {
|
||||
setTabs: setTabs,
|
||||
getTabsElement: getTabsElement,
|
||||
selectedTabIndex: selectedTabIndex
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionseditor/libraryoptionseditor', 'globalize', 'emby-toggle', 'emby-input', 'emby-select', 'paper-icon-button-light', 'listViewStyle', 'formDialogStyle', 'emby-button', 'flexStyles'], function (loading, dialogHelper, dom, $, libraryoptionseditor, globalize) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for media library creator.
|
||||
* @module components/mediaLibraryCreator/mediaLibraryCreator
|
||||
*/
|
||||
|
||||
import loading from 'loading';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import dom from 'dom';
|
||||
import $ from 'jQuery';
|
||||
import libraryoptionseditor from 'components/libraryoptionseditor/libraryoptionseditor';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-toggle';
|
||||
import 'emby-input';
|
||||
import 'emby-select';
|
||||
import 'paper-icon-button-light';
|
||||
import 'listViewStyle';
|
||||
import 'formDialogStyle';
|
||||
import 'emby-button';
|
||||
import 'flexStyles';
|
||||
|
||||
function onAddLibrary() {
|
||||
if (isCreating) {
|
||||
@@ -7,7 +26,7 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
if (pathInfos.length == 0) {
|
||||
require(['alert'], function (alert) {
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert({
|
||||
text: globalize.translate('PleaseAddAtLeastOneFolder'),
|
||||
type: 'error'
|
||||
@@ -19,23 +38,23 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
|
||||
isCreating = true;
|
||||
loading.show();
|
||||
var dlg = dom.parentWithClass(this, 'dlg-librarycreator');
|
||||
var name = $('#txtValue', dlg).val();
|
||||
var type = $('#selectCollectionType', dlg).val();
|
||||
const dlg = dom.parentWithClass(this, 'dlg-librarycreator');
|
||||
const name = $('#txtValue', dlg).val();
|
||||
let type = $('#selectCollectionType', dlg).val();
|
||||
|
||||
if (type == 'mixed') {
|
||||
type = null;
|
||||
}
|
||||
|
||||
var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions'));
|
||||
const libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions'));
|
||||
libraryOptions.PathInfos = pathInfos;
|
||||
ApiClient.addVirtualFolder(name, type, currentOptions.refresh, libraryOptions).then(function () {
|
||||
ApiClient.addVirtualFolder(name, type, currentOptions.refresh, libraryOptions).then(() => {
|
||||
hasChanges = true;
|
||||
isCreating = false;
|
||||
loading.hide();
|
||||
dialogHelper.close(dlg);
|
||||
}, function () {
|
||||
require(['toast'], function (toast) {
|
||||
}, () => {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder'));
|
||||
});
|
||||
|
||||
@@ -46,15 +65,15 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function getCollectionTypeOptionsHtml(collectionTypeOptions) {
|
||||
return collectionTypeOptions.map(function (i) {
|
||||
return '<option value="' + i.value + '">' + i.name + '</option>';
|
||||
return collectionTypeOptions.map(i => {
|
||||
return `<option value="${i.value}">${i.name}</option>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function initEditor(page, collectionTypeOptions) {
|
||||
$('#selectCollectionType', page).html(getCollectionTypeOptionsHtml(collectionTypeOptions)).val('').on('change', function () {
|
||||
var value = this.value;
|
||||
var dlg = $(this).parents('.dialog')[0];
|
||||
const value = this.value;
|
||||
const dlg = $(this).parents('.dialog')[0];
|
||||
libraryoptionseditor.setContentType(dlg.querySelector('.libraryOptions'), value == 'mixed' ? '' : value);
|
||||
|
||||
if (value) {
|
||||
@@ -64,12 +83,12 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
if (value != 'mixed') {
|
||||
var index = this.selectedIndex;
|
||||
const index = this.selectedIndex;
|
||||
|
||||
if (index != -1) {
|
||||
var name = this.options[index].innerHTML.replace('*', '').replace('&', '&');
|
||||
const name = this.options[index].innerHTML.replace('*', '').replace('&', '&');
|
||||
$('#txtValue', dlg).val(name);
|
||||
var folderOption = collectionTypeOptions.filter(function (i) {
|
||||
const folderOption = collectionTypeOptions.filter(i => {
|
||||
return i.value == value;
|
||||
})[0];
|
||||
$('.collectionTypeFieldDescription', dlg).html(folderOption.message || '');
|
||||
@@ -83,15 +102,15 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function onToggleAdvancedChange() {
|
||||
var dlg = dom.parentWithClass(this, 'dlg-librarycreator');
|
||||
const dlg = dom.parentWithClass(this, 'dlg-librarycreator');
|
||||
libraryoptionseditor.setAdvancedVisible(dlg.querySelector('.libraryOptions'), this.checked);
|
||||
}
|
||||
|
||||
function onAddButtonClick() {
|
||||
var page = dom.parentWithClass(this, 'dlg-librarycreator');
|
||||
const page = dom.parentWithClass(this, 'dlg-librarycreator');
|
||||
|
||||
require(['directorybrowser'], function (directoryBrowser) {
|
||||
var picker = new directoryBrowser();
|
||||
import('directorybrowser').then(({default: directoryBrowser}) => {
|
||||
const picker = new directoryBrowser();
|
||||
picker.show({
|
||||
enableNetworkSharePath: true,
|
||||
callback: function (path, networkSharePath) {
|
||||
@@ -106,24 +125,24 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function getFolderHtml(pathInfo, index) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
html += '<div class="listItem listItem-border lnkPath" style="padding-left:.5em;">';
|
||||
html += '<div class="' + (pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody') + '">';
|
||||
html += '<div class="listItemBodyText">' + pathInfo.Path + '</div>';
|
||||
html += `<div class="${pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody'}">`;
|
||||
html += `<div class="listItemBodyText">${pathInfo.Path}</div>`;
|
||||
|
||||
if (pathInfo.NetworkPath) {
|
||||
html += '<div class="listItemBodyText secondary">' + pathInfo.NetworkPath + '</div>';
|
||||
html += `<div class="listItemBodyText secondary">${pathInfo.NetworkPath}</div>`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += '<button type="button" is="paper-icon-button-light"" class="listItemButton btnRemovePath" data-index="' + index + '"><span class="material-icons remove_circle"></span></button>';
|
||||
html += `<button type="button" is="paper-icon-button-light"" class="listItemButton btnRemovePath" data-index="${index}"><span class="material-icons remove_circle"></span></button>`;
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderPaths(page) {
|
||||
var foldersHtml = pathInfos.map(getFolderHtml).join('');
|
||||
var folderList = page.querySelector('.folderList');
|
||||
const foldersHtml = pathInfos.map(getFolderHtml).join('');
|
||||
const folderList = page.querySelector('.folderList');
|
||||
folderList.innerHTML = foldersHtml;
|
||||
|
||||
if (foldersHtml) {
|
||||
@@ -134,13 +153,13 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function addMediaLocation(page, path, networkSharePath) {
|
||||
var pathLower = path.toLowerCase();
|
||||
var pathFilter = pathInfos.filter(function (p) {
|
||||
const pathLower = path.toLowerCase();
|
||||
const pathFilter = pathInfos.filter(p => {
|
||||
return p.Path.toLowerCase() == pathLower;
|
||||
});
|
||||
|
||||
if (!pathFilter.length) {
|
||||
var pathInfo = {
|
||||
const pathInfo = {
|
||||
Path: path
|
||||
};
|
||||
|
||||
@@ -154,11 +173,11 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function onRemoveClick(e) {
|
||||
var button = dom.parentWithClass(e.target, 'btnRemovePath');
|
||||
var index = parseInt(button.getAttribute('data-index'));
|
||||
var location = pathInfos[index].Path;
|
||||
var locationLower = location.toLowerCase();
|
||||
pathInfos = pathInfos.filter(function (p) {
|
||||
const button = dom.parentWithClass(e.target, 'btnRemovePath');
|
||||
const index = parseInt(button.getAttribute('data-index'));
|
||||
const location = pathInfos[index].Path;
|
||||
const locationLower = location.toLowerCase();
|
||||
pathInfos = pathInfos.filter(p => {
|
||||
return p.Path.toLowerCase() != locationLower;
|
||||
});
|
||||
renderPaths(dom.parentWithClass(button, 'dlg-librarycreator'));
|
||||
@@ -169,54 +188,49 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function initLibraryOptions(dlg) {
|
||||
libraryoptionseditor.embed(dlg.querySelector('.libraryOptions')).then(function () {
|
||||
libraryoptionseditor.embed(dlg.querySelector('.libraryOptions')).then(() => {
|
||||
$('#selectCollectionType', dlg).trigger('change');
|
||||
onToggleAdvancedChange.call(dlg.querySelector('.chkAdvanced'));
|
||||
});
|
||||
}
|
||||
|
||||
function editor() {
|
||||
this.show = function (options) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
currentOptions = options;
|
||||
currentResolve = resolve;
|
||||
hasChanges = false;
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'components/mediaLibraryCreator/mediaLibraryCreator.template.html', true);
|
||||
|
||||
xhr.onload = function (e) {
|
||||
var template = this.response;
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
modal: false,
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add('ui-body-a');
|
||||
dlg.classList.add('background-theme-a');
|
||||
dlg.classList.add('dlg-librarycreator');
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.innerHTML = globalize.translateDocument(template);
|
||||
initEditor(dlg, options.collectionTypeOptions);
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
pathInfos = [];
|
||||
renderPaths(dlg);
|
||||
initLibraryOptions(dlg);
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
export class showEditor {
|
||||
constructor(options) {
|
||||
return new Promise((resolve) => {
|
||||
currentOptions = options;
|
||||
currentResolve = resolve;
|
||||
hasChanges = false;
|
||||
import('text!./components/mediaLibraryCreator/mediaLibraryCreator.template.html').then(({default: template}) => {
|
||||
const dlg = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
modal: false,
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add('ui-body-a');
|
||||
dlg.classList.add('background-theme-a');
|
||||
dlg.classList.add('dlg-librarycreator');
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.innerHTML = globalize.translateHtml(template);
|
||||
initEditor(dlg, options.collectionTypeOptions);
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
pathInfos = [];
|
||||
renderPaths(dlg);
|
||||
initLibraryOptions(dlg);
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var pathInfos = [];
|
||||
var currentResolve;
|
||||
var currentOptions;
|
||||
var hasChanges = false;
|
||||
var isCreating = false;
|
||||
return editor;
|
||||
});
|
||||
let pathInfos = [];
|
||||
let currentResolve;
|
||||
let currentOptions;
|
||||
let hasChanges = false;
|
||||
let isCreating = false;
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default showEditor;
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
<div class="folders">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<h1 style="margin: .5em 0;">${HeadersFolders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${ButtonAdd}">
|
||||
<h1 style="margin: .5em 0;">${Folders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${Add}">
|
||||
<span class="material-icons add"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionseditor/libraryoptionseditor', 'globalize', 'emby-button', 'listViewStyle', 'paper-icon-button-light', 'formDialogStyle', 'emby-toggle', 'flexStyles'], function (jQuery, loading, dialogHelper, dom, libraryoptionseditor, globalize) {
|
||||
'use strict';
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for media library editor.
|
||||
* @module components/mediaLibraryEditor/mediaLibraryEditor
|
||||
*/
|
||||
|
||||
import jQuery from 'jQuery';
|
||||
import loading from 'loading';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import dom from 'dom';
|
||||
import libraryoptionseditor from 'components/libraryoptionseditor/libraryoptionseditor';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-button';
|
||||
import 'listViewStyle';
|
||||
import 'paper-icon-button-light';
|
||||
import 'formDialogStyle';
|
||||
import 'emby-toggle';
|
||||
import 'flexStyles';
|
||||
|
||||
function onEditLibrary() {
|
||||
if (isCreating) {
|
||||
@@ -8,15 +25,15 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
|
||||
isCreating = true;
|
||||
loading.show();
|
||||
var dlg = dom.parentWithClass(this, 'dlg-libraryeditor');
|
||||
var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions'));
|
||||
const dlg = dom.parentWithClass(this, 'dlg-libraryeditor');
|
||||
let libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions'));
|
||||
libraryOptions = Object.assign(currentOptions.library.LibraryOptions || {}, libraryOptions);
|
||||
ApiClient.updateVirtualFolderOptions(currentOptions.library.ItemId, libraryOptions).then(function () {
|
||||
ApiClient.updateVirtualFolderOptions(currentOptions.library.ItemId, libraryOptions).then(() => {
|
||||
hasChanges = true;
|
||||
isCreating = false;
|
||||
loading.hide();
|
||||
dialogHelper.close(dlg);
|
||||
}, function () {
|
||||
}, () => {
|
||||
isCreating = false;
|
||||
loading.hide();
|
||||
});
|
||||
@@ -24,51 +41,51 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function addMediaLocation(page, path, networkSharePath) {
|
||||
var virtualFolder = currentOptions.library;
|
||||
var refreshAfterChange = currentOptions.refresh;
|
||||
ApiClient.addMediaPath(virtualFolder.Name, path, networkSharePath, refreshAfterChange).then(function () {
|
||||
const virtualFolder = currentOptions.library;
|
||||
const refreshAfterChange = currentOptions.refresh;
|
||||
ApiClient.addMediaPath(virtualFolder.Name, path, networkSharePath, refreshAfterChange).then(() => {
|
||||
hasChanges = true;
|
||||
refreshLibraryFromServer(page);
|
||||
}, function () {
|
||||
require(['toast'], function (toast) {
|
||||
}, () => {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateMediaLocation(page, path, networkSharePath) {
|
||||
var virtualFolder = currentOptions.library;
|
||||
const virtualFolder = currentOptions.library;
|
||||
ApiClient.updateMediaPath(virtualFolder.Name, {
|
||||
Path: path,
|
||||
NetworkPath: networkSharePath
|
||||
}).then(function () {
|
||||
}).then(() => {
|
||||
hasChanges = true;
|
||||
refreshLibraryFromServer(page);
|
||||
}, function () {
|
||||
require(['toast'], function (toast) {
|
||||
}, () => {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onRemoveClick(btnRemovePath, location) {
|
||||
var button = btnRemovePath;
|
||||
var virtualFolder = currentOptions.library;
|
||||
const button = btnRemovePath;
|
||||
const virtualFolder = currentOptions.library;
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
import('confirm').then(({default: confirm}) => {
|
||||
confirm({
|
||||
title: globalize.translate('HeaderRemoveMediaLocation'),
|
||||
text: globalize.translate('MessageConfirmRemoveMediaLocation'),
|
||||
confirmText: globalize.translate('ButtonDelete'),
|
||||
confirmText: globalize.translate('Delete'),
|
||||
primary: 'delete'
|
||||
}).then(function () {
|
||||
var refreshAfterChange = currentOptions.refresh;
|
||||
ApiClient.removeMediaPath(virtualFolder.Name, location, refreshAfterChange).then(function () {
|
||||
}).then(() => {
|
||||
const refreshAfterChange = currentOptions.refresh;
|
||||
ApiClient.removeMediaPath(virtualFolder.Name, location, refreshAfterChange).then(() => {
|
||||
hasChanges = true;
|
||||
refreshLibraryFromServer(dom.parentWithClass(button, 'dlg-libraryeditor'));
|
||||
}, function () {
|
||||
require(['toast'], function (toast) {
|
||||
toast(globalize.translate('DefaultErrorMessage'));
|
||||
}, () => {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('ErrorDefault'));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -76,14 +93,14 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function onListItemClick(e) {
|
||||
var listItem = dom.parentWithClass(e.target, 'listItem');
|
||||
const listItem = dom.parentWithClass(e.target, 'listItem');
|
||||
|
||||
if (listItem) {
|
||||
var index = parseInt(listItem.getAttribute('data-index'));
|
||||
var pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || [];
|
||||
var pathInfo = null == index ? {} : pathInfos[index] || {};
|
||||
var originalPath = pathInfo.Path || (null == index ? null : currentOptions.library.Locations[index]);
|
||||
var btnRemovePath = dom.parentWithClass(e.target, 'btnRemovePath');
|
||||
const index = parseInt(listItem.getAttribute('data-index'));
|
||||
const pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || [];
|
||||
const pathInfo = index == null ? {} : pathInfos[index] || {};
|
||||
const originalPath = pathInfo.Path || (index == null ? null : currentOptions.library.Locations[index]);
|
||||
const btnRemovePath = dom.parentWithClass(e.target, 'btnRemovePath');
|
||||
|
||||
if (btnRemovePath) {
|
||||
onRemoveClick(btnRemovePath, originalPath);
|
||||
@@ -95,26 +112,26 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function getFolderHtml(pathInfo, index) {
|
||||
var html = '';
|
||||
html += '<div class="listItem listItem-border lnkPath" data-index="' + index + '" style="padding-left:.5em;">';
|
||||
html += '<div class="' + (pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody') + '">';
|
||||
let html = '';
|
||||
html += `<div class="listItem listItem-border lnkPath" data-index="${index}" style="padding-left:.5em;">`;
|
||||
html += `<div class="${pathInfo.NetworkPath ? 'listItemBody two-line' : 'listItemBody'}">`;
|
||||
html += '<h3 class="listItemBodyText">';
|
||||
html += pathInfo.Path;
|
||||
html += '</h3>';
|
||||
|
||||
if (pathInfo.NetworkPath) {
|
||||
html += '<div class="listItemBodyText secondary">' + pathInfo.NetworkPath + '</div>';
|
||||
html += `<div class="listItemBodyText secondary">${pathInfo.NetworkPath}</div>`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += '<button type="button" is="paper-icon-button-light" class="listItemButton btnRemovePath" data-index="' + index + '"><span class="material-icons remove_circle"></span></button>';
|
||||
html += `<button type="button" is="paper-icon-button-light" class="listItemButton btnRemovePath" data-index="${index}"><span class="material-icons remove_circle"></span></button>`;
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
function refreshLibraryFromServer(page) {
|
||||
ApiClient.getVirtualFolders().then(function (result) {
|
||||
var library = result.filter(function (f) {
|
||||
ApiClient.getVirtualFolders().then(result => {
|
||||
const library = result.filter(f => {
|
||||
return f.Name === currentOptions.library.Name;
|
||||
})[0];
|
||||
|
||||
@@ -126,10 +143,10 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function renderLibrary(page, options) {
|
||||
var pathInfos = (options.library.LibraryOptions || {}).PathInfos || [];
|
||||
let pathInfos = (options.library.LibraryOptions || {}).PathInfos || [];
|
||||
|
||||
if (!pathInfos.length) {
|
||||
pathInfos = options.library.Locations.map(function (p) {
|
||||
pathInfos = options.library.Locations.map(p => {
|
||||
return {
|
||||
Path: p
|
||||
};
|
||||
@@ -150,11 +167,11 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function showDirectoryBrowser(context, originalPath, networkPath) {
|
||||
require(['directorybrowser'], function (directoryBrowser) {
|
||||
var picker = new directoryBrowser();
|
||||
import('directorybrowser').then(({default: directoryBrowser}) => {
|
||||
const picker = new directoryBrowser();
|
||||
picker.show({
|
||||
enableNetworkSharePath: true,
|
||||
pathReadOnly: null != originalPath,
|
||||
pathReadOnly: originalPath != null,
|
||||
path: originalPath,
|
||||
networkSharePath: networkPath,
|
||||
callback: function (path, networkSharePath) {
|
||||
@@ -173,7 +190,7 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
}
|
||||
|
||||
function onToggleAdvancedChange() {
|
||||
var dlg = dom.parentWithClass(this, 'dlg-libraryeditor');
|
||||
const dlg = dom.parentWithClass(this, 'dlg-libraryeditor');
|
||||
libraryoptionseditor.setAdvancedVisible(dlg.querySelector('.libraryOptions'), this.checked);
|
||||
}
|
||||
|
||||
@@ -183,7 +200,7 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
dlg.querySelector('.folderList').addEventListener('click', onListItemClick);
|
||||
dlg.querySelector('.chkAdvanced').addEventListener('change', onToggleAdvancedChange);
|
||||
dlg.querySelector('.btnSubmit').addEventListener('click', onEditLibrary);
|
||||
libraryoptionseditor.embed(dlg.querySelector('.libraryOptions'), options.library.CollectionType, options.library.LibraryOptions).then(function () {
|
||||
libraryoptionseditor.embed(dlg.querySelector('.libraryOptions'), options.library.CollectionType, options.library.LibraryOptions).then(() => {
|
||||
onToggleAdvancedChange.call(dlg.querySelector('.chkAdvanced'));
|
||||
});
|
||||
}
|
||||
@@ -192,46 +209,41 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
||||
currentDeferred.resolveWith(null, [hasChanges]);
|
||||
}
|
||||
|
||||
function editor() {
|
||||
this.show = function (options) {
|
||||
var deferred = jQuery.Deferred();
|
||||
currentOptions = options;
|
||||
currentDeferred = deferred;
|
||||
hasChanges = false;
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'components/mediaLibraryEditor/mediaLibraryEditor.template.html', true);
|
||||
|
||||
xhr.onload = function (e) {
|
||||
var template = this.response;
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
modal: false,
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add('dlg-libraryeditor');
|
||||
dlg.classList.add('ui-body-a');
|
||||
dlg.classList.add('background-theme-a');
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.innerHTML = globalize.translateDocument(template);
|
||||
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.library.Name;
|
||||
initEditor(dlg, options);
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
refreshLibraryFromServer(dlg);
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
return deferred.promise();
|
||||
};
|
||||
export class showEditor {
|
||||
constructor(options) {
|
||||
const deferred = jQuery.Deferred();
|
||||
currentOptions = options;
|
||||
currentDeferred = deferred;
|
||||
hasChanges = false;
|
||||
import('text!./components/mediaLibraryEditor/mediaLibraryEditor.template.html').then(({default: template}) => {
|
||||
const dlg = dialogHelper.createDialog({
|
||||
size: 'small',
|
||||
modal: false,
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
dlg.classList.add('dlg-libraryeditor');
|
||||
dlg.classList.add('ui-body-a');
|
||||
dlg.classList.add('background-theme-a');
|
||||
dlg.classList.add('formDialog');
|
||||
dlg.innerHTML = globalize.translateHtml(template);
|
||||
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.library.Name;
|
||||
initEditor(dlg, options);
|
||||
dlg.addEventListener('close', onDialogClosed);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
refreshLibraryFromServer(dlg);
|
||||
});
|
||||
return deferred.promise();
|
||||
}
|
||||
}
|
||||
|
||||
var currentDeferred;
|
||||
var currentOptions;
|
||||
var hasChanges = false;
|
||||
var isCreating = false;
|
||||
return editor;
|
||||
});
|
||||
let currentDeferred;
|
||||
let currentOptions;
|
||||
let hasChanges = false;
|
||||
let isCreating = false;
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default showEditor;
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
<div class="folders hide">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<h1 style="margin: .5em 0;">${HeadersFolders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${ButtonAdd}">
|
||||
<h1 style="margin: .5em 0;">${Folders}</h1>
|
||||
<button is="emby-button" type="button" class="fab btnAddFolder submit" style="margin-left:1em;" title="${Add}">
|
||||
<span class="material-icons add"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
font-size: 1.4em;
|
||||
margin-right: 0.125em;
|
||||
color: #f2b01e;
|
||||
}
|
||||
|
||||
.mediaInfoCriticRating {
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'material-icons', 'css!./mediainfo.css', 'programStyles', 'emby-button'], function (datetime, globalize, appRouter, itemHelper, indicators) {
|
||||
'use strict';
|
||||
import datetime from 'datetime';
|
||||
import globalize from 'globalize';
|
||||
import appRouter from 'appRouter';
|
||||
import itemHelper from 'itemHelper';
|
||||
import indicators from 'indicators';
|
||||
import 'material-icons';
|
||||
import 'css!./mediainfo.css';
|
||||
import 'programStyles';
|
||||
import 'emby-button';
|
||||
|
||||
/* eslint-disable indent */
|
||||
function getTimerIndicator(item) {
|
||||
|
||||
var status;
|
||||
let status;
|
||||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
return '<span class="material-icons mediaInfoItem mediaInfoIconItem mediaInfoTimerIcon fiber_smart_record"></span>';
|
||||
} else if (item.TimerId || item.SeriesTimerId) {
|
||||
|
||||
status = item.Status || 'Cancelled';
|
||||
} else if (item.Type === 'Timer') {
|
||||
|
||||
status = item.Status;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (item.SeriesTimerId) {
|
||||
|
||||
if (status !== 'Cancelled') {
|
||||
return '<span class="material-icons mediaInfoItem mediaInfoIconItem mediaInfoTimerIcon fiber_smart_record"></span>';
|
||||
}
|
||||
@@ -30,16 +34,14 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
function getProgramInfoHtml(item, options) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
var miscInfo = [];
|
||||
var text;
|
||||
var date;
|
||||
const miscInfo = [];
|
||||
let text;
|
||||
let date;
|
||||
|
||||
if (item.StartDate && options.programTime !== false) {
|
||||
|
||||
try {
|
||||
|
||||
text = '';
|
||||
|
||||
date = datetime.parseISO8601Date(item.StartDate);
|
||||
@@ -48,35 +50,34 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
text += datetime.toLocaleDateString(date, { weekday: 'short', month: 'short', day: 'numeric' });
|
||||
}
|
||||
|
||||
text += ' ' + datetime.getDisplayTime(date);
|
||||
text += ` ${datetime.getDisplayTime(date)}`;
|
||||
|
||||
if (item.EndDate) {
|
||||
date = datetime.parseISO8601Date(item.EndDate);
|
||||
text += ' - ' + datetime.getDisplayTime(date);
|
||||
text += ` - ${datetime.getDisplayTime(date)}`;
|
||||
}
|
||||
|
||||
miscInfo.push(text);
|
||||
} catch (e) {
|
||||
console.error('error parsing date: ' + item.StartDate);
|
||||
console.error('error parsing date:', item.StartDate);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.ChannelNumber) {
|
||||
miscInfo.push('CH ' + item.ChannelNumber);
|
||||
miscInfo.push(`CH ${item.ChannelNumber}`);
|
||||
}
|
||||
|
||||
if (item.ChannelName) {
|
||||
|
||||
if (options.interactive && item.ChannelId) {
|
||||
miscInfo.push({
|
||||
html: '<a is="emby-linkbutton" class="button-flat mediaInfoItem" href="' + appRouter.getRouteUrl({
|
||||
html: `<a is="emby-linkbutton" class="button-flat mediaInfoItem" href="${appRouter.getRouteUrl({
|
||||
|
||||
ServerId: item.ServerId,
|
||||
Type: 'TvChannel',
|
||||
Name: item.ChannelName,
|
||||
Id: item.ChannelId
|
||||
|
||||
}) + '">' + item.ChannelName + '</a>'
|
||||
})}">${item.ChannelName}</a>`
|
||||
});
|
||||
} else {
|
||||
miscInfo.push(item.ChannelName);
|
||||
@@ -84,7 +85,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
if (options.timerIndicator !== false) {
|
||||
var timerHtml = getTimerIndicator(item);
|
||||
const timerHtml = getTimerIndicator(item);
|
||||
if (timerHtml) {
|
||||
miscInfo.push({
|
||||
html: timerHtml
|
||||
@@ -92,31 +93,29 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
}
|
||||
|
||||
html += miscInfo.map(function (m) {
|
||||
html += miscInfo.map(m => {
|
||||
return getMediaInfoItem(m);
|
||||
}).join('');
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function getMediaInfoHtml(item, options) {
|
||||
var html = '';
|
||||
export function getMediaInfoHtml(item, options) {
|
||||
let html = '';
|
||||
|
||||
var miscInfo = [];
|
||||
const miscInfo = [];
|
||||
options = options || {};
|
||||
var text;
|
||||
var date;
|
||||
var minutes;
|
||||
var count;
|
||||
let text;
|
||||
let date;
|
||||
let minutes;
|
||||
let count;
|
||||
|
||||
var showFolderRuntime = item.Type === 'MusicAlbum' || item.MediaType === 'MusicArtist' || item.MediaType === 'Playlist' || item.MediaType === 'MusicGenre';
|
||||
const showFolderRuntime = item.Type === 'MusicAlbum' || item.MediaType === 'MusicArtist' || item.MediaType === 'Playlist' || item.MediaType === 'MusicGenre';
|
||||
|
||||
if (showFolderRuntime) {
|
||||
|
||||
count = item.SongCount || item.ChildCount;
|
||||
|
||||
if (count) {
|
||||
|
||||
miscInfo.push(globalize.translate('TrackCount', count));
|
||||
}
|
||||
|
||||
@@ -124,33 +123,28 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
}
|
||||
} else if (item.Type === 'PhotoAlbum' || item.Type === 'BoxSet') {
|
||||
|
||||
count = item.ChildCount;
|
||||
|
||||
if (count) {
|
||||
|
||||
miscInfo.push(globalize.translate('ItemCount', count));
|
||||
}
|
||||
}
|
||||
|
||||
if ((item.Type === 'Episode' || item.MediaType === 'Photo') && options.originalAirDate !== false) {
|
||||
|
||||
if (item.PremiereDate) {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.PremiereDate);
|
||||
|
||||
text = datetime.toLocaleDateString(date);
|
||||
miscInfo.push(text);
|
||||
} catch (e) {
|
||||
console.error('error parsing date: ' + item.PremiereDate);
|
||||
console.error('error parsing date:', item.PremiereDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Type === 'SeriesTimer') {
|
||||
if (item.RecordAnyTime) {
|
||||
|
||||
miscInfo.push(globalize.translate('Anytime'));
|
||||
} else {
|
||||
miscInfo.push(datetime.getDisplayTime(item.StartDate));
|
||||
@@ -164,7 +158,6 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
if (item.StartDate && item.Type !== 'Program' && item.Type !== 'SeriesTimer') {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.StartDate);
|
||||
|
||||
@@ -176,31 +169,25 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
miscInfo.push(text);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('error parsing date: ' + item.StartDate);
|
||||
console.error('error parsing date:', item.StartDate);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.year !== false && item.ProductionYear && item.Type === 'Series') {
|
||||
|
||||
if (item.Status === 'Continuing') {
|
||||
miscInfo.push(globalize.translate('SeriesYearToPresent', item.ProductionYear));
|
||||
|
||||
} else if (item.ProductionYear) {
|
||||
|
||||
text = item.ProductionYear;
|
||||
|
||||
if (item.EndDate) {
|
||||
|
||||
try {
|
||||
|
||||
var endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
|
||||
if (endYear !== item.ProductionYear) {
|
||||
text += '-' + datetime.parseISO8601Date(item.EndDate).getFullYear();
|
||||
text += `-${datetime.parseISO8601Date(item.EndDate).getFullYear()}`;
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error('error parsing date: ' + item.EndDate);
|
||||
console.error('error parsing date:', item.EndDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,29 +196,27 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
if (item.Type === 'Program') {
|
||||
|
||||
if (options.programIndicator !== false) {
|
||||
if (item.IsLive) {
|
||||
miscInfo.push({
|
||||
html: '<div class="mediaInfoProgramAttribute mediaInfoItem liveTvProgram">' + globalize.translate('Live') + '</div>'
|
||||
html: `<div class="mediaInfoProgramAttribute mediaInfoItem liveTvProgram">${globalize.translate('Live')}</div>`
|
||||
});
|
||||
} else if (item.IsPremiere) {
|
||||
miscInfo.push({
|
||||
html: '<div class="mediaInfoProgramAttribute mediaInfoItem premiereTvProgram">' + globalize.translate('Premiere') + '</div>'
|
||||
html: `<div class="mediaInfoProgramAttribute mediaInfoItem premiereTvProgram">${globalize.translate('Premiere')}</div>`
|
||||
});
|
||||
} else if (item.IsSeries && !item.IsRepeat) {
|
||||
miscInfo.push({
|
||||
html: '<div class="mediaInfoProgramAttribute mediaInfoItem newTvProgram">' + globalize.translate('AttributeNew') + '</div>'
|
||||
html: `<div class="mediaInfoProgramAttribute mediaInfoItem newTvProgram">${globalize.translate('New')}</div>`
|
||||
});
|
||||
} else if (item.IsSeries && item.IsRepeat) {
|
||||
miscInfo.push({
|
||||
html: '<div class="mediaInfoProgramAttribute mediaInfoItem repeatTvProgram">' + globalize.translate('Repeat') + '</div>'
|
||||
html: `<div class="mediaInfoProgramAttribute mediaInfoItem repeatTvProgram">${globalize.translate('Repeat')}</div>`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ((item.IsSeries || item.EpisodeTitle) && options.episodeTitle !== false) {
|
||||
|
||||
text = itemHelper.getDisplayName(item, {
|
||||
includeIndexNumber: options.episodeTitleIndexNumber
|
||||
});
|
||||
@@ -242,13 +227,12 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
} else if (item.IsMovie && item.ProductionYear && options.originalAirDate !== false) {
|
||||
miscInfo.push(item.ProductionYear);
|
||||
} else if (item.PremiereDate && options.originalAirDate !== false) {
|
||||
|
||||
try {
|
||||
date = datetime.parseISO8601Date(item.PremiereDate);
|
||||
text = globalize.translate('OriginalAirDateValue', datetime.toLocaleDateString(date));
|
||||
miscInfo.push(text);
|
||||
} catch (e) {
|
||||
console.error('error parsing date: ' + item.PremiereDate);
|
||||
console.error('error parsing date:', item.PremiereDate);
|
||||
}
|
||||
} else if (item.ProductionYear) {
|
||||
miscInfo.push(item.ProductionYear);
|
||||
@@ -257,34 +241,28 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
|
||||
if (options.year !== false) {
|
||||
if (item.Type !== 'Series' && item.Type !== 'Episode' && item.Type !== 'Person' && item.MediaType !== 'Photo' && item.Type !== 'Program' && item.Type !== 'Season') {
|
||||
|
||||
if (item.ProductionYear) {
|
||||
|
||||
miscInfo.push(item.ProductionYear);
|
||||
} else if (item.PremiereDate) {
|
||||
|
||||
try {
|
||||
text = datetime.parseISO8601Date(item.PremiereDate).getFullYear();
|
||||
miscInfo.push(text);
|
||||
} catch (e) {
|
||||
console.error('error parsing date: ' + item.PremiereDate);
|
||||
console.error('error parsing date:', item.PremiereDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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') {
|
||||
|
||||
miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
|
||||
|
||||
} else {
|
||||
minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
minutes = minutes || 1;
|
||||
|
||||
miscInfo.push(Math.round(minutes) + ' mins');
|
||||
miscInfo.push(`${Math.round(minutes)} mins`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,14 +278,14 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
if (item.MediaType === 'Photo' && item.Width && item.Height) {
|
||||
miscInfo.push(item.Width + 'x' + item.Height);
|
||||
miscInfo.push(`${item.Width}x${item.Height}`);
|
||||
}
|
||||
|
||||
if (options.container !== false && item.Type === 'Audio' && item.Container) {
|
||||
miscInfo.push(item.Container);
|
||||
}
|
||||
|
||||
html += miscInfo.map(function (m) {
|
||||
html += miscInfo.map(m => {
|
||||
return getMediaInfoItem(m);
|
||||
}).join('');
|
||||
|
||||
@@ -318,17 +296,15 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
if (item.CriticRating && options.criticRating !== false) {
|
||||
|
||||
if (item.CriticRating >= 60) {
|
||||
html += '<div class="mediaInfoItem mediaInfoCriticRating mediaInfoCriticRatingFresh">' + item.CriticRating + '</div>';
|
||||
html += `<div class="mediaInfoItem mediaInfoCriticRating mediaInfoCriticRatingFresh">${item.CriticRating}</div>`;
|
||||
} else {
|
||||
html += '<div class="mediaInfoItem mediaInfoCriticRating mediaInfoCriticRatingRotten">' + item.CriticRating + '</div>';
|
||||
html += `<div class="mediaInfoItem mediaInfoCriticRating mediaInfoCriticRatingRotten">${item.CriticRating}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.endsAt !== false) {
|
||||
|
||||
var endsAt = getEndsAt(item);
|
||||
const endsAt = getEndsAt(item);
|
||||
if (endsAt) {
|
||||
html += getMediaInfoItem(endsAt, 'endsAt');
|
||||
}
|
||||
@@ -339,15 +315,13 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
return html;
|
||||
}
|
||||
|
||||
function getEndsAt(item) {
|
||||
|
||||
export function getEndsAt(item) {
|
||||
if (item.MediaType === 'Video' && item.RunTimeTicks) {
|
||||
|
||||
if (!item.StartDate) {
|
||||
var endDate = new Date().getTime() + (item.RunTimeTicks / 10000);
|
||||
let endDate = new Date().getTime() + (item.RunTimeTicks / 10000);
|
||||
endDate = new Date(endDate);
|
||||
|
||||
var displayTime = datetime.getDisplayTime(endDate);
|
||||
const displayTime = datetime.getDisplayTime(endDate);
|
||||
return globalize.translate('EndsAtValue', displayTime);
|
||||
}
|
||||
}
|
||||
@@ -355,12 +329,11 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
return null;
|
||||
}
|
||||
|
||||
function getEndsAtFromPosition(runtimeTicks, positionTicks, includeText) {
|
||||
|
||||
var endDate = new Date().getTime() + ((runtimeTicks - (positionTicks || 0)) / 10000);
|
||||
export function getEndsAtFromPosition(runtimeTicks, positionTicks, includeText) {
|
||||
let endDate = new Date().getTime() + ((runtimeTicks - (positionTicks || 0)) / 10000);
|
||||
endDate = new Date(endDate);
|
||||
|
||||
var displayTime = datetime.getDisplayTime(endDate);
|
||||
const displayTime = datetime.getDisplayTime(endDate);
|
||||
|
||||
if (includeText === false) {
|
||||
return displayTime;
|
||||
@@ -369,23 +342,21 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
function getMediaInfoItem(m, cssClass) {
|
||||
|
||||
cssClass = cssClass ? (cssClass + ' mediaInfoItem') : 'mediaInfoItem';
|
||||
var mediaInfoText = m;
|
||||
cssClass = cssClass ? (`${cssClass} mediaInfoItem`) : 'mediaInfoItem';
|
||||
let mediaInfoText = m;
|
||||
|
||||
if (typeof (m) !== 'string' && typeof (m) !== 'number') {
|
||||
|
||||
if (m.html) {
|
||||
return m.html;
|
||||
}
|
||||
mediaInfoText = m.text;
|
||||
cssClass += ' ' + m.cssClass;
|
||||
cssClass += ` ${m.cssClass}`;
|
||||
}
|
||||
return '<div class="' + cssClass + '">' + mediaInfoText + '</div>';
|
||||
return `<div class="${cssClass}">${mediaInfoText}</div>`;
|
||||
}
|
||||
|
||||
function getStarIconsHtml(item) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
if (item.CommunityRating) {
|
||||
html += '<div class="starRatingContainer mediaInfoItem">';
|
||||
@@ -399,53 +370,47 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
function dynamicEndTime(elem, item) {
|
||||
|
||||
var interval = setInterval(function () {
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (!document.body.contains(elem)) {
|
||||
|
||||
clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
|
||||
elem.innerHTML = getEndsAt(item);
|
||||
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
function fillPrimaryMediaInfo(elem, item, options) {
|
||||
var html = getPrimaryMediaInfoHtml(item, options);
|
||||
export function fillPrimaryMediaInfo(elem, item, options) {
|
||||
const html = getPrimaryMediaInfoHtml(item, options);
|
||||
|
||||
elem.innerHTML = html;
|
||||
afterFill(elem, item, options);
|
||||
}
|
||||
|
||||
function fillSecondaryMediaInfo(elem, item, options) {
|
||||
var html = getSecondaryMediaInfoHtml(item, options);
|
||||
export function fillSecondaryMediaInfo(elem, item, options) {
|
||||
const html = getSecondaryMediaInfoHtml(item, options);
|
||||
|
||||
elem.innerHTML = html;
|
||||
afterFill(elem, item, options);
|
||||
}
|
||||
|
||||
function afterFill(elem, item, options) {
|
||||
|
||||
if (options.endsAt !== false) {
|
||||
var endsAtElem = elem.querySelector('.endsAt');
|
||||
const endsAtElem = elem.querySelector('.endsAt');
|
||||
if (endsAtElem) {
|
||||
dynamicEndTime(endsAtElem, item);
|
||||
}
|
||||
}
|
||||
|
||||
var lnkChannel = elem.querySelector('.lnkChannel');
|
||||
const lnkChannel = elem.querySelector('.lnkChannel');
|
||||
if (lnkChannel) {
|
||||
lnkChannel.addEventListener('click', onChannelLinkClick);
|
||||
}
|
||||
}
|
||||
|
||||
function onChannelLinkClick(e) {
|
||||
|
||||
var channelId = this.getAttribute('data-id');
|
||||
var serverId = this.getAttribute('data-serverid');
|
||||
const channelId = this.getAttribute('data-id');
|
||||
const serverId = this.getAttribute('data-serverid');
|
||||
|
||||
appRouter.showItem(channelId, serverId);
|
||||
|
||||
@@ -453,8 +418,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
return false;
|
||||
}
|
||||
|
||||
function getPrimaryMediaInfoHtml(item, options) {
|
||||
|
||||
export function getPrimaryMediaInfoHtml(item, options) {
|
||||
options = options || {};
|
||||
if (options.interactive == null) {
|
||||
options.interactive = false;
|
||||
@@ -463,8 +427,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
return getMediaInfoHtml(item, options);
|
||||
}
|
||||
|
||||
function getSecondaryMediaInfoHtml(item, options) {
|
||||
|
||||
export function getSecondaryMediaInfoHtml(item, options) {
|
||||
options = options || {};
|
||||
if (options.interactive == null) {
|
||||
options.interactive = false;
|
||||
@@ -476,13 +439,11 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
return '';
|
||||
}
|
||||
|
||||
function getResolutionText(i) {
|
||||
|
||||
var width = i.Width;
|
||||
var height = i.Height;
|
||||
export function getResolutionText(i) {
|
||||
const width = i.Width;
|
||||
const height = i.Height;
|
||||
|
||||
if (width && height) {
|
||||
|
||||
if (width >= 3800 || height >= 2000) {
|
||||
return '4K';
|
||||
}
|
||||
@@ -505,45 +466,41 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
return '720p';
|
||||
}
|
||||
if (width >= 700 || height >= 400) {
|
||||
|
||||
if (i.IsInterlaced) {
|
||||
return '480i';
|
||||
}
|
||||
return '480p';
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getAudioStreamForDisplay(item) {
|
||||
|
||||
if (!item.MediaSources) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var mediaSource = item.MediaSources[0];
|
||||
const mediaSource = item.MediaSources[0];
|
||||
if (!mediaSource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (mediaSource.MediaStreams || []).filter(function (i) {
|
||||
return (mediaSource.MediaStreams || []).filter(i => {
|
||||
return i.Type === 'Audio' && (i.Index === mediaSource.DefaultAudioStreamIndex || mediaSource.DefaultAudioStreamIndex == null);
|
||||
})[0];
|
||||
}
|
||||
|
||||
function getMediaInfoStats(item, options) {
|
||||
|
||||
export function getMediaInfoStats(item, options) {
|
||||
options = options || {};
|
||||
|
||||
var list = [];
|
||||
const list = [];
|
||||
|
||||
var mediaSource = (item.MediaSources || [])[0] || {};
|
||||
const mediaSource = (item.MediaSources || [])[0] || {};
|
||||
|
||||
var videoStream = (mediaSource.MediaStreams || []).filter(function (i) {
|
||||
const videoStream = (mediaSource.MediaStreams || []).filter(i => {
|
||||
return i.Type === 'Video';
|
||||
})[0] || {};
|
||||
var audioStream = getAudioStreamForDisplay(item) || {};
|
||||
const audioStream = getAudioStreamForDisplay(item) || {};
|
||||
|
||||
if (item.VideoType === 'Dvd') {
|
||||
list.push({
|
||||
@@ -559,11 +516,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
});
|
||||
}
|
||||
|
||||
//if (mediaSource.Container) {
|
||||
// html += '<div class="mediaInfoIcon mediaInfoText">' + mediaSource.Container + '</div>';
|
||||
//}
|
||||
|
||||
var resolutionText = getResolutionText(videoStream);
|
||||
const resolutionText = getResolutionText(videoStream);
|
||||
if (resolutionText) {
|
||||
list.push({
|
||||
type: 'mediainfo',
|
||||
@@ -578,23 +531,16 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
});
|
||||
}
|
||||
|
||||
var channels = audioStream.Channels;
|
||||
var channelText;
|
||||
const channels = audioStream.Channels;
|
||||
let channelText;
|
||||
|
||||
if (channels === 8) {
|
||||
|
||||
channelText = '7.1';
|
||||
|
||||
} else if (channels === 7) {
|
||||
|
||||
channelText = '6.1';
|
||||
|
||||
} else if (channels === 6) {
|
||||
|
||||
channelText = '5.1';
|
||||
|
||||
} else if (channels === 2) {
|
||||
|
||||
channelText = '2.0';
|
||||
}
|
||||
|
||||
@@ -605,7 +551,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
});
|
||||
}
|
||||
|
||||
var audioCodec = (audioStream.Codec || '').toLowerCase();
|
||||
const audioCodec = (audioStream.Codec || '').toLowerCase();
|
||||
|
||||
if ((audioCodec === 'dca' || audioCodec === 'dts') && audioStream.Profile) {
|
||||
list.push({
|
||||
@@ -620,28 +566,27 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater
|
||||
}
|
||||
|
||||
if (item.DateCreated && itemHelper.enableDateAddedDisplay(item)) {
|
||||
|
||||
var dateCreated = datetime.parseISO8601Date(item.DateCreated);
|
||||
const dateCreated = datetime.parseISO8601Date(item.DateCreated);
|
||||
|
||||
list.push({
|
||||
type: 'added',
|
||||
text: globalize.translate('AddedOnValue', datetime.toLocaleDateString(dateCreated) + ' ' + datetime.getDisplayTime(dateCreated))
|
||||
text: globalize.translate('AddedOnValue', `${datetime.toLocaleDateString(dateCreated)} ${datetime.getDisplayTime(dateCreated)}`)
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return {
|
||||
getMediaInfoHtml: getPrimaryMediaInfoHtml,
|
||||
fill: fillPrimaryMediaInfo,
|
||||
getEndsAt: getEndsAt,
|
||||
getEndsAtFromPosition: getEndsAtFromPosition,
|
||||
getPrimaryMediaInfoHtml: getPrimaryMediaInfoHtml,
|
||||
getSecondaryMediaInfoHtml: getSecondaryMediaInfoHtml,
|
||||
fillPrimaryMediaInfo: fillPrimaryMediaInfo,
|
||||
fillSecondaryMediaInfo: fillSecondaryMediaInfo,
|
||||
getMediaInfoStats: getMediaInfoStats,
|
||||
getResolutionText: getResolutionText
|
||||
};
|
||||
});
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
getMediaInfoHtml: getPrimaryMediaInfoHtml,
|
||||
getEndsAt: getEndsAt,
|
||||
getEndsAtFromPosition: getEndsAtFromPosition,
|
||||
getPrimaryMediaInfoHtml: getPrimaryMediaInfoHtml,
|
||||
getSecondaryMediaInfoHtml: getSecondaryMediaInfoHtml,
|
||||
fillPrimaryMediaInfo: fillPrimaryMediaInfo,
|
||||
fillSecondaryMediaInfo: fillSecondaryMediaInfo,
|
||||
getMediaInfoStats: getMediaInfoStats,
|
||||
getResolutionText: getResolutionText
|
||||
};
|
||||
|
||||
@@ -1,26 +1,41 @@
|
||||
define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loading', 'focusManager', 'connectionManager', 'globalize', 'require', 'shell', 'emby-checkbox', 'emby-input', 'emby-select', 'listViewStyle', 'emby-textarea', 'emby-button', 'paper-icon-button-light', 'css!./../formdialog', 'clearButtonStyle', 'flexStyles'], function (itemHelper, dom, layoutManager, dialogHelper, datetime, loading, focusManager, connectionManager, globalize, require, shell) {
|
||||
'use strict';
|
||||
import dom from 'dom';
|
||||
import layoutManager from 'layoutManager';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import datetime from 'datetime';
|
||||
import loading from 'loading';
|
||||
import focusManager from 'focusManager';
|
||||
import globalize from 'globalize';
|
||||
import shell from 'shell';
|
||||
import 'emby-checkbox';
|
||||
import 'emby-input';
|
||||
import 'emby-select';
|
||||
import 'listViewStyle';
|
||||
import 'emby-textarea';
|
||||
import 'emby-button';
|
||||
import 'paper-icon-button-light';
|
||||
import 'css!./../formdialog';
|
||||
import 'clearButtonStyle';
|
||||
import 'flexStyles';
|
||||
|
||||
var currentContext;
|
||||
var metadataEditorInfo;
|
||||
var currentItem;
|
||||
/* eslint-disable indent */
|
||||
|
||||
let currentContext;
|
||||
let metadataEditorInfo;
|
||||
let currentItem;
|
||||
|
||||
function isDialog() {
|
||||
return currentContext.classList.contains('dialog');
|
||||
}
|
||||
|
||||
function closeDialog(isSubmitted) {
|
||||
|
||||
if (isDialog()) {
|
||||
dialogHelper.close(currentContext);
|
||||
}
|
||||
}
|
||||
|
||||
function submitUpdatedItem(form, item) {
|
||||
|
||||
function afterContentTypeUpdated() {
|
||||
|
||||
require(['toast'], function (toast) {
|
||||
import('toast').then(({default: toast}) => {
|
||||
toast(globalize.translate('MessageItemSaved'));
|
||||
});
|
||||
|
||||
@@ -28,14 +43,12 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
closeDialog(true);
|
||||
}
|
||||
|
||||
var apiClient = getApiClient();
|
||||
const apiClient = getApiClient();
|
||||
|
||||
apiClient.updateItem(item).then(function () {
|
||||
|
||||
var newContentType = form.querySelector('#selectContentType').value || '';
|
||||
const newContentType = form.querySelector('#selectContentType').value || '';
|
||||
|
||||
if ((metadataEditorInfo.ContentType || '') !== newContentType) {
|
||||
|
||||
apiClient.ajax({
|
||||
|
||||
url: apiClient.getUrl('Items/' + item.Id + '/ContentType', {
|
||||
@@ -47,29 +60,23 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}).then(function () {
|
||||
afterContentTypeUpdated();
|
||||
});
|
||||
|
||||
} else {
|
||||
afterContentTypeUpdated();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function getSelectedAirDays(form) {
|
||||
var checkedItems = form.querySelectorAll('.chkAirDay:checked') || [];
|
||||
const checkedItems = form.querySelectorAll('.chkAirDay:checked') || [];
|
||||
return Array.prototype.map.call(checkedItems, function (c) {
|
||||
return c.getAttribute('data-day');
|
||||
});
|
||||
}
|
||||
|
||||
function getAlbumArtists(form) {
|
||||
|
||||
return form.querySelector('#txtAlbumArtist').value.trim().split(';').filter(function (s) {
|
||||
|
||||
return s.length > 0;
|
||||
|
||||
}).map(function (a) {
|
||||
|
||||
return {
|
||||
Name: a
|
||||
};
|
||||
@@ -77,13 +84,9 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function getArtists(form) {
|
||||
|
||||
return form.querySelector('#txtArtist').value.trim().split(';').filter(function (s) {
|
||||
|
||||
return s.length > 0;
|
||||
|
||||
}).map(function (a) {
|
||||
|
||||
return {
|
||||
Name: a
|
||||
};
|
||||
@@ -91,23 +94,20 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function getDateValue(form, element, property) {
|
||||
|
||||
var val = form.querySelector(element).value;
|
||||
let val = form.querySelector(element).value;
|
||||
|
||||
if (!val) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (currentItem[property]) {
|
||||
const date = datetime.parseISO8601Date(currentItem[property], true);
|
||||
|
||||
var date = datetime.parseISO8601Date(currentItem[property], true);
|
||||
|
||||
var parts = date.toISOString().split('T');
|
||||
const parts = date.toISOString().split('T');
|
||||
|
||||
// If the date is the same, preserve the time
|
||||
if (parts[0].indexOf(val) === 0) {
|
||||
|
||||
var iso = parts[1];
|
||||
const iso = parts[1];
|
||||
|
||||
val += 'T' + iso;
|
||||
}
|
||||
@@ -117,12 +117,11 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function onSubmit(e) {
|
||||
|
||||
loading.show();
|
||||
|
||||
var form = this;
|
||||
const form = this;
|
||||
|
||||
var item = {
|
||||
const item = {
|
||||
Id: currentItem.Id,
|
||||
Name: form.querySelector('#txtName').value,
|
||||
OriginalTitle: form.querySelector('#txtOriginalName').value,
|
||||
@@ -168,9 +167,9 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
|
||||
item.ProviderIds = Object.assign({}, currentItem.ProviderIds);
|
||||
|
||||
var idElements = form.querySelectorAll('.txtExternalId');
|
||||
const idElements = form.querySelectorAll('.txtExternalId');
|
||||
Array.prototype.map.call(idElements, function (idElem) {
|
||||
var providerKey = idElem.getAttribute('data-providerkey');
|
||||
const providerKey = idElem.getAttribute('data-providerkey');
|
||||
item.ProviderIds[providerKey] = idElem.value;
|
||||
});
|
||||
|
||||
@@ -178,20 +177,18 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
item.PreferredMetadataCountryCode = form.querySelector('#selectCountry').value;
|
||||
|
||||
if (currentItem.Type === 'Person') {
|
||||
|
||||
var placeOfBirth = form.querySelector('#txtPlaceOfBirth').value;
|
||||
const placeOfBirth = form.querySelector('#txtPlaceOfBirth').value;
|
||||
|
||||
item.ProductionLocations = placeOfBirth ? [placeOfBirth] : [];
|
||||
}
|
||||
|
||||
if (currentItem.Type === 'Series') {
|
||||
|
||||
// 600000000
|
||||
var seriesRuntime = form.querySelector('#txtSeriesRuntime').value;
|
||||
const seriesRuntime = form.querySelector('#txtSeriesRuntime').value;
|
||||
item.RunTimeTicks = seriesRuntime ? (seriesRuntime * 600000000) : null;
|
||||
}
|
||||
|
||||
var tagline = form.querySelector('#txtTagline').value;
|
||||
const tagline = form.querySelector('#txtTagline').value;
|
||||
item.Taglines = tagline ? [tagline] : [];
|
||||
|
||||
submitUpdatedItem(form, item);
|
||||
@@ -210,13 +207,12 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function addElementToList(source, sortCallback) {
|
||||
require(['prompt'], function (prompt) {
|
||||
|
||||
import('prompt').then(({default: prompt}) => {
|
||||
prompt({
|
||||
label: 'Value:'
|
||||
}).then(function (text) {
|
||||
var list = dom.parentWithClass(source, 'editableListviewContainer').querySelector('.paperList');
|
||||
var items = getListValues(list);
|
||||
const list = dom.parentWithClass(source, 'editableListviewContainer').querySelector('.paperList');
|
||||
const items = getListValues(list);
|
||||
items.push(text);
|
||||
populateListView(list, items, sortCallback);
|
||||
});
|
||||
@@ -224,17 +220,14 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function removeElementFromList(source) {
|
||||
var el = dom.parentWithClass(source, 'listItem');
|
||||
const el = dom.parentWithClass(source, 'listItem');
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
|
||||
function editPerson(context, person, index) {
|
||||
|
||||
require(['personEditor'], function (personEditor) {
|
||||
|
||||
import('personEditor').then(({default: personEditor}) => {
|
||||
personEditor.show(person).then(function (updatedPerson) {
|
||||
|
||||
var isNew = index === -1;
|
||||
const isNew = index === -1;
|
||||
|
||||
if (isNew) {
|
||||
currentItem.People.push(updatedPerson);
|
||||
@@ -245,38 +238,73 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
});
|
||||
}
|
||||
|
||||
function onEditorClick(e) {
|
||||
function afterDeleted(context, item) {
|
||||
var parentId = item.ParentId || item.SeasonId || item.SeriesId;
|
||||
|
||||
var btnRemoveFromEditorList = dom.parentWithClass(e.target, 'btnRemoveFromEditorList');
|
||||
if (parentId) {
|
||||
reload(context, parentId, item.ServerId);
|
||||
} else {
|
||||
import('appRouter').then(({default: appRouter}) => {
|
||||
appRouter.goHome();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showMoreMenu(context, button, user) {
|
||||
import('itemContextMenu').then(({default: itemContextMenu}) => {
|
||||
var item = currentItem;
|
||||
|
||||
itemContextMenu.show({
|
||||
item: item,
|
||||
positionTo: button,
|
||||
edit: false,
|
||||
editImages: true,
|
||||
editSubtitles: true,
|
||||
sync: false,
|
||||
share: false,
|
||||
play: false,
|
||||
queue: false,
|
||||
user: user
|
||||
}).then(function (result) {
|
||||
if (result.deleted) {
|
||||
afterDeleted(context, item);
|
||||
} else if (result.updated) {
|
||||
reload(context, item.Id, item.ServerId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onEditorClick(e) {
|
||||
const btnRemoveFromEditorList = dom.parentWithClass(e.target, 'btnRemoveFromEditorList');
|
||||
if (btnRemoveFromEditorList) {
|
||||
removeElementFromList(btnRemoveFromEditorList);
|
||||
return;
|
||||
}
|
||||
|
||||
var btnAddTextItem = dom.parentWithClass(e.target, 'btnAddTextItem');
|
||||
const btnAddTextItem = dom.parentWithClass(e.target, 'btnAddTextItem');
|
||||
if (btnAddTextItem) {
|
||||
addElementToList(btnAddTextItem);
|
||||
}
|
||||
}
|
||||
|
||||
function getApiClient() {
|
||||
return connectionManager.getApiClient(currentItem.ServerId);
|
||||
return window.connectionManager.getApiClient(currentItem.ServerId);
|
||||
}
|
||||
|
||||
function bindAll(elems, eventName, fn) {
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener(eventName, fn);
|
||||
}
|
||||
}
|
||||
|
||||
function init(context, apiClient) {
|
||||
|
||||
context.querySelector('.externalIds').addEventListener('click', function (e) {
|
||||
var btnOpenExternalId = dom.parentWithClass(e.target, 'btnOpenExternalId');
|
||||
const btnOpenExternalId = dom.parentWithClass(e.target, 'btnOpenExternalId');
|
||||
if (btnOpenExternalId) {
|
||||
var field = context.querySelector('#' + btnOpenExternalId.getAttribute('data-fieldid'));
|
||||
const field = context.querySelector('#' + btnOpenExternalId.getAttribute('data-fieldid'));
|
||||
|
||||
var formatString = field.getAttribute('data-formatstring');
|
||||
const formatString = field.getAttribute('data-formatstring');
|
||||
|
||||
if (field.value) {
|
||||
shell.openUrl(formatString.replace('{0}', field.value));
|
||||
@@ -294,13 +322,17 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
closeDialog(false);
|
||||
});
|
||||
|
||||
context.querySelector('.btnHeaderSave').addEventListener('click', function (e) {
|
||||
context.querySelector('.btnMore').addEventListener('click', function (e) {
|
||||
getApiClient().getCurrentUser().then(function (user) {
|
||||
showMoreMenu(context, e.target, user);
|
||||
});
|
||||
});
|
||||
|
||||
context.querySelector('.btnHeaderSave').addEventListener('click', function (e) {
|
||||
context.querySelector('.btnSave').click();
|
||||
});
|
||||
|
||||
context.querySelector('#chkLockData').addEventListener('click', function (e) {
|
||||
|
||||
if (!e.target.checked) {
|
||||
showElement('.providerSettingsContainer');
|
||||
} else {
|
||||
@@ -308,29 +340,27 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
});
|
||||
|
||||
context.removeEventListener('submit', onEditorClick);
|
||||
context.addEventListener('submit', onEditorClick);
|
||||
context.removeEventListener('click', onEditorClick);
|
||||
context.addEventListener('click', onEditorClick);
|
||||
|
||||
var form = context.querySelector('form');
|
||||
const form = context.querySelector('form');
|
||||
form.removeEventListener('submit', onSubmit);
|
||||
form.addEventListener('submit', onSubmit);
|
||||
|
||||
context.querySelector('#btnAddPerson').addEventListener('click', function (event, data) {
|
||||
|
||||
editPerson(context, {}, -1);
|
||||
});
|
||||
|
||||
context.querySelector('#peopleList').addEventListener('click', function (e) {
|
||||
|
||||
var index;
|
||||
var btnDeletePerson = dom.parentWithClass(e.target, 'btnDeletePerson');
|
||||
let index;
|
||||
const btnDeletePerson = dom.parentWithClass(e.target, 'btnDeletePerson');
|
||||
if (btnDeletePerson) {
|
||||
index = parseInt(btnDeletePerson.getAttribute('data-index'));
|
||||
currentItem.People.splice(index, 1);
|
||||
populatePeople(context, currentItem.People);
|
||||
}
|
||||
|
||||
var btnEditPerson = dom.parentWithClass(e.target, 'btnEditPerson');
|
||||
const btnEditPerson = dom.parentWithClass(e.target, 'btnEditPerson');
|
||||
if (btnEditPerson) {
|
||||
index = parseInt(btnEditPerson.getAttribute('data-index'));
|
||||
editPerson(context, currentItem.People[index], index);
|
||||
@@ -339,8 +369,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function getItem(itemId, serverId) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
if (itemId) {
|
||||
return apiClient.getItem(apiClient.getCurrentUserId(), itemId);
|
||||
@@ -350,8 +379,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function getEditorConfig(itemId, serverId) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
const apiClient = window.connectionManager.getApiClient(serverId);
|
||||
|
||||
if (itemId) {
|
||||
return apiClient.getJSON(apiClient.getUrl('Items/' + itemId + '/MetadataEditor'));
|
||||
@@ -361,14 +389,12 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function populateCountries(select, allCountries) {
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
|
||||
for (var i = 0, length = allCountries.length; i < length; i++) {
|
||||
|
||||
var culture = allCountries[i];
|
||||
for (let i = 0, length = allCountries.length; i < length; i++) {
|
||||
const culture = allCountries[i];
|
||||
|
||||
html += "<option value='" + culture.TwoLetterISORegionName + "'>" + culture.DisplayName + '</option>';
|
||||
}
|
||||
@@ -377,14 +403,12 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function populateLanguages(select, languages) {
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
|
||||
for (var i = 0, length = languages.length; i < length; i++) {
|
||||
|
||||
var culture = languages[i];
|
||||
for (let i = 0, length = languages.length; i < length; i++) {
|
||||
const culture = languages[i];
|
||||
|
||||
html += "<option value='" + culture.TwoLetterISOLanguageName + "'>" + culture.DisplayName + '</option>';
|
||||
}
|
||||
@@ -393,48 +417,43 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function renderContentTypeOptions(context, metadataInfo) {
|
||||
|
||||
if (!metadataInfo.ContentTypeOptions.length) {
|
||||
hideElement('#fldContentType', context);
|
||||
} else {
|
||||
showElement('#fldContentType', context);
|
||||
}
|
||||
|
||||
var html = metadataInfo.ContentTypeOptions.map(function (i) {
|
||||
|
||||
const html = metadataInfo.ContentTypeOptions.map(function (i) {
|
||||
return '<option value="' + i.Value + '">' + i.Name + '</option>';
|
||||
|
||||
}).join('');
|
||||
|
||||
var selectEl = context.querySelector('#selectContentType');
|
||||
const selectEl = context.querySelector('#selectContentType');
|
||||
selectEl.innerHTML = html;
|
||||
selectEl.value = metadataInfo.ContentType || '';
|
||||
}
|
||||
|
||||
function loadExternalIds(context, item, externalIds) {
|
||||
let html = '';
|
||||
|
||||
var html = '';
|
||||
const providerIds = item.ProviderIds || {};
|
||||
|
||||
var providerIds = item.ProviderIds || {};
|
||||
for (let i = 0, length = externalIds.length; i < length; i++) {
|
||||
const idInfo = externalIds[i];
|
||||
|
||||
for (var i = 0, length = externalIds.length; i < length; i++) {
|
||||
const id = 'txt1' + idInfo.Key;
|
||||
const formatString = idInfo.UrlFormatString || '';
|
||||
|
||||
var idInfo = externalIds[i];
|
||||
|
||||
var id = 'txt1' + idInfo.Key;
|
||||
var formatString = idInfo.UrlFormatString || '';
|
||||
|
||||
var fullName = idInfo.Name;
|
||||
let fullName = idInfo.Name;
|
||||
if (idInfo.Type) {
|
||||
fullName = idInfo.Name + ' ' + globalize.translate(idInfo.Type);
|
||||
}
|
||||
|
||||
var labelText = globalize.translate('LabelDynamicExternalId', fullName);
|
||||
const labelText = globalize.translate('LabelDynamicExternalId', fullName);
|
||||
|
||||
html += '<div class="inputContainer">';
|
||||
html += '<div class="flex align-items-center">';
|
||||
|
||||
var value = providerIds[idInfo.Key] || '';
|
||||
const value = providerIds[idInfo.Key] || '';
|
||||
|
||||
html += '<div class="flex-grow">';
|
||||
html += '<input is="emby-input" class="txtExternalId" value="' + value + '" data-providerkey="' + idInfo.Key + '" data-formatstring="' + formatString + '" id="' + id + '" label="' + labelText + '"/>';
|
||||
@@ -448,7 +467,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
var elem = context.querySelector('.externalIds', context);
|
||||
const elem = context.querySelector('.externalIds', context);
|
||||
elem.innerHTML = html;
|
||||
|
||||
if (externalIds.length) {
|
||||
@@ -464,8 +483,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
function hideElement(selector, context, multiple) {
|
||||
context = context || document;
|
||||
if (typeof selector === 'string') {
|
||||
|
||||
var elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)];
|
||||
const elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)];
|
||||
|
||||
Array.prototype.forEach.call(elements, function (el) {
|
||||
if (el) {
|
||||
@@ -483,8 +501,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
function showElement(selector, context, multiple) {
|
||||
context = context || document;
|
||||
if (typeof selector === 'string') {
|
||||
|
||||
var elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)];
|
||||
const elements = multiple ? context.querySelectorAll(selector) : [context.querySelector(selector)];
|
||||
|
||||
Array.prototype.forEach.call(elements, function (el) {
|
||||
if (el) {
|
||||
@@ -685,8 +702,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function fillItemInfo(context, item, parentalRatingOptions) {
|
||||
|
||||
var select = context.querySelector('#selectOfficialRating');
|
||||
let select = context.querySelector('#selectOfficialRating');
|
||||
|
||||
populateRatings(parentalRatingOptions, select, item.OfficialRating);
|
||||
|
||||
@@ -698,7 +714,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
|
||||
select.value = item.CustomRating || '';
|
||||
|
||||
var selectStatus = context.querySelector('#selectStatus');
|
||||
const selectStatus = context.querySelector('#selectStatus');
|
||||
populateStatus(selectStatus);
|
||||
selectStatus.value = item.Status || '';
|
||||
|
||||
@@ -717,8 +733,8 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
|
||||
populateListView(context.querySelector('#listTags'), item.Tags);
|
||||
|
||||
var lockData = (item.LockData || false);
|
||||
var chkLockData = context.querySelector('#chkLockData');
|
||||
const lockData = (item.LockData || false);
|
||||
const chkLockData = context.querySelector('#chkLockData');
|
||||
chkLockData.checked = lockData;
|
||||
if (chkLockData.checked) {
|
||||
hideElement('.providerSettingsContainer', context);
|
||||
@@ -756,7 +772,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
return a.Name;
|
||||
}).join(';');
|
||||
|
||||
var date;
|
||||
let date;
|
||||
|
||||
if (item.DateCreated) {
|
||||
try {
|
||||
@@ -798,7 +814,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
|
||||
context.querySelector('#txtAirTime').value = item.AirTime || '';
|
||||
|
||||
var placeofBirth = item.ProductionLocations && item.ProductionLocations.length ? item.ProductionLocations[0] : '';
|
||||
const placeofBirth = item.ProductionLocations && item.ProductionLocations.length ? item.ProductionLocations[0] : '';
|
||||
context.querySelector('#txtPlaceOfBirth').value = placeofBirth;
|
||||
|
||||
context.querySelector('#txtOriginalAspectRatio').value = item.AspectRatio || '';
|
||||
@@ -807,8 +823,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
context.querySelector('#selectCountry').value = item.PreferredMetadataCountryCode || '';
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
|
||||
var minutes = item.RunTimeTicks / 600000000;
|
||||
const minutes = item.RunTimeTicks / 600000000;
|
||||
|
||||
context.querySelector('#txtSeriesRuntime').value = Math.round(minutes);
|
||||
} else {
|
||||
@@ -817,20 +832,16 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function populateRatings(allParentalRatings, select, currentValue) {
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
|
||||
var ratings = [];
|
||||
var i;
|
||||
var length;
|
||||
var rating;
|
||||
const ratings = [];
|
||||
let rating;
|
||||
|
||||
var currentValueFound = false;
|
||||
|
||||
for (i = 0, length = allParentalRatings.length; i < length; i++) {
|
||||
let currentValueFound = false;
|
||||
|
||||
for (let i = 0, length = allParentalRatings.length; i < length; i++) {
|
||||
rating = allParentalRatings[i];
|
||||
|
||||
ratings.push({ Name: rating.Name, Value: rating.Name });
|
||||
@@ -844,8 +855,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
ratings.push({ Name: currentValue, Value: currentValue });
|
||||
}
|
||||
|
||||
for (i = 0, length = ratings.length; i < length; i++) {
|
||||
|
||||
for (let i = 0, length = ratings.length; i < length; i++) {
|
||||
rating = ratings[i];
|
||||
|
||||
html += "<option value='" + rating.Value + "'>" + rating.Name + '</option>';
|
||||
@@ -855,7 +865,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function populateStatus(select) {
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += "<option value=''></option>";
|
||||
html += "<option value='Continuing'>" + globalize.translate('Continuing') + '</option>';
|
||||
@@ -864,7 +874,6 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function populateListView(list, items, sortCallback) {
|
||||
|
||||
items = items || [];
|
||||
if (typeof (sortCallback) === 'undefined') {
|
||||
items.sort(function (a, b) {
|
||||
@@ -873,8 +882,8 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
} else {
|
||||
items = sortCallback(items);
|
||||
}
|
||||
var html = '';
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
let html = '';
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
html += '<div class="listItem">';
|
||||
|
||||
html += '<span class="material-icons listItemIcon live_tv" style="background-color:#333;"></span>';
|
||||
@@ -896,15 +905,13 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function populatePeople(context, people) {
|
||||
const lastType = '';
|
||||
let html = '';
|
||||
|
||||
var lastType = '';
|
||||
var html = '';
|
||||
const elem = context.querySelector('#peopleList');
|
||||
|
||||
var elem = context.querySelector('#peopleList');
|
||||
|
||||
for (var i = 0, length = people.length; i < length; i++) {
|
||||
|
||||
var person = people[i];
|
||||
for (let i = 0, length = people.length; i < length; i++) {
|
||||
const person = people[i];
|
||||
|
||||
html += '<div class="listItem">';
|
||||
|
||||
@@ -933,14 +940,12 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function getLockedFieldsHtml(fields, currentFields) {
|
||||
|
||||
var html = '';
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
|
||||
var field = fields[i];
|
||||
var name = field.name;
|
||||
var value = field.value || field.name;
|
||||
var checkedHtml = currentFields.indexOf(value) === -1 ? ' checked' : '';
|
||||
let html = '';
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const field = fields[i];
|
||||
const name = field.name;
|
||||
const value = field.value || field.name;
|
||||
const checkedHtml = currentFields.indexOf(value) === -1 ? ' checked' : '';
|
||||
html += '<label>';
|
||||
html += '<input type="checkbox" is="emby-checkbox" class="selectLockedField" data-value="' + value + '"' + checkedHtml + '/>';
|
||||
html += '<span>' + name + '</span>';
|
||||
@@ -950,10 +955,10 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function fillMetadataSettings(context, item, lockedFields) {
|
||||
var container = context.querySelector('.providerSettingsContainer');
|
||||
const container = context.querySelector('.providerSettingsContainer');
|
||||
lockedFields = lockedFields || [];
|
||||
|
||||
var lockedFieldsList = [
|
||||
const lockedFieldsList = [
|
||||
{ name: globalize.translate('Name'), value: 'Name' },
|
||||
{ name: globalize.translate('Overview'), value: 'Overview' },
|
||||
{ name: globalize.translate('Genres'), value: 'Genres' },
|
||||
@@ -974,7 +979,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
lockedFieldsList.push({ name: globalize.translate('Studios'), value: 'Studios' });
|
||||
lockedFieldsList.push({ name: globalize.translate('Tags'), value: 'Tags' });
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<h2>' + globalize.translate('HeaderEnabledFields') + '</h2>';
|
||||
html += '<p>' + globalize.translate('HeaderEnabledFieldsHelp') + '</p>';
|
||||
@@ -983,18 +988,16 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function reload(context, itemId, serverId) {
|
||||
|
||||
loading.show();
|
||||
|
||||
Promise.all([getItem(itemId, serverId), getEditorConfig(itemId, serverId)]).then(function (responses) {
|
||||
|
||||
var item = responses[0];
|
||||
const item = responses[0];
|
||||
metadataEditorInfo = responses[1];
|
||||
|
||||
currentItem = item;
|
||||
|
||||
var languages = metadataEditorInfo.Cultures;
|
||||
var countries = metadataEditorInfo.Countries;
|
||||
const languages = metadataEditorInfo.Cultures;
|
||||
const countries = metadataEditorInfo.Countries;
|
||||
|
||||
renderContentTypeOptions(context, metadataEditorInfo);
|
||||
|
||||
@@ -1017,8 +1020,8 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
import('scrollHelper').then(({default: scrollHelper}) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
@@ -1026,9 +1029,8 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
function show(itemId, serverId, resolve, reject) {
|
||||
loading.show();
|
||||
|
||||
require(['text!./metadataEditor.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
import('text!./metadataEditor.template.html').then(({default: template}) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
@@ -1039,13 +1041,13 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += globalize.translateDocument(template, 'core');
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
@@ -1065,13 +1067,13 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
|
||||
currentContext = dlg;
|
||||
|
||||
init(dlg, connectionManager.getApiClient(serverId));
|
||||
init(dlg, window.connectionManager.getApiClient(serverId));
|
||||
|
||||
reload(dlg, itemId, serverId);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
export default {
|
||||
show: function (itemId, serverId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
return show(itemId, serverId, resolve, reject);
|
||||
@@ -1080,20 +1082,19 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
|
||||
embed: function (elem, itemId, serverId) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
loading.show();
|
||||
|
||||
require(['text!./metadataEditor.template.html'], function (template) {
|
||||
|
||||
elem.innerHTML = globalize.translateDocument(template, 'core');
|
||||
import('text!./metadataEditor.template.html').then(({default: template}) => {
|
||||
elem.innerHTML = globalize.translateHtml(template, 'core');
|
||||
|
||||
elem.querySelector('.formDialogFooter').classList.remove('formDialogFooter');
|
||||
elem.querySelector('.btnClose').classList.add('hide');
|
||||
elem.querySelector('.btnHeaderSave').classList.remove('hide');
|
||||
elem.querySelector('.btnCancel').classList.add('hide');
|
||||
|
||||
currentContext = elem;
|
||||
|
||||
init(elem, connectionManager.getApiClient(serverId));
|
||||
init(elem, window.connectionManager.getApiClient(serverId));
|
||||
reload(elem, itemId, serverId);
|
||||
|
||||
focusManager.autoFocus(elem);
|
||||
@@ -1101,4 +1102,5 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
<span class="material-icons check"></span>
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnMore autoSize" tabindex="-1">
|
||||
<span class="material-icons more_vert"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnCancel btnClose autoSize" tabindex="-1">
|
||||
<span class="material-icons close"></span>
|
||||
</button>
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-button-light', 'emby-input', 'emby-select', 'css!./../formdialog'], function (dialogHelper, layoutManager, globalize, require) {
|
||||
'use strict';
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-input';
|
||||
import 'emby-select';
|
||||
import 'css!./../formdialog';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
import('scrollHelper').then(({default: scrollHelper}) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function show(person) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['text!./personEditor.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
import('text!./personEditor.template.html').then(({default: template}) => {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
@@ -24,14 +29,14 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-but
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
const dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
dlg.classList.add('formDialog');
|
||||
|
||||
var html = '';
|
||||
var submitted = false;
|
||||
let html = '';
|
||||
let submitted = false;
|
||||
|
||||
html += globalize.translateDocument(template, 'core');
|
||||
html += globalize.translateHtml(template, 'core');
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
@@ -46,7 +51,6 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-but
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
|
||||
}
|
||||
@@ -59,7 +63,6 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-but
|
||||
});
|
||||
|
||||
dlg.querySelector('.selectPersonType').addEventListener('change', function (e) {
|
||||
|
||||
if (this.value === 'Actor') {
|
||||
dlg.querySelector('.fldRole').classList.remove('hide');
|
||||
} else {
|
||||
@@ -68,12 +71,10 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-but
|
||||
});
|
||||
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
|
||||
dlg.querySelector('form').addEventListener('submit', function (e) {
|
||||
|
||||
submitted = true;
|
||||
|
||||
person.Name = dlg.querySelector('.txtPersonName', dlg).value;
|
||||
@@ -93,7 +94,8 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-but
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: show
|
||||
};
|
||||
});
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
<div class="formDialogContent smoothScrollY" style="padding-top:2em;">
|
||||
<form class="popupEditPersonForm dialogContentInner dialog-content-centered">
|
||||
|
||||
<div class="inputContainer">
|
||||
<input type="text" is="emby-input" class="txtPersonName" required="required" label="${LabelName}" />
|
||||
</div>
|
||||
@@ -23,6 +22,7 @@
|
||||
<option value="Writer">${Writer}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer fldRole hide">
|
||||
<input is="emby-input" type="text" class="txtPersonRole" label="${LabelPersonRole}" />
|
||||
<div class="fieldDescription">${LabelPersonRoleHelp}</div>
|
||||
@@ -33,6 +33,5 @@
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'globalize', 'appRouter', 'dom', 'css!./multiSelect'], function (browser, appStorage, appHost, loading, connectionManager, globalize, appRouter, dom) {
|
||||
'use strict';
|
||||
import browser from 'browser';
|
||||
import appHost from 'apphost';
|
||||
import loading from 'loading';
|
||||
import globalize from 'globalize';
|
||||
import dom from 'dom';
|
||||
import 'css!./multiSelect';
|
||||
|
||||
var selectedItems = [];
|
||||
var selectedElements = [];
|
||||
var currentSelectionCommandsPanel;
|
||||
/* eslint-disable indent */
|
||||
|
||||
let selectedItems = [];
|
||||
let selectedElements = [];
|
||||
let currentSelectionCommandsPanel;
|
||||
|
||||
function hideSelections() {
|
||||
|
||||
var selectionCommandsPanel = currentSelectionCommandsPanel;
|
||||
const selectionCommandsPanel = currentSelectionCommandsPanel;
|
||||
if (selectionCommandsPanel) {
|
||||
|
||||
selectionCommandsPanel.parentNode.removeChild(selectionCommandsPanel);
|
||||
currentSelectionCommandsPanel = null;
|
||||
|
||||
selectedItems = [];
|
||||
selectedElements = [];
|
||||
var elems = document.querySelectorAll('.itemSelectionPanel');
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
var parent = elems[i].parentNode;
|
||||
const elems = document.querySelectorAll('.itemSelectionPanel');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
const parent = elems[i].parentNode;
|
||||
parent.removeChild(elems[i]);
|
||||
parent.classList.remove('withMultiSelect');
|
||||
}
|
||||
@@ -26,17 +29,15 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function onItemSelectionPanelClick(e, itemSelectionPanel) {
|
||||
|
||||
// toggle the checkbox, if it wasn't clicked on
|
||||
if (!dom.parentWithClass(e.target, 'chkItemSelect')) {
|
||||
var chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect');
|
||||
const chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect');
|
||||
|
||||
if (chkItemSelect) {
|
||||
|
||||
if (chkItemSelect.classList.contains('checkedInitial')) {
|
||||
chkItemSelect.classList.remove('checkedInitial');
|
||||
} else {
|
||||
var newValue = !chkItemSelect.checked;
|
||||
const newValue = !chkItemSelect.checked;
|
||||
chkItemSelect.checked = newValue;
|
||||
updateItemSelection(chkItemSelect, newValue);
|
||||
}
|
||||
@@ -49,12 +50,10 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function updateItemSelection(chkItemSelect, selected) {
|
||||
|
||||
var id = dom.parentWithAttribute(chkItemSelect, 'data-id').getAttribute('data-id');
|
||||
const id = dom.parentWithAttribute(chkItemSelect, 'data-id').getAttribute('data-id');
|
||||
|
||||
if (selected) {
|
||||
|
||||
var current = selectedItems.filter(function (i) {
|
||||
const current = selectedItems.filter(i => {
|
||||
return i === id;
|
||||
});
|
||||
|
||||
@@ -62,18 +61,17 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
selectedItems.push(id);
|
||||
selectedElements.push(chkItemSelect);
|
||||
}
|
||||
|
||||
} else {
|
||||
selectedItems = selectedItems.filter(function (i) {
|
||||
selectedItems = selectedItems.filter(i => {
|
||||
return i !== id;
|
||||
});
|
||||
selectedElements = selectedElements.filter(function (i) {
|
||||
selectedElements = selectedElements.filter(i => {
|
||||
return i !== chkItemSelect;
|
||||
});
|
||||
}
|
||||
|
||||
if (selectedItems.length) {
|
||||
var itemSelectionCount = document.querySelector('.itemSelectionCount');
|
||||
const itemSelectionCount = document.querySelector('.itemSelectionCount');
|
||||
if (itemSelectionCount) {
|
||||
itemSelectionCount.innerHTML = selectedItems.length;
|
||||
}
|
||||
@@ -87,107 +85,94 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function showSelection(item, isChecked) {
|
||||
|
||||
var itemSelectionPanel = item.querySelector('.itemSelectionPanel');
|
||||
let itemSelectionPanel = item.querySelector('.itemSelectionPanel');
|
||||
|
||||
if (!itemSelectionPanel) {
|
||||
|
||||
itemSelectionPanel = document.createElement('div');
|
||||
itemSelectionPanel.classList.add('itemSelectionPanel');
|
||||
|
||||
var parent = item.querySelector('.cardBox') || item.querySelector('.cardContent');
|
||||
const parent = item.querySelector('.cardBox') || item.querySelector('.cardContent');
|
||||
parent.classList.add('withMultiSelect');
|
||||
parent.appendChild(itemSelectionPanel);
|
||||
|
||||
var cssClass = 'chkItemSelect';
|
||||
let cssClass = 'chkItemSelect';
|
||||
if (isChecked && !browser.firefox) {
|
||||
// In firefox, the initial tap hold doesnt' get treated as a click
|
||||
// In other browsers it does, so we need to make sure that initial click is ignored
|
||||
cssClass += ' checkedInitial';
|
||||
}
|
||||
var checkedAttribute = isChecked ? ' checked' : '';
|
||||
itemSelectionPanel.innerHTML = '<label class="checkboxContainer"><input type="checkbox" is="emby-checkbox" data-outlineclass="multiSelectCheckboxOutline" class="' + cssClass + '"' + checkedAttribute + '/><span></span></label>';
|
||||
var chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect');
|
||||
const checkedAttribute = isChecked ? ' checked' : '';
|
||||
itemSelectionPanel.innerHTML = `<label class="checkboxContainer"><input type="checkbox" is="emby-checkbox" data-outlineclass="multiSelectCheckboxOutline" class="${cssClass}"${checkedAttribute}/><span></span></label>`;
|
||||
const chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect');
|
||||
chkItemSelect.addEventListener('change', onSelectionChange);
|
||||
}
|
||||
}
|
||||
|
||||
function showSelectionCommands() {
|
||||
|
||||
var selectionCommandsPanel = currentSelectionCommandsPanel;
|
||||
let selectionCommandsPanel = currentSelectionCommandsPanel;
|
||||
|
||||
if (!selectionCommandsPanel) {
|
||||
|
||||
selectionCommandsPanel = document.createElement('div');
|
||||
selectionCommandsPanel.classList.add('selectionCommandsPanel');
|
||||
|
||||
document.body.appendChild(selectionCommandsPanel);
|
||||
currentSelectionCommandsPanel = selectionCommandsPanel;
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseSelectionPanel autoSize"><span class="material-icons close"></span></button>';
|
||||
html += '<h1 class="itemSelectionCount"></h1>';
|
||||
|
||||
const moreIcon = 'more_vert';
|
||||
html += '<button is="paper-icon-button-light" class="btnSelectionPanelOptions autoSize" style="margin-left:auto;"><span class="material-icons ' + moreIcon + '"></span></button>';
|
||||
html += `<button is="paper-icon-button-light" class="btnSelectionPanelOptions autoSize" style="margin-left:auto;"><span class="material-icons ${moreIcon}"></span></button>`;
|
||||
|
||||
selectionCommandsPanel.innerHTML = html;
|
||||
|
||||
selectionCommandsPanel.querySelector('.btnCloseSelectionPanel').addEventListener('click', hideSelections);
|
||||
|
||||
var btnSelectionPanelOptions = selectionCommandsPanel.querySelector('.btnSelectionPanelOptions');
|
||||
const btnSelectionPanelOptions = selectionCommandsPanel.querySelector('.btnSelectionPanelOptions');
|
||||
|
||||
dom.addEventListener(btnSelectionPanelOptions, 'click', showMenuForSelectedItems, { passive: true });
|
||||
}
|
||||
}
|
||||
|
||||
function alertText(options) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
return new Promise((resolve, reject) => {
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert(options).then(resolve, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteItems(apiClient, itemIds) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var msg = globalize.translate('ConfirmDeleteItem');
|
||||
var title = globalize.translate('HeaderDeleteItem');
|
||||
return new Promise((resolve, reject) => {
|
||||
let msg = globalize.translate('ConfirmDeleteItem');
|
||||
let title = globalize.translate('HeaderDeleteItem');
|
||||
|
||||
if (itemIds.length > 1) {
|
||||
msg = globalize.translate('ConfirmDeleteItems');
|
||||
title = globalize.translate('HeaderDeleteItems');
|
||||
}
|
||||
|
||||
require(['confirm'], function (confirm) {
|
||||
|
||||
confirm(msg, title).then(function () {
|
||||
var promises = itemIds.map(function (itemId) {
|
||||
import('confirm').then(({default: confirm}) => {
|
||||
confirm(msg, title).then(() => {
|
||||
const promises = itemIds.map(itemId => {
|
||||
apiClient.deleteItem(itemId);
|
||||
});
|
||||
|
||||
Promise.all(promises).then(resolve, function () {
|
||||
|
||||
Promise.all(promises).then(resolve, () => {
|
||||
alertText(globalize.translate('ErrorDeletingItem')).then(reject, reject);
|
||||
});
|
||||
}, reject);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showMenuForSelectedItems(e) {
|
||||
const apiClient = window.connectionManager.currentApiClient();
|
||||
|
||||
var apiClient = connectionManager.currentApiClient();
|
||||
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
|
||||
var menuItems = [];
|
||||
apiClient.getCurrentUser().then(user => {
|
||||
const menuItems = [];
|
||||
|
||||
menuItems.push({
|
||||
name: globalize.translate('AddToCollection'),
|
||||
@@ -212,7 +197,7 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
|
||||
if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) {
|
||||
menuItems.push({
|
||||
name: globalize.translate('ButtonDownload'),
|
||||
name: globalize.translate('Download'),
|
||||
id: 'download',
|
||||
icon: 'file_download'
|
||||
});
|
||||
@@ -244,18 +229,18 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
icon: 'refresh'
|
||||
});
|
||||
|
||||
require(['actionsheet'], function (actionsheet) {
|
||||
import('actionsheet').then(({default: actionsheet}) => {
|
||||
actionsheet.show({
|
||||
items: menuItems,
|
||||
positionTo: e.target,
|
||||
callback: function (id) {
|
||||
var items = selectedItems.slice(0);
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
const items = selectedItems.slice(0);
|
||||
const serverId = apiClient.serverInfo().Id;
|
||||
|
||||
switch (id) {
|
||||
case 'addtocollection':
|
||||
require(['collectionEditor'], function (collectionEditor) {
|
||||
new collectionEditor().show({
|
||||
import('collectionEditor').then(({default: collectionEditor}) => {
|
||||
new collectionEditor({
|
||||
items: items,
|
||||
serverId: serverId
|
||||
});
|
||||
@@ -264,8 +249,8 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
dispatchNeedsRefresh();
|
||||
break;
|
||||
case 'playlist':
|
||||
require(['playlistEditor'], function (playlistEditor) {
|
||||
new playlistEditor().show({
|
||||
import('playlistEditor').then(({default: playlistEditor}) => {
|
||||
new playlistEditor({
|
||||
items: items,
|
||||
serverId: serverId
|
||||
});
|
||||
@@ -282,21 +267,21 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
combineVersions(apiClient, items);
|
||||
break;
|
||||
case 'markplayed':
|
||||
items.forEach(function (itemId) {
|
||||
items.forEach(itemId => {
|
||||
apiClient.markPlayed(apiClient.getCurrentUserId(), itemId);
|
||||
});
|
||||
hideSelections();
|
||||
dispatchNeedsRefresh();
|
||||
break;
|
||||
case 'markunplayed':
|
||||
items.forEach(function (itemId) {
|
||||
items.forEach(itemId => {
|
||||
apiClient.markUnplayed(apiClient.getCurrentUserId(), itemId);
|
||||
});
|
||||
hideSelections();
|
||||
dispatchNeedsRefresh();
|
||||
break;
|
||||
case 'refresh':
|
||||
require(['refreshDialog'], function (refreshDialog) {
|
||||
import('refreshDialog').then(({default: refreshDialog}) => {
|
||||
new refreshDialog({
|
||||
itemIds: items,
|
||||
serverId: serverId
|
||||
@@ -310,35 +295,31 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function dispatchNeedsRefresh() {
|
||||
const elems = [];
|
||||
|
||||
var elems = [];
|
||||
[].forEach.call(selectedElements, i => {
|
||||
const container = dom.parentWithAttribute(i, 'is', 'emby-itemscontainer');
|
||||
|
||||
[].forEach.call(selectedElements, function (i) {
|
||||
|
||||
var container = dom.parentWithAttribute(i, 'is', 'emby-itemscontainer');
|
||||
|
||||
if (container && elems.indexOf(container) === -1) {
|
||||
if (container && !elems.includes(container)) {
|
||||
elems.push(container);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].notifyRefreshNeeded(true);
|
||||
}
|
||||
}
|
||||
|
||||
function combineVersions(apiClient, selection) {
|
||||
|
||||
if (selection.length < 2) {
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
import('alert').then(({default: alert}) => {
|
||||
alert({
|
||||
|
||||
text: globalize.translate('PleaseSelectTwoItems')
|
||||
});
|
||||
});
|
||||
@@ -352,8 +333,7 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
type: 'POST',
|
||||
url: apiClient.getUrl('Videos/MergeVersions', { Ids: selection.join(',') })
|
||||
|
||||
}).then(function () {
|
||||
|
||||
}).then(() => {
|
||||
loading.hide();
|
||||
hideSelections();
|
||||
dispatchNeedsRefresh();
|
||||
@@ -361,10 +341,9 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function showSelections(initialCard) {
|
||||
|
||||
require(['emby-checkbox'], function () {
|
||||
var cards = document.querySelectorAll('.card');
|
||||
for (var i = 0, length = cards.length; i < length; i++) {
|
||||
import('emby-checkbox').then(() => {
|
||||
const cards = document.querySelectorAll('.card');
|
||||
for (let i = 0, length = cards.length; i < length; i++) {
|
||||
showSelection(cards[i], initialCard === cards[i]);
|
||||
}
|
||||
|
||||
@@ -374,14 +353,12 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function onContainerClick(e) {
|
||||
|
||||
var target = e.target;
|
||||
const target = e.target;
|
||||
|
||||
if (selectedItems.length) {
|
||||
|
||||
var card = dom.parentWithClass(target, 'card');
|
||||
const card = dom.parentWithClass(target, 'card');
|
||||
if (card) {
|
||||
var itemSelectionPanel = card.querySelector('.itemSelectionPanel');
|
||||
const itemSelectionPanel = card.querySelector('.itemSelectionPanel');
|
||||
if (itemSelectionPanel) {
|
||||
return onItemSelectionPanelClick(e, itemSelectionPanel);
|
||||
}
|
||||
@@ -395,18 +372,15 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
|
||||
document.addEventListener('viewbeforehide', hideSelections);
|
||||
|
||||
return function (options) {
|
||||
export default function (options) {
|
||||
const self = this;
|
||||
|
||||
var self = this;
|
||||
|
||||
var container = options.container;
|
||||
const container = options.container;
|
||||
|
||||
function onTapHold(e) {
|
||||
|
||||
var card = dom.parentWithClass(e.target, 'card');
|
||||
const card = dom.parentWithClass(e.target, 'card');
|
||||
|
||||
if (card) {
|
||||
|
||||
showSelections(card);
|
||||
}
|
||||
|
||||
@@ -419,17 +393,15 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function getTouches(e) {
|
||||
|
||||
return e.changedTouches || e.targetTouches || e.touches;
|
||||
}
|
||||
|
||||
var touchTarget;
|
||||
var touchStartTimeout;
|
||||
var touchStartX;
|
||||
var touchStartY;
|
||||
let touchTarget;
|
||||
let touchStartTimeout;
|
||||
let touchStartX;
|
||||
let touchStartY;
|
||||
function onTouchStart(e) {
|
||||
|
||||
var touch = getTouches(e)[0];
|
||||
const touch = getTouches(e)[0];
|
||||
touchTarget = null;
|
||||
touchStartX = 0;
|
||||
touchStartY = 0;
|
||||
@@ -437,13 +409,12 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
if (touch) {
|
||||
touchStartX = touch.clientX;
|
||||
touchStartY = touch.clientY;
|
||||
var element = touch.target;
|
||||
const element = touch.target;
|
||||
|
||||
if (element) {
|
||||
var card = dom.parentWithClass(element, 'card');
|
||||
const card = dom.parentWithClass(element, 'card');
|
||||
|
||||
if (card) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
@@ -457,15 +428,14 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function onTouchMove(e) {
|
||||
|
||||
if (touchTarget) {
|
||||
var touch = getTouches(e)[0];
|
||||
var deltaX;
|
||||
var deltaY;
|
||||
const touch = getTouches(e)[0];
|
||||
let deltaX;
|
||||
let deltaY;
|
||||
|
||||
if (touch) {
|
||||
var touchEndX = touch.clientX || 0;
|
||||
var touchEndY = touch.clientY || 0;
|
||||
const touchEndX = touch.clientX || 0;
|
||||
const touchEndY = touch.clientY || 0;
|
||||
deltaX = Math.abs(touchEndX - (touchStartX || 0));
|
||||
deltaY = Math.abs(touchEndY - (touchStartY || 0));
|
||||
} else {
|
||||
@@ -479,12 +449,10 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function onTouchEnd(e) {
|
||||
|
||||
onMouseOut(e);
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
@@ -495,7 +463,6 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function onMouseOut(e) {
|
||||
|
||||
if (touchStartTimeout) {
|
||||
clearTimeout(touchStartTimeout);
|
||||
touchStartTimeout = null;
|
||||
@@ -504,22 +471,19 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
}
|
||||
|
||||
function onTouchStartTimerFired() {
|
||||
|
||||
if (!touchTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
var card = dom.parentWithClass(touchTarget, 'card');
|
||||
const card = dom.parentWithClass(touchTarget, 'card');
|
||||
touchTarget = null;
|
||||
|
||||
if (card) {
|
||||
|
||||
showSelections(card);
|
||||
}
|
||||
}
|
||||
|
||||
function initTapHold(element) {
|
||||
|
||||
// mobile safari doesn't allow contextmenu override
|
||||
if (browser.touch && !browser.safari) {
|
||||
element.addEventListener('contextmenu', onTapHold);
|
||||
@@ -556,12 +520,11 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
|
||||
self.onContainerClick = onContainerClick;
|
||||
|
||||
self.destroy = function () {
|
||||
|
||||
self.destroy = () => {
|
||||
container.removeEventListener('click', onContainerClick);
|
||||
container.removeEventListener('contextmenu', onTapHold);
|
||||
|
||||
var element = container;
|
||||
const element = container;
|
||||
|
||||
dom.removeEventListener(element, 'touchstart', onTouchStart, {
|
||||
passive: true
|
||||
@@ -572,10 +535,6 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
dom.removeEventListener(element, 'touchend', onTouchEnd, {
|
||||
passive: true
|
||||
});
|
||||
// this fires in safari due to magnifying class
|
||||
//dom.removeEventListener(element, "touchcancel", onTouchEnd, {
|
||||
// passive: true
|
||||
//});
|
||||
dom.removeEventListener(element, 'mousedown', onMouseDown, {
|
||||
passive: true
|
||||
});
|
||||
@@ -586,5 +545,6 @@ define(['browser', 'appStorage', 'apphost', 'loading', 'connectionManager', 'glo
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -1,192 +1,181 @@
|
||||
define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'require'], function (serverNotifications, playbackManager, events, globalize, require) {
|
||||
'use strict';
|
||||
import serverNotifications from 'serverNotifications';
|
||||
import playbackManager from 'playbackManager';
|
||||
import events from 'events';
|
||||
import globalize from 'globalize';
|
||||
|
||||
function onOneDocumentClick() {
|
||||
document.removeEventListener('click', onOneDocumentClick);
|
||||
document.removeEventListener('keydown', onOneDocumentClick);
|
||||
function onOneDocumentClick() {
|
||||
document.removeEventListener('click', onOneDocumentClick);
|
||||
document.removeEventListener('keydown', onOneDocumentClick);
|
||||
|
||||
// don't request notification permissions if they're already granted or denied
|
||||
if (window.Notification && window.Notification.permission === 'default') {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
Notification.requestPermission();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', onOneDocumentClick);
|
||||
document.addEventListener('keydown', onOneDocumentClick);
|
||||
|
||||
var serviceWorkerRegistration;
|
||||
|
||||
function closeAfter(notification, timeoutMs) {
|
||||
setTimeout(function () {
|
||||
if (notification.close) {
|
||||
notification.close();
|
||||
} else if (notification.cancel) {
|
||||
notification.cancel();
|
||||
}
|
||||
}, timeoutMs);
|
||||
}
|
||||
|
||||
function resetRegistration() {
|
||||
// don't request notification permissions if they're already granted or denied
|
||||
if (window.Notification && window.Notification.permission === 'default') {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
var serviceWorker = navigator.serviceWorker;
|
||||
if (serviceWorker) {
|
||||
serviceWorker.ready.then(function (registration) {
|
||||
serviceWorkerRegistration = registration;
|
||||
});
|
||||
Notification.requestPermission();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', onOneDocumentClick);
|
||||
document.addEventListener('keydown', onOneDocumentClick);
|
||||
|
||||
let serviceWorkerRegistration;
|
||||
|
||||
function closeAfter(notification, timeoutMs) {
|
||||
setTimeout(function () {
|
||||
if (notification.close) {
|
||||
notification.close();
|
||||
} else if (notification.cancel) {
|
||||
notification.cancel();
|
||||
}
|
||||
}, timeoutMs);
|
||||
}
|
||||
|
||||
function resetRegistration() {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
let serviceWorker = navigator.serviceWorker;
|
||||
if (serviceWorker) {
|
||||
serviceWorker.ready.then(function (registration) {
|
||||
serviceWorkerRegistration = registration;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
resetRegistration();
|
||||
|
||||
function showPersistentNotification(title, options, timeoutMs) {
|
||||
serviceWorkerRegistration.showNotification(title, options);
|
||||
}
|
||||
|
||||
function showNonPersistentNotification(title, options, timeoutMs) {
|
||||
try {
|
||||
let notif = new Notification(title, options); /* eslint-disable-line compat/compat */
|
||||
|
||||
if (notif.show) {
|
||||
notif.show();
|
||||
}
|
||||
|
||||
if (timeoutMs) {
|
||||
closeAfter(notif, timeoutMs);
|
||||
}
|
||||
} catch (err) {
|
||||
if (options.actions) {
|
||||
options.actions = [];
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showNotification(options, timeoutMs, apiClient) {
|
||||
let title = options.title;
|
||||
|
||||
options.data = options.data || {};
|
||||
options.data.serverId = apiClient.serverInfo().Id;
|
||||
options.icon = options.icon || getIconUrl();
|
||||
options.badge = options.badge || getIconUrl('badge.png');
|
||||
|
||||
resetRegistration();
|
||||
|
||||
function showPersistentNotification(title, options, timeoutMs) {
|
||||
serviceWorkerRegistration.showNotification(title, options);
|
||||
if (serviceWorkerRegistration) {
|
||||
showPersistentNotification(title, options, timeoutMs);
|
||||
return;
|
||||
}
|
||||
|
||||
function showNonPersistentNotification(title, options, timeoutMs) {
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
}
|
||||
|
||||
try {
|
||||
var notif = new Notification(title, options); /* eslint-disable-line compat/compat */
|
||||
|
||||
if (notif.show) {
|
||||
notif.show();
|
||||
}
|
||||
|
||||
if (timeoutMs) {
|
||||
closeAfter(notif, timeoutMs);
|
||||
}
|
||||
} catch (err) {
|
||||
if (options.actions) {
|
||||
options.actions = [];
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
function showNewItemNotification(item, apiClient) {
|
||||
if (playbackManager.isPlayingLocally(['Video'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
function showNotification(options, timeoutMs, apiClient) {
|
||||
let body = item.Name;
|
||||
|
||||
var title = options.title;
|
||||
|
||||
options.data = options.data || {};
|
||||
options.data.serverId = apiClient.serverInfo().Id;
|
||||
options.icon = options.icon || getIconUrl();
|
||||
options.badge = options.badge || getIconUrl('badge.png');
|
||||
|
||||
resetRegistration();
|
||||
|
||||
if (serviceWorkerRegistration) {
|
||||
showPersistentNotification(title, options, timeoutMs);
|
||||
return;
|
||||
}
|
||||
|
||||
showNonPersistentNotification(title, options, timeoutMs);
|
||||
if (item.SeriesName) {
|
||||
body = item.SeriesName + ' - ' + body;
|
||||
}
|
||||
|
||||
function showNewItemNotification(item, apiClient) {
|
||||
let notification = {
|
||||
title: 'New ' + item.Type,
|
||||
body: body,
|
||||
vibrate: true,
|
||||
tag: 'newItem' + item.Id,
|
||||
data: {}
|
||||
};
|
||||
|
||||
if (playbackManager.isPlayingLocally(['Video'])) {
|
||||
return;
|
||||
}
|
||||
let imageTags = item.ImageTags || {};
|
||||
|
||||
var body = item.Name;
|
||||
|
||||
if (item.SeriesName) {
|
||||
body = item.SeriesName + ' - ' + body;
|
||||
}
|
||||
|
||||
var notification = {
|
||||
title: 'New ' + item.Type,
|
||||
body: body,
|
||||
vibrate: true,
|
||||
tag: 'newItem' + item.Id,
|
||||
data: {
|
||||
//options: {
|
||||
// url: LibraryBrowser.getHref(item)
|
||||
//}
|
||||
}
|
||||
};
|
||||
|
||||
var imageTags = item.ImageTags || {};
|
||||
|
||||
if (imageTags.Primary) {
|
||||
|
||||
notification.icon = apiClient.getScaledImageUrl(item.Id, {
|
||||
width: 80,
|
||||
tag: imageTags.Primary,
|
||||
type: 'Primary'
|
||||
});
|
||||
}
|
||||
|
||||
showNotification(notification, 15000, apiClient);
|
||||
}
|
||||
|
||||
function onLibraryChanged(data, apiClient) {
|
||||
|
||||
var newItems = data.ItemsAdded;
|
||||
|
||||
if (!newItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't put a massive number of Id's onto the query string
|
||||
if (newItems.length > 12) {
|
||||
newItems.length = 12;
|
||||
}
|
||||
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), {
|
||||
|
||||
Recursive: true,
|
||||
Limit: 3,
|
||||
Filters: 'IsNotFolder',
|
||||
SortBy: 'DateCreated',
|
||||
SortOrder: 'Descending',
|
||||
Ids: newItems.join(','),
|
||||
MediaTypes: 'Audio,Video',
|
||||
EnableTotalRecordCount: false
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
var items = result.Items;
|
||||
|
||||
for (var i = 0, length = items.length ; i < length; i++) {
|
||||
|
||||
showNewItemNotification(items[i], apiClient);
|
||||
}
|
||||
if (imageTags.Primary) {
|
||||
notification.icon = apiClient.getScaledImageUrl(item.Id, {
|
||||
width: 80,
|
||||
tag: imageTags.Primary,
|
||||
type: 'Primary'
|
||||
});
|
||||
}
|
||||
|
||||
function getIconUrl(name) {
|
||||
name = name || 'notificationicon.png';
|
||||
return require.toUrl('.').split('?')[0] + '/' + name;
|
||||
showNotification(notification, 15000, apiClient);
|
||||
}
|
||||
|
||||
function onLibraryChanged(data, apiClient) {
|
||||
let newItems = data.ItemsAdded;
|
||||
|
||||
if (!newItems.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
function showPackageInstallNotification(apiClient, installation, status) {
|
||||
// Don't put a massive number of Id's onto the query string
|
||||
if (newItems.length > 12) {
|
||||
newItems.length = 12;
|
||||
}
|
||||
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), {
|
||||
|
||||
if (!user.Policy.IsAdministrator) {
|
||||
return;
|
||||
}
|
||||
Recursive: true,
|
||||
Limit: 3,
|
||||
Filters: 'IsNotFolder',
|
||||
SortBy: 'DateCreated',
|
||||
SortOrder: 'Descending',
|
||||
Ids: newItems.join(','),
|
||||
MediaTypes: 'Audio,Video',
|
||||
EnableTotalRecordCount: false
|
||||
|
||||
var notification = {
|
||||
tag: 'install' + installation.Id,
|
||||
data: {}
|
||||
};
|
||||
}).then(function (result) {
|
||||
let items = result.Items;
|
||||
|
||||
if (status === 'completed') {
|
||||
notification.title = globalize.translate('PackageInstallCompleted', installation.Name, installation.Version);
|
||||
notification.vibrate = true;
|
||||
} else if (status === 'cancelled') {
|
||||
notification.title = globalize.translate('PackageInstallCancelled', installation.Name, installation.Version);
|
||||
} else if (status === 'failed') {
|
||||
notification.title = globalize.translate('PackageInstallFailed', installation.Name, installation.Version);
|
||||
notification.vibrate = true;
|
||||
} else if (status === 'progress') {
|
||||
notification.title = globalize.translate('InstallingPackage', installation.Name, installation.Version);
|
||||
for (const item of items) {
|
||||
showNewItemNotification(item, apiClient);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
notification.actions =
|
||||
function getIconUrl(name) {
|
||||
name = name || 'notificationicon.png';
|
||||
return './components/notifications/' + name;
|
||||
}
|
||||
|
||||
function showPackageInstallNotification(apiClient, installation, status) {
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
if (!user.Policy.IsAdministrator) {
|
||||
return;
|
||||
}
|
||||
|
||||
let notification = {
|
||||
tag: 'install' + installation.Id,
|
||||
data: {}
|
||||
};
|
||||
|
||||
if (status === 'completed') {
|
||||
notification.title = globalize.translate('PackageInstallCompleted', installation.Name, installation.Version);
|
||||
notification.vibrate = true;
|
||||
} else if (status === 'cancelled') {
|
||||
notification.title = globalize.translate('PackageInstallCancelled', installation.Name, installation.Version);
|
||||
} else if (status === 'failed') {
|
||||
notification.title = globalize.translate('PackageInstallFailed', installation.Name, installation.Version);
|
||||
notification.vibrate = true;
|
||||
} else if (status === 'progress') {
|
||||
notification.title = globalize.translate('InstallingPackage', installation.Name, installation.Version);
|
||||
|
||||
notification.actions =
|
||||
[
|
||||
{
|
||||
action: 'cancel-install',
|
||||
@@ -195,77 +184,75 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir
|
||||
}
|
||||
];
|
||||
|
||||
notification.data.id = installation.id;
|
||||
}
|
||||
notification.data.id = installation.id;
|
||||
}
|
||||
|
||||
if (status === 'progress') {
|
||||
if (status === 'progress') {
|
||||
let percentComplete = Math.round(installation.PercentComplete || 0);
|
||||
|
||||
var percentComplete = Math.round(installation.PercentComplete || 0);
|
||||
notification.body = percentComplete + '% complete.';
|
||||
}
|
||||
|
||||
notification.body = percentComplete + '% complete.';
|
||||
}
|
||||
let timeout = status === 'cancelled' ? 5000 : 0;
|
||||
|
||||
var timeout = status === 'cancelled' ? 5000 : 0;
|
||||
|
||||
showNotification(notification, timeout, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
events.on(serverNotifications, 'LibraryChanged', function (e, apiClient, data) {
|
||||
onLibraryChanged(data, apiClient);
|
||||
showNotification(notification, timeout, apiClient);
|
||||
});
|
||||
}
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'completed');
|
||||
});
|
||||
events.on(serverNotifications, 'LibraryChanged', function (e, apiClient, data) {
|
||||
onLibraryChanged(data, apiClient);
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'failed');
|
||||
});
|
||||
events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'completed');
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'cancelled');
|
||||
});
|
||||
events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'failed');
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'progress');
|
||||
});
|
||||
events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'cancelled');
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) {
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsShuttingDown', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) {
|
||||
showPackageInstallNotification(apiClient, data, 'progress');
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) {
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsRestarting', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsShuttingDown', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
|
||||
events.on(serverNotifications, 'RestartRequired', function (e, apiClient) {
|
||||
events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('ServerNameIsRestarting', apiClient.serverInfo().Name)
|
||||
};
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
|
||||
var serverId = apiClient.serverInfo().Id;
|
||||
var notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('PleaseRestartServerName', apiClient.serverInfo().Name)
|
||||
};
|
||||
events.on(serverNotifications, 'RestartRequired', function (e, apiClient) {
|
||||
let serverId = apiClient.serverInfo().Id;
|
||||
let notification = {
|
||||
tag: 'restart' + serverId,
|
||||
title: globalize.translate('PleaseRestartServerName', apiClient.serverInfo().Name)
|
||||
};
|
||||
|
||||
notification.actions =
|
||||
notification.actions =
|
||||
[
|
||||
{
|
||||
action: 'restart',
|
||||
title: globalize.translate('ButtonRestart'),
|
||||
title: globalize.translate('Restart'),
|
||||
icon: getIconUrl()
|
||||
}
|
||||
];
|
||||
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
showNotification(notification, 0, apiClient);
|
||||
});
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@
|
||||
text-align: left;
|
||||
flex-grow: 1;
|
||||
font-size: 92%;
|
||||
margin-right: 2.4em;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.nowPlayingBarCenter {
|
||||
@@ -114,8 +114,6 @@
|
||||
|
||||
.nowPlayingBarUserDataButtons {
|
||||
display: inline-block;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.nowPlayingBarPositionSlider::-webkit-slider-thumb {
|
||||
@@ -133,33 +131,50 @@
|
||||
.toggleRepeatButton {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 62em) {
|
||||
.nowPlayingBarCenter .nowPlayingBarCurrentTime {
|
||||
.nowPlayingBar .btnShuffleQueue {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 80em) {
|
||||
.nowPlayingBarCenter .nowPlayingBarCurrentTime,
|
||||
.nowPlayingBarCenter .stopButton {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.nowPlayingBarInfoContainer {
|
||||
width: 45%;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingBarRight button:not(.playPauseButton, .nextTrackButton) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-desktop .nowPlayingBarRight .playPauseButton,
|
||||
.layout-tv .nowPlayingBarRight .playPauseButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layout-mobile .nowPlayingBarRight input,
|
||||
.layout-mobile .nowPlayingBarRight div {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media all and (max-width: 56em) {
|
||||
.nowPlayingBarCenter {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 56em) {
|
||||
.nowPlayingBarRight .playPauseButton {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 36em) {
|
||||
@media all and (max-width: 60em) {
|
||||
.nowPlayingBarRight .nowPlayingBarVolumeSliderContainer {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.nowPlayingBarInfoContainer {
|
||||
width: 70%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,42 @@
|
||||
define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', 'layoutManager', 'playbackManager', 'nowPlayingHelper', 'apphost', 'dom', 'connectionManager', 'itemContextMenu', 'paper-icon-button-light', 'emby-ratingbutton'], function (require, datetime, itemHelper, events, browser, imageLoader, layoutManager, playbackManager, nowPlayingHelper, appHost, dom, connectionManager, itemContextMenu) {
|
||||
'use strict';
|
||||
import datetime from 'datetime';
|
||||
import events from 'events';
|
||||
import browser from 'browser';
|
||||
import imageLoader from 'imageLoader';
|
||||
import layoutManager from 'layoutManager';
|
||||
import playbackManager from 'playbackManager';
|
||||
import nowPlayingHelper from 'nowPlayingHelper';
|
||||
import appHost from 'apphost';
|
||||
import dom from 'dom';
|
||||
import itemContextMenu from 'itemContextMenu';
|
||||
import 'paper-icon-button-light';
|
||||
import 'emby-ratingbutton';
|
||||
|
||||
var currentPlayer;
|
||||
var currentPlayerSupportedCommands = [];
|
||||
/* eslint-disable indent */
|
||||
|
||||
var currentTimeElement;
|
||||
var nowPlayingImageElement;
|
||||
var nowPlayingTextElement;
|
||||
var nowPlayingUserData;
|
||||
var muteButton;
|
||||
var volumeSlider;
|
||||
var volumeSliderContainer;
|
||||
var playPauseButtons;
|
||||
var positionSlider;
|
||||
var toggleRepeatButton;
|
||||
var toggleRepeatButtonIcon;
|
||||
let currentPlayer;
|
||||
let currentPlayerSupportedCommands = [];
|
||||
|
||||
var lastUpdateTime = 0;
|
||||
var lastPlayerState = {};
|
||||
var isEnabled;
|
||||
var currentRuntimeTicks = 0;
|
||||
let currentTimeElement;
|
||||
let nowPlayingImageElement;
|
||||
let nowPlayingTextElement;
|
||||
let nowPlayingUserData;
|
||||
let muteButton;
|
||||
let volumeSlider;
|
||||
let volumeSliderContainer;
|
||||
let playPauseButtons;
|
||||
let positionSlider;
|
||||
let toggleRepeatButton;
|
||||
let toggleRepeatButtonIcon;
|
||||
|
||||
var isVisibilityAllowed = true;
|
||||
let lastUpdateTime = 0;
|
||||
let lastPlayerState = {};
|
||||
let isEnabled;
|
||||
let currentRuntimeTicks = 0;
|
||||
|
||||
let isVisibilityAllowed = true;
|
||||
|
||||
function getNowPlayingBarHtml() {
|
||||
|
||||
var html = '';
|
||||
let html = '';
|
||||
|
||||
html += '<div class="nowPlayingBar hide nowPlayingBar-hidden">';
|
||||
|
||||
@@ -47,7 +58,9 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
html += '<button is="paper-icon-button-light" class="playPauseButton mediaButton"><span class="material-icons pause"></span></button>';
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="stopButton mediaButton"><span class="material-icons stop"></span></button>';
|
||||
html += '<button is="paper-icon-button-light" class="nextTrackButton mediaButton"><span class="material-icons skip_next"></span></button>';
|
||||
if (!layoutManager.mobile) {
|
||||
html += '<button is="paper-icon-button-light" class="nextTrackButton mediaButton"><span class="material-icons skip_next"></span></button>';
|
||||
}
|
||||
|
||||
html += '<div class="nowPlayingBarCurrentTime"></div>';
|
||||
html += '</div>';
|
||||
@@ -61,12 +74,17 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
html += '</div>';
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="toggleRepeatButton mediaButton"><span class="material-icons repeat"></span></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnShuffleQueue mediaButton"><span class="material-icons shuffle"></span></button>';
|
||||
|
||||
html += '<div class="nowPlayingBarUserDataButtons">';
|
||||
html += '</div>';
|
||||
|
||||
html += '<button is="paper-icon-button-light" class="playPauseButton mediaButton"><span class="material-icons pause"></span></button>';
|
||||
html += '<button is="paper-icon-button-light" class="btnToggleContextMenu"><span class="material-icons more_vert"></span></button>';
|
||||
if (layoutManager.mobile) {
|
||||
html += '<button is="paper-icon-button-light" class="nextTrackButton mediaButton"><span class="material-icons skip_next"></span></button>';
|
||||
} else {
|
||||
html += '<button is="paper-icon-button-light" class="btnToggleContextMenu mediaButton"><span class="material-icons more_vert"></span></button>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
@@ -77,12 +95,10 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function onSlideDownComplete() {
|
||||
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
function slideDown(elem) {
|
||||
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
||||
@@ -94,7 +110,6 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function slideUp(elem) {
|
||||
|
||||
dom.removeEventListener(elem, dom.whichTransitionEvent(), onSlideDownComplete, {
|
||||
once: true
|
||||
});
|
||||
@@ -112,108 +127,108 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function bindEvents(elem) {
|
||||
|
||||
currentTimeElement = elem.querySelector('.nowPlayingBarCurrentTime');
|
||||
nowPlayingImageElement = elem.querySelector('.nowPlayingImage');
|
||||
nowPlayingTextElement = elem.querySelector('.nowPlayingBarText');
|
||||
nowPlayingUserData = elem.querySelector('.nowPlayingBarUserDataButtons');
|
||||
|
||||
positionSlider = elem.querySelector('.nowPlayingBarPositionSlider');
|
||||
muteButton = elem.querySelector('.muteButton');
|
||||
muteButton.addEventListener('click', function () {
|
||||
playPauseButtons = elem.querySelectorAll('.playPauseButton');
|
||||
toggleRepeatButton = elem.querySelector('.toggleRepeatButton');
|
||||
volumeSlider = elem.querySelector('.nowPlayingBarVolumeSlider');
|
||||
volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer');
|
||||
|
||||
muteButton.addEventListener('click', function () {
|
||||
if (currentPlayer) {
|
||||
playbackManager.toggleMute(currentPlayer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
elem.querySelector('.stopButton').addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
playbackManager.stop(currentPlayer);
|
||||
}
|
||||
});
|
||||
|
||||
playPauseButtons = elem.querySelectorAll('.playPauseButton');
|
||||
playPauseButtons.forEach((button) => {
|
||||
button.addEventListener('click', onPlayPauseClick);
|
||||
});
|
||||
|
||||
elem.querySelector('.nextTrackButton').addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
playbackManager.nextTrack(currentPlayer);
|
||||
}
|
||||
});
|
||||
|
||||
elem.querySelector('.previousTrackButton').addEventListener('click', function () {
|
||||
elem.querySelector('.previousTrackButton').addEventListener('click', function (e) {
|
||||
if (currentPlayer) {
|
||||
if (lastPlayerState.NowPlayingItem.MediaType === 'Audio' && (currentPlayer._currentTime >= 5 || !playbackManager.previousTrack(currentPlayer))) {
|
||||
// Cancel this event if doubleclick is fired
|
||||
if (e.detail > 1 && playbackManager.previousTrack(currentPlayer)) {
|
||||
return;
|
||||
}
|
||||
playbackManager.seekPercent(0, currentPlayer);
|
||||
// This is done automatically by playbackManager, however, setting this here gives instant visual feedback.
|
||||
// TODO: Check why seekPercentage doesn't reflect the changes inmmediately, so we can remove this workaround.
|
||||
positionSlider.value = 0;
|
||||
} else {
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
elem.querySelector('.previousTrackButton').addEventListener('dblclick', function () {
|
||||
if (currentPlayer) {
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
}
|
||||
});
|
||||
|
||||
elem.querySelector('.btnShuffleQueue').addEventListener('click', function () {
|
||||
if (currentPlayer) {
|
||||
playbackManager.toggleQueueShuffleMode();
|
||||
}
|
||||
});
|
||||
|
||||
toggleRepeatButton = elem.querySelector('.toggleRepeatButton');
|
||||
toggleRepeatButton.addEventListener('click', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
||||
switch (playbackManager.getRepeatMode(currentPlayer)) {
|
||||
case 'RepeatAll':
|
||||
playbackManager.setRepeatMode('RepeatOne', currentPlayer);
|
||||
break;
|
||||
case 'RepeatOne':
|
||||
playbackManager.setRepeatMode('RepeatNone', currentPlayer);
|
||||
break;
|
||||
default:
|
||||
playbackManager.setRepeatMode('RepeatAll', currentPlayer);
|
||||
break;
|
||||
}
|
||||
switch (playbackManager.getRepeatMode()) {
|
||||
case 'RepeatAll':
|
||||
playbackManager.setRepeatMode('RepeatOne');
|
||||
break;
|
||||
case 'RepeatOne':
|
||||
playbackManager.setRepeatMode('RepeatNone');
|
||||
break;
|
||||
case 'RepeatNone':
|
||||
playbackManager.setRepeatMode('RepeatAll');
|
||||
}
|
||||
});
|
||||
|
||||
toggleRepeatButtonIcon = toggleRepeatButton.querySelector('.material-icons');
|
||||
|
||||
volumeSlider = elem.querySelector('.nowPlayingBarVolumeSlider');
|
||||
volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer');
|
||||
volumeSliderContainer.classList.toggle('hide', appHost.supports('physicalvolumecontrol'));
|
||||
|
||||
if (appHost.supports('physicalvolumecontrol')) {
|
||||
volumeSliderContainer.classList.add('hide');
|
||||
} else {
|
||||
volumeSliderContainer.classList.remove('hide');
|
||||
}
|
||||
|
||||
function setVolume() {
|
||||
volumeSlider.addEventListener('input', (e) => {
|
||||
if (currentPlayer) {
|
||||
currentPlayer.setVolume(this.value);
|
||||
currentPlayer.setVolume(e.target.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
volumeSlider.addEventListener('change', setVolume);
|
||||
volumeSlider.addEventListener('mousemove', setVolume);
|
||||
volumeSlider.addEventListener('touchmove', setVolume);
|
||||
|
||||
positionSlider = elem.querySelector('.nowPlayingBarPositionSlider');
|
||||
positionSlider.addEventListener('change', function () {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
||||
var newPercent = parseFloat(this.value);
|
||||
const newPercent = parseFloat(this.value);
|
||||
|
||||
playbackManager.seekPercent(newPercent, currentPlayer);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
positionSlider.getBubbleText = function (value) {
|
||||
|
||||
var state = lastPlayerState;
|
||||
const state = lastPlayerState;
|
||||
|
||||
if (!state || !state.NowPlayingItem || !currentRuntimeTicks) {
|
||||
return '--:--';
|
||||
}
|
||||
|
||||
var ticks = currentRuntimeTicks;
|
||||
let ticks = currentRuntimeTicks;
|
||||
ticks /= 100;
|
||||
ticks *= value;
|
||||
|
||||
@@ -221,7 +236,6 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
};
|
||||
|
||||
elem.addEventListener('click', function (e) {
|
||||
|
||||
if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT'])) {
|
||||
showRemoteControl();
|
||||
}
|
||||
@@ -229,24 +243,26 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function showRemoteControl() {
|
||||
|
||||
require(['appRouter'], function (appRouter) {
|
||||
import('appRouter').then(({default: appRouter}) => {
|
||||
appRouter.showNowPlaying();
|
||||
});
|
||||
}
|
||||
|
||||
var nowPlayingBarElement;
|
||||
let nowPlayingBarElement;
|
||||
function getNowPlayingBar() {
|
||||
|
||||
if (nowPlayingBarElement) {
|
||||
return Promise.resolve(nowPlayingBarElement);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(['appFooter-shared', 'itemShortcuts', 'css!./nowPlayingBar.css', 'emby-slider'], function (appfooter, itemShortcuts) {
|
||||
|
||||
var parentContainer = appfooter.element;
|
||||
Promise.all([
|
||||
import('appFooter-shared'),
|
||||
import('itemShortcuts'),
|
||||
import('css!./nowPlayingBar.css'),
|
||||
import('emby-slider')
|
||||
])
|
||||
.then(([appfooter, itemShortcuts]) => {
|
||||
const parentContainer = appfooter.element;
|
||||
nowPlayingBarElement = parentContainer.querySelector('.nowPlayingBar');
|
||||
|
||||
if (nowPlayingBarElement) {
|
||||
@@ -257,6 +273,11 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
parentContainer.insertAdjacentHTML('afterbegin', getNowPlayingBarHtml());
|
||||
nowPlayingBarElement = parentContainer.querySelector('.nowPlayingBar');
|
||||
|
||||
if (layoutManager.mobile) {
|
||||
hideButton(nowPlayingBarElement.querySelector('.btnShuffleQueue'));
|
||||
hideButton(nowPlayingBarElement.querySelector('.nowPlayingBarCenter'));
|
||||
}
|
||||
|
||||
if (browser.safari && browser.slow) {
|
||||
// Not handled well here. The wrong elements receive events, bar doesn't update quickly enough, etc.
|
||||
nowPlayingBarElement.classList.add('noMediaProgress');
|
||||
@@ -289,18 +310,17 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function updatePlayerStateInternal(event, state, player) {
|
||||
|
||||
showNowPlayingBar();
|
||||
|
||||
lastPlayerState = state;
|
||||
|
||||
var playerInfo = playbackManager.getPlayerInfo();
|
||||
const playerInfo = playbackManager.getPlayerInfo();
|
||||
|
||||
var playState = state.PlayState || {};
|
||||
const playState = state.PlayState || {};
|
||||
|
||||
updatePlayPauseState(playState.IsPaused);
|
||||
|
||||
var supportedCommands = playerInfo.supportedCommands;
|
||||
const supportedCommands = playerInfo.supportedCommands;
|
||||
currentPlayerSupportedCommands = supportedCommands;
|
||||
|
||||
if (supportedCommands.indexOf('SetRepeatMode') === -1) {
|
||||
@@ -309,7 +329,8 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
toggleRepeatButton.classList.remove('hide');
|
||||
}
|
||||
|
||||
updateRepeatModeDisplay(playState.RepeatMode);
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode());
|
||||
onQueueShuffleModeChange();
|
||||
|
||||
updatePlayerVolumeState(playState.IsMuted, playState.VolumeLevel);
|
||||
|
||||
@@ -317,11 +338,11 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
positionSlider.disabled = !playState.CanSeek;
|
||||
|
||||
// determines if both forward and backward buffer progress will be visible
|
||||
var isProgressClear = state.MediaSource && state.MediaSource.RunTimeTicks == null;
|
||||
const isProgressClear = state.MediaSource && state.MediaSource.RunTimeTicks == null;
|
||||
positionSlider.setIsClear(isProgressClear);
|
||||
}
|
||||
|
||||
var nowPlayingItem = state.NowPlayingItem || {};
|
||||
const nowPlayingItem = state.NowPlayingItem || {};
|
||||
updateTimeDisplay(playState.PositionTicks, nowPlayingItem.RunTimeTicks, playbackManager.getBufferedRanges(player));
|
||||
|
||||
updateNowPlayingInfo(state);
|
||||
@@ -329,32 +350,34 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
|
||||
function updateRepeatModeDisplay(repeatMode) {
|
||||
toggleRepeatButtonIcon.classList.remove('repeat', 'repeat_one');
|
||||
const cssClass = 'buttonActive';
|
||||
|
||||
if (repeatMode === 'RepeatAll') {
|
||||
toggleRepeatButtonIcon.classList.add('repeat');
|
||||
toggleRepeatButton.classList.add('repeatButton-active');
|
||||
} else if (repeatMode === 'RepeatOne') {
|
||||
toggleRepeatButtonIcon.classList.add('repeat_one');
|
||||
toggleRepeatButton.classList.add('repeatButton-active');
|
||||
} else {
|
||||
toggleRepeatButtonIcon.classList.add('repeat');
|
||||
toggleRepeatButton.classList.remove('repeatButton-active');
|
||||
switch (repeatMode) {
|
||||
case 'RepeatAll':
|
||||
toggleRepeatButtonIcon.classList.add('repeat');
|
||||
toggleRepeatButton.classList.add(cssClass);
|
||||
break;
|
||||
case 'RepeatOne':
|
||||
toggleRepeatButtonIcon.classList.add('repeat_one');
|
||||
toggleRepeatButton.classList.add(cssClass);
|
||||
break;
|
||||
case 'RepeatNone':
|
||||
default:
|
||||
toggleRepeatButtonIcon.classList.add('repeat');
|
||||
toggleRepeatButton.classList.remove(cssClass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function updateTimeDisplay(positionTicks, runtimeTicks, bufferedRanges) {
|
||||
|
||||
// See bindEvents for why this is necessary
|
||||
if (positionSlider && !positionSlider.dragging) {
|
||||
if (runtimeTicks) {
|
||||
|
||||
var pct = positionTicks / runtimeTicks;
|
||||
let pct = positionTicks / runtimeTicks;
|
||||
pct *= 100;
|
||||
|
||||
positionSlider.value = pct;
|
||||
|
||||
} else {
|
||||
|
||||
positionSlider.value = 0;
|
||||
}
|
||||
}
|
||||
@@ -364,9 +387,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
if (currentTimeElement) {
|
||||
|
||||
var timeText = positionTicks == null ? '--:--' : datetime.getDisplayRunningTime(positionTicks);
|
||||
|
||||
let timeText = positionTicks == null ? '--:--' : datetime.getDisplayRunningTime(positionTicks);
|
||||
if (runtimeTicks) {
|
||||
timeText += ' / ' + datetime.getDisplayRunningTime(runtimeTicks);
|
||||
}
|
||||
@@ -376,11 +397,10 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function updatePlayerVolumeState(isMuted, volumeLevel) {
|
||||
const supportedCommands = currentPlayerSupportedCommands;
|
||||
|
||||
var supportedCommands = currentPlayerSupportedCommands;
|
||||
|
||||
var showMuteButton = true;
|
||||
var showVolumeSlider = true;
|
||||
let showMuteButton = true;
|
||||
let showVolumeSlider = true;
|
||||
|
||||
if (supportedCommands.indexOf('ToggleMute') === -1) {
|
||||
showMuteButton = false;
|
||||
@@ -407,12 +427,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
|
||||
// See bindEvents for why this is necessary
|
||||
if (volumeSlider) {
|
||||
|
||||
if (showVolumeSlider) {
|
||||
volumeSliderContainer.classList.remove('hide');
|
||||
} else {
|
||||
volumeSliderContainer.classList.add('hide');
|
||||
}
|
||||
volumeSliderContainer.classList.toggle('hide', !showVolumeSlider);
|
||||
|
||||
if (!volumeSlider.dragging) {
|
||||
volumeSlider.value = volumeLevel || 0;
|
||||
@@ -420,17 +435,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
}
|
||||
|
||||
function getTextActionButton(item, text) {
|
||||
|
||||
if (!text) {
|
||||
text = itemHelper.getDisplayName(item);
|
||||
}
|
||||
|
||||
return `<a>${text}</a>`;
|
||||
}
|
||||
|
||||
function seriesImageUrl(item, options) {
|
||||
|
||||
if (!item) {
|
||||
throw new Error('item cannot be null!');
|
||||
}
|
||||
@@ -443,28 +448,23 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
options.type = options.type || 'Primary';
|
||||
|
||||
if (options.type === 'Primary') {
|
||||
|
||||
if (item.SeriesPrimaryImageTag) {
|
||||
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.type === 'Thumb') {
|
||||
|
||||
if (item.SeriesThumbImageTag) {
|
||||
|
||||
options.tag = item.SeriesThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
}
|
||||
if (item.ParentThumbImageTag) {
|
||||
|
||||
options.tag = item.ParentThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +472,6 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function imageUrl(item, options) {
|
||||
|
||||
if (!item) {
|
||||
throw new Error('item cannot be null!');
|
||||
}
|
||||
@@ -481,51 +480,55 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
options.type = options.type || 'Primary';
|
||||
|
||||
if (item.ImageTags && item.ImageTags[options.type]) {
|
||||
|
||||
options.tag = item.ImageTags[options.type];
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.PrimaryImageItemId || item.Id, options);
|
||||
}
|
||||
|
||||
if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var currentImgUrl;
|
||||
let currentImgUrl;
|
||||
function updateNowPlayingInfo(state) {
|
||||
const nowPlayingItem = state.NowPlayingItem;
|
||||
|
||||
var nowPlayingItem = state.NowPlayingItem;
|
||||
|
||||
var textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : [];
|
||||
if (textLines.length > 1) {
|
||||
textLines[1].secondary = true;
|
||||
}
|
||||
nowPlayingTextElement.innerHTML = textLines.map(function (nowPlayingName) {
|
||||
|
||||
var cssClass = nowPlayingName.secondary ? ' class="nowPlayingBarSecondaryText"' : '';
|
||||
|
||||
if (nowPlayingName.item) {
|
||||
var nowPlayingText = getTextActionButton(nowPlayingName.item, nowPlayingName.text);
|
||||
return `<div ${cssClass}>${nowPlayingText}</div>`;
|
||||
const textLines = nowPlayingItem ? nowPlayingHelper.getNowPlayingNames(nowPlayingItem) : [];
|
||||
nowPlayingTextElement.innerHTML = '';
|
||||
if (textLines) {
|
||||
const itemText = document.createElement('div');
|
||||
const secondaryText = document.createElement('div');
|
||||
secondaryText.classList.add('nowPlayingBarSecondaryText');
|
||||
if (textLines.length > 1) {
|
||||
textLines[1].secondary = true;
|
||||
if (textLines[1].text) {
|
||||
const text = document.createElement('a');
|
||||
text.innerHTML = textLines[1].text;
|
||||
secondaryText.appendChild(text);
|
||||
}
|
||||
}
|
||||
|
||||
return `<div ${cssClass}>${nowPlayingText}</div>`;
|
||||
if (textLines[0].text) {
|
||||
const text = document.createElement('a');
|
||||
text.innerHTML = textLines[0].text;
|
||||
itemText.appendChild(text);
|
||||
}
|
||||
nowPlayingTextElement.appendChild(itemText);
|
||||
nowPlayingTextElement.appendChild(secondaryText);
|
||||
}
|
||||
|
||||
}).join('');
|
||||
const imgHeight = 70;
|
||||
|
||||
var imgHeight = 70;
|
||||
|
||||
var url = nowPlayingItem ? (seriesImageUrl(nowPlayingItem, {
|
||||
const url = nowPlayingItem ? (seriesImageUrl(nowPlayingItem, {
|
||||
height: imgHeight
|
||||
}) || imageUrl(nowPlayingItem, {
|
||||
height: imgHeight
|
||||
})) : null;
|
||||
|
||||
var isRefreshing = false;
|
||||
let isRefreshing = false;
|
||||
|
||||
if (url !== currentImgUrl) {
|
||||
currentImgUrl = url;
|
||||
@@ -533,33 +536,43 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
|
||||
if (url) {
|
||||
imageLoader.lazyImage(nowPlayingImageElement, url);
|
||||
nowPlayingImageElement.style.display = null;
|
||||
nowPlayingTextElement.style.marginLeft = null;
|
||||
} else {
|
||||
nowPlayingImageElement.style.backgroundImage = '';
|
||||
nowPlayingImageElement.style.display = 'none';
|
||||
nowPlayingTextElement.style.marginLeft = '1em';
|
||||
}
|
||||
}
|
||||
|
||||
if (nowPlayingItem.Id) {
|
||||
if (isRefreshing) {
|
||||
|
||||
var apiClient = connectionManager.getApiClient(nowPlayingItem.ServerId);
|
||||
const apiClient = window.connectionManager.getApiClient(nowPlayingItem.ServerId);
|
||||
apiClient.getItem(apiClient.getCurrentUserId(), nowPlayingItem.Id).then(function (item) {
|
||||
var userData = item.UserData || {};
|
||||
var likes = userData.Likes == null ? '' : userData.Likes;
|
||||
var contextButton = document.querySelector('.btnToggleContextMenu');
|
||||
var options = {
|
||||
play: false,
|
||||
queue: false,
|
||||
positionTo: contextButton
|
||||
};
|
||||
nowPlayingUserData.innerHTML = '<button is="emby-ratingbutton" type="button" class="listItemButton mediaButton 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>';
|
||||
apiClient.getCurrentUser().then(function(user) {
|
||||
contextButton.addEventListener('click', function () {
|
||||
itemContextMenu.show(Object.assign({
|
||||
item: item,
|
||||
user: user
|
||||
}, options ));
|
||||
const userData = item.UserData || {};
|
||||
const likes = userData.Likes == null ? '' : userData.Likes;
|
||||
if (!layoutManager.mobile) {
|
||||
let contextButton = nowPlayingBarElement.querySelector('.btnToggleContextMenu');
|
||||
// We remove the previous event listener by replacing the item in each update event
|
||||
const contextButtonClone = contextButton.cloneNode(true);
|
||||
contextButton.parentNode.replaceChild(contextButtonClone, contextButton);
|
||||
contextButton = nowPlayingBarElement.querySelector('.btnToggleContextMenu');
|
||||
const options = {
|
||||
play: false,
|
||||
queue: false,
|
||||
clearQueue: true,
|
||||
positionTo: contextButton
|
||||
};
|
||||
apiClient.getCurrentUser().then(function (user) {
|
||||
contextButton.addEventListener('click', function () {
|
||||
itemContextMenu.show(Object.assign({
|
||||
item: item,
|
||||
user: user
|
||||
}, options));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
nowPlayingUserData.innerHTML = '<button is="emby-ratingbutton" type="button" class="listItemButton mediaButton 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>';
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -569,25 +582,39 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
|
||||
function onPlaybackStart(e, state) {
|
||||
console.debug('nowplaying event: ' + e.type);
|
||||
|
||||
var player = this;
|
||||
|
||||
onStateChanged.call(player, e, state);
|
||||
}
|
||||
|
||||
function onRepeatModeChange(e) {
|
||||
|
||||
function onRepeatModeChange() {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var player = this;
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode());
|
||||
}
|
||||
|
||||
updateRepeatModeDisplay(playbackManager.getRepeatMode(player));
|
||||
function onQueueShuffleModeChange() {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shuffleMode = playbackManager.getQueueShuffleMode();
|
||||
const context = nowPlayingBarElement;
|
||||
const cssClass = 'buttonActive';
|
||||
const toggleShuffleButton = context.querySelector('.btnShuffleQueue');
|
||||
switch (shuffleMode) {
|
||||
case 'Shuffle':
|
||||
toggleShuffleButton.classList.add(cssClass);
|
||||
break;
|
||||
case 'Sorted':
|
||||
default:
|
||||
toggleShuffleButton.classList.remove(cssClass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function showNowPlayingBar() {
|
||||
|
||||
if (!isVisibilityAllowed) {
|
||||
hideNowPlayingBar();
|
||||
return;
|
||||
@@ -597,24 +624,21 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function hideNowPlayingBar() {
|
||||
|
||||
isEnabled = false;
|
||||
|
||||
// Use a timeout to prevent the bar from hiding and showing quickly
|
||||
// in the event of a stop->play command
|
||||
|
||||
// Don't call getNowPlayingBar here because we don't want to end up creating it just to hide it
|
||||
var elem = document.getElementsByClassName('nowPlayingBar')[0];
|
||||
const elem = document.getElementsByClassName('nowPlayingBar')[0];
|
||||
if (elem) {
|
||||
|
||||
slideDown(elem);
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, state) {
|
||||
|
||||
console.debug('nowplaying event: ' + e.type);
|
||||
var player = this;
|
||||
const player = this;
|
||||
|
||||
if (player.isLocalPlayer) {
|
||||
if (state.NextMediaType !== 'Audio') {
|
||||
@@ -628,19 +652,17 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function onPlayPauseStateChanged(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var player = this;
|
||||
const player = this;
|
||||
updatePlayPauseState(player.paused());
|
||||
}
|
||||
|
||||
function onStateChanged(event, state) {
|
||||
|
||||
console.debug('nowplaying event: ' + event.type);
|
||||
var player = this;
|
||||
const player = this;
|
||||
|
||||
if (!state.NowPlayingItem || layoutManager.tv) {
|
||||
hideNowPlayingBar();
|
||||
@@ -665,32 +687,30 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function onTimeUpdate(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to avoid hammering the document with changes
|
||||
var now = new Date().getTime();
|
||||
const now = new Date().getTime();
|
||||
if ((now - lastUpdateTime) < 700) {
|
||||
|
||||
return;
|
||||
}
|
||||
lastUpdateTime = now;
|
||||
|
||||
var player = this;
|
||||
const player = this;
|
||||
currentRuntimeTicks = playbackManager.duration(player);
|
||||
updateTimeDisplay(playbackManager.currentTime(player), currentRuntimeTicks, playbackManager.getBufferedRanges(player));
|
||||
updateTimeDisplay(playbackManager.currentTime(player) * 10000, currentRuntimeTicks, playbackManager.getBufferedRanges(player));
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
var player = currentPlayer;
|
||||
const player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
events.off(player, 'playbackstart', onPlaybackStart);
|
||||
events.off(player, 'statechange', onPlaybackStart);
|
||||
events.off(player, 'repeatmodechange', onRepeatModeChange);
|
||||
events.off(player, 'shufflequeuemodechange', onQueueShuffleModeChange);
|
||||
events.off(player, 'playbackstop', onPlaybackStopped);
|
||||
events.off(player, 'volumechange', onVolumeChanged);
|
||||
events.off(player, 'pause', onPlayPauseStateChanged);
|
||||
@@ -703,25 +723,22 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
|
||||
function onVolumeChanged(e) {
|
||||
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var player = this;
|
||||
const player = this;
|
||||
|
||||
updatePlayerVolumeState(player.isMuted(), player.getVolume());
|
||||
}
|
||||
|
||||
function refreshFromPlayer(player) {
|
||||
|
||||
var state = playbackManager.getPlayerState(player);
|
||||
const state = playbackManager.getPlayerState(player);
|
||||
|
||||
onStateChanged.call(player, { type: 'init' }, state);
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
@@ -739,6 +756,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
events.on(player, 'playbackstart', onPlaybackStart);
|
||||
events.on(player, 'statechange', onPlaybackStart);
|
||||
events.on(player, 'repeatmodechange', onRepeatModeChange);
|
||||
events.on(player, 'shufflequeuemodechange', onQueueShuffleModeChange);
|
||||
events.on(player, 'playbackstop', onPlaybackStopped);
|
||||
events.on(player, 'volumechange', onVolumeChanged);
|
||||
events.on(player, 'pause', onPlayPauseStateChanged);
|
||||
@@ -753,16 +771,12 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
||||
document.addEventListener('viewbeforeshow', function (e) {
|
||||
|
||||
if (!e.detail.options.enableMediaControl) {
|
||||
|
||||
if (isVisibilityAllowed) {
|
||||
isVisibilityAllowed = false;
|
||||
hideNowPlayingBar();
|
||||
}
|
||||
|
||||
} else if (!isVisibilityAllowed) {
|
||||
|
||||
isVisibilityAllowed = true;
|
||||
if (currentPlayer) {
|
||||
refreshFromPlayer(currentPlayer);
|
||||
@@ -771,4 +785,5 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader',
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import appSettings from 'appSettings';
|
||||
import pluginManager from 'pluginManager';
|
||||
/* eslint-disable indent */
|
||||
|
||||
class PackageManager {
|
||||
#packagesList = [];
|
||||
#settingsKey = 'installedpackages1';
|
||||
|
||||
init() {
|
||||
console.groupCollapsed('loading packages');
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
return Promise.all(manifestUrls.map((url) => {
|
||||
return this.loadPackage(url);
|
||||
}))
|
||||
.then(() => {
|
||||
console.debug('finished loading packages');
|
||||
return Promise.resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
return Promise.resolve();
|
||||
}).finally(() => {
|
||||
console.groupEnd('loading packages');
|
||||
});
|
||||
}
|
||||
|
||||
get packages() {
|
||||
return this.#packagesList.slice(0);
|
||||
}
|
||||
|
||||
install(url) {
|
||||
return this.loadPackage(url, true).then((pkg) => {
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
if (!manifestUrls.includes(url)) {
|
||||
manifestUrls.push(url);
|
||||
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
return pkg;
|
||||
});
|
||||
}
|
||||
|
||||
uninstall(name) {
|
||||
var pkg = this.#packagesList.filter((p) => {
|
||||
return p.name === name;
|
||||
})[0];
|
||||
|
||||
if (pkg) {
|
||||
this.#packagesList = this.#packagesList.filter((p) => {
|
||||
return p.name !== name;
|
||||
});
|
||||
|
||||
this.removeUrl(pkg.url);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
mapPath(pkg, pluginUrl) {
|
||||
var urlLower = pluginUrl.toLowerCase();
|
||||
if (urlLower.startsWith('http:') || urlLower.startsWith('https:') || urlLower.startsWith('file:')) {
|
||||
return pluginUrl;
|
||||
}
|
||||
|
||||
var packageUrl = pkg.url;
|
||||
packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/'));
|
||||
|
||||
packageUrl += '/';
|
||||
packageUrl += pluginUrl;
|
||||
|
||||
return packageUrl;
|
||||
}
|
||||
|
||||
addPackage(pkg) {
|
||||
this.#packagesList = this.#packagesList.filter((p) => {
|
||||
return p.name !== pkg.name;
|
||||
});
|
||||
|
||||
this.#packagesList.push(pkg);
|
||||
}
|
||||
|
||||
removeUrl(url) {
|
||||
var manifestUrls = JSON.parse(appSettings.get(this.#settingsKey) || '[]');
|
||||
|
||||
manifestUrls = manifestUrls.filter((i) => {
|
||||
return i !== url;
|
||||
});
|
||||
|
||||
appSettings.set(this.#settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
loadPackage(url, throwError = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var xhr = new XMLHttpRequest();
|
||||
var originalUrl = url;
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 't=' + new Date().getTime();
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
var onError = () => {
|
||||
if (throwError === true) {
|
||||
reject();
|
||||
} else {
|
||||
this.removeUrl(originalUrl);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = () => {
|
||||
if (this.status < 400) {
|
||||
var pkg = JSON.parse(this.response);
|
||||
pkg.url = originalUrl;
|
||||
|
||||
this.addPackage(pkg);
|
||||
|
||||
var plugins = pkg.plugins || [];
|
||||
if (pkg.plugin) {
|
||||
plugins.push(pkg.plugin);
|
||||
}
|
||||
var promises = plugins.map((pluginUrl) => {
|
||||
return pluginManager.loadPlugin(this.mapPath(pkg, pluginUrl));
|
||||
});
|
||||
Promise.all(promises).then(resolve, resolve);
|
||||
} else {
|
||||
onError();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = onError;
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default new PackageManager();
|
||||
@@ -1,152 +0,0 @@
|
||||
define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) {
|
||||
'use strict';
|
||||
|
||||
var settingsKey = 'installedpackages1';
|
||||
|
||||
function addPackage(packageManager, pkg) {
|
||||
|
||||
packageManager.packagesList = packageManager.packagesList.filter(function (p) {
|
||||
|
||||
return p.name !== pkg.name;
|
||||
});
|
||||
|
||||
packageManager.packagesList.push(pkg);
|
||||
}
|
||||
|
||||
function removeUrl(url) {
|
||||
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
manifestUrls = manifestUrls.filter(function (i) {
|
||||
return i !== url;
|
||||
});
|
||||
|
||||
appSettings.set(settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
function loadPackage(packageManager, url, throwError) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
var originalUrl = url;
|
||||
url += url.indexOf('?') === -1 ? '?' : '&';
|
||||
url += 't=' + new Date().getTime();
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
var onError = function () {
|
||||
|
||||
if (throwError === true) {
|
||||
reject();
|
||||
} else {
|
||||
removeUrl(originalUrl);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function (e) {
|
||||
if (this.status < 400) {
|
||||
|
||||
var pkg = JSON.parse(this.response);
|
||||
pkg.url = originalUrl;
|
||||
|
||||
addPackage(packageManager, pkg);
|
||||
|
||||
var plugins = pkg.plugins || [];
|
||||
if (pkg.plugin) {
|
||||
plugins.push(pkg.plugin);
|
||||
}
|
||||
var promises = plugins.map(function (pluginUrl) {
|
||||
return pluginManager.loadPlugin(packageManager.mapPath(pkg, pluginUrl));
|
||||
});
|
||||
Promise.all(promises).then(resolve, resolve);
|
||||
|
||||
} else {
|
||||
onError();
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = onError;
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function PackageManager() {
|
||||
|
||||
this.packagesList = [];
|
||||
}
|
||||
|
||||
PackageManager.prototype.init = function () {
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
var instance = this;
|
||||
return Promise.all(manifestUrls.map(function (u) {
|
||||
|
||||
return loadPackage(instance, u);
|
||||
|
||||
})).then(function () {
|
||||
return Promise.resolve();
|
||||
}, function () {
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
PackageManager.prototype.packages = function () {
|
||||
return this.packagesList.slice(0);
|
||||
};
|
||||
|
||||
PackageManager.prototype.install = function (url) {
|
||||
|
||||
return loadPackage(this, url, true).then(function (pkg) {
|
||||
|
||||
var manifestUrls = JSON.parse(appSettings.get(settingsKey) || '[]');
|
||||
|
||||
if (manifestUrls.indexOf(url) === -1) {
|
||||
manifestUrls.push(url);
|
||||
appSettings.set(settingsKey, JSON.stringify(manifestUrls));
|
||||
}
|
||||
|
||||
return pkg;
|
||||
});
|
||||
};
|
||||
|
||||
PackageManager.prototype.uninstall = function (name) {
|
||||
|
||||
var pkg = this.packagesList.filter(function (p) {
|
||||
|
||||
return p.name === name;
|
||||
})[0];
|
||||
|
||||
if (pkg) {
|
||||
|
||||
this.packagesList = this.packagesList.filter(function (p) {
|
||||
|
||||
return p.name !== name;
|
||||
});
|
||||
|
||||
removeUrl(pkg.url);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
PackageManager.prototype.mapPath = function (pkg, pluginUrl) {
|
||||
|
||||
var urlLower = pluginUrl.toLowerCase();
|
||||
if (urlLower.indexOf('http:') === 0 || urlLower.indexOf('https:') === 0 || urlLower.indexOf('file:') === 0) {
|
||||
return pluginUrl;
|
||||
}
|
||||
|
||||
var packageUrl = pkg.url;
|
||||
packageUrl = packageUrl.substring(0, packageUrl.lastIndexOf('/'));
|
||||
|
||||
packageUrl += '/';
|
||||
packageUrl += pluginUrl;
|
||||
|
||||
return packageUrl;
|
||||
};
|
||||
|
||||
return new PackageManager();
|
||||
});
|
||||
@@ -1,171 +1,162 @@
|
||||
define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'material-icons'], function (events, playbackManager, dom, browser) {
|
||||
'use strict';
|
||||
import events from 'events';
|
||||
import playbackManager from 'playbackManager';
|
||||
import dom from 'dom';
|
||||
import browser from 'browser';
|
||||
import 'css!./iconosd';
|
||||
import 'material-icons';
|
||||
|
||||
var currentPlayer;
|
||||
var osdElement;
|
||||
var iconElement;
|
||||
var progressElement;
|
||||
var currentPlayer;
|
||||
var osdElement;
|
||||
var iconElement;
|
||||
var progressElement;
|
||||
|
||||
var enableAnimation;
|
||||
var enableAnimation;
|
||||
|
||||
function getOsdElementHtml() {
|
||||
var html = '';
|
||||
function getOsdElementHtml() {
|
||||
var html = '';
|
||||
|
||||
html += '<span class="material-icons iconOsdIcon brightness_high"></span>';
|
||||
html += '<span class="material-icons iconOsdIcon brightness_high"></span>';
|
||||
|
||||
html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner brightnessOsdProgressInner"></div></div>';
|
||||
html += '<div class="iconOsdProgressOuter"><div class="iconOsdProgressInner brightnessOsdProgressInner"></div></div>';
|
||||
|
||||
return html;
|
||||
return html;
|
||||
}
|
||||
|
||||
function ensureOsdElement() {
|
||||
var elem = osdElement;
|
||||
if (!elem) {
|
||||
enableAnimation = browser.supportsCssAnimation();
|
||||
|
||||
elem = document.createElement('div');
|
||||
elem.classList.add('hide');
|
||||
elem.classList.add('iconOsd');
|
||||
elem.classList.add('iconOsd-hidden');
|
||||
elem.classList.add('brightnessOsd');
|
||||
elem.innerHTML = getOsdElementHtml();
|
||||
|
||||
iconElement = elem.querySelector('.material-icons');
|
||||
progressElement = elem.querySelector('.iconOsdProgressInner');
|
||||
|
||||
document.body.appendChild(elem);
|
||||
osdElement = elem;
|
||||
}
|
||||
}
|
||||
|
||||
function ensureOsdElement() {
|
||||
function onHideComplete() {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
var elem = osdElement;
|
||||
if (!elem) {
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
clearHideTimeout();
|
||||
|
||||
enableAnimation = browser.supportsCssAnimation();
|
||||
var elem = osdElement;
|
||||
|
||||
elem = document.createElement('div');
|
||||
elem.classList.add('hide');
|
||||
elem.classList.add('iconOsd');
|
||||
elem.classList.add('iconOsd-hidden');
|
||||
elem.classList.add('brightnessOsd');
|
||||
elem.innerHTML = getOsdElementHtml();
|
||||
|
||||
iconElement = elem.querySelector('.material-icons');
|
||||
progressElement = elem.querySelector('.iconOsdProgressInner');
|
||||
|
||||
document.body.appendChild(elem);
|
||||
osdElement = elem;
|
||||
}
|
||||
}
|
||||
|
||||
function onHideComplete() {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
var hideTimeout;
|
||||
function showOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
|
||||
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
|
||||
once: true
|
||||
});
|
||||
|
||||
elem.classList.remove('hide');
|
||||
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
elem.classList.remove('iconOsd-hidden');
|
||||
|
||||
hideTimeout = setTimeout(hideOsd, 3000);
|
||||
});
|
||||
}
|
||||
|
||||
function clearHideTimeout() {
|
||||
if (hideTimeout) {
|
||||
clearTimeout(hideTimeout);
|
||||
hideTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
if (elem) {
|
||||
|
||||
if (enableAnimation) {
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
elem.classList.add('iconOsd-hidden');
|
||||
|
||||
dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
|
||||
once: true
|
||||
});
|
||||
});
|
||||
} else {
|
||||
onHideComplete.call(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setIcon(iconElement, icon) {
|
||||
iconElement.classList.remove('brightness_high');
|
||||
iconElement.classList.remove('brightness_medium');
|
||||
iconElement.classList.remove('brightness_low');
|
||||
iconElement.classList.add(icon);
|
||||
}
|
||||
|
||||
function updateElementsFromPlayer(brightness) {
|
||||
|
||||
if (iconElement) {
|
||||
if (brightness >= 80) {
|
||||
setIcon(iconElement, 'brightness_high');
|
||||
} else if (brightness >= 20) {
|
||||
setIcon(iconElement, 'brightness_medium');
|
||||
} else {
|
||||
setIcon(iconElement, 'brightness_low');
|
||||
}
|
||||
}
|
||||
if (progressElement) {
|
||||
progressElement.style.width = (brightness || 0) + '%';
|
||||
}
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
var player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
events.off(player, 'brightnesschange', onBrightnessChanged);
|
||||
events.off(player, 'playbackstop', hideOsd);
|
||||
currentPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function onBrightnessChanged(e) {
|
||||
|
||||
var player = this;
|
||||
|
||||
ensureOsdElement();
|
||||
|
||||
updateElementsFromPlayer(playbackManager.getBrightness(player));
|
||||
|
||||
showOsd();
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
releaseCurrentPlayer();
|
||||
|
||||
currentPlayer = player;
|
||||
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
hideOsd();
|
||||
events.on(player, 'brightnesschange', onBrightnessChanged);
|
||||
events.on(player, 'playbackstop', hideOsd);
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playerchange', function () {
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
dom.removeEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
|
||||
once: true
|
||||
});
|
||||
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
elem.classList.remove('hide');
|
||||
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
elem.classList.remove('iconOsd-hidden');
|
||||
|
||||
hideTimeout = setTimeout(hideOsd, 3000);
|
||||
});
|
||||
}
|
||||
|
||||
function clearHideTimeout() {
|
||||
if (hideTimeout) {
|
||||
clearTimeout(hideTimeout);
|
||||
hideTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
function hideOsd() {
|
||||
clearHideTimeout();
|
||||
|
||||
var elem = osdElement;
|
||||
if (elem) {
|
||||
if (enableAnimation) {
|
||||
// trigger reflow
|
||||
void elem.offsetWidth;
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
elem.classList.add('iconOsd-hidden');
|
||||
|
||||
dom.addEventListener(elem, dom.whichTransitionEvent(), onHideComplete, {
|
||||
once: true
|
||||
});
|
||||
});
|
||||
} else {
|
||||
onHideComplete.call(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setIcon(iconElement, icon) {
|
||||
iconElement.classList.remove('brightness_high', 'brightness_medium', 'brightness_low');
|
||||
iconElement.classList.add(icon);
|
||||
}
|
||||
|
||||
function updateElementsFromPlayer(brightness) {
|
||||
if (iconElement) {
|
||||
if (brightness >= 80) {
|
||||
setIcon(iconElement, 'brightness_high');
|
||||
} else if (brightness >= 20) {
|
||||
setIcon(iconElement, 'brightness_medium');
|
||||
} else {
|
||||
setIcon(iconElement, 'brightness_low');
|
||||
}
|
||||
}
|
||||
if (progressElement) {
|
||||
progressElement.style.width = (brightness || 0) + '%';
|
||||
}
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
var player = currentPlayer;
|
||||
|
||||
if (player) {
|
||||
events.off(player, 'brightnesschange', onBrightnessChanged);
|
||||
events.off(player, 'playbackstop', hideOsd);
|
||||
currentPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function onBrightnessChanged(e) {
|
||||
var player = this;
|
||||
|
||||
ensureOsdElement();
|
||||
|
||||
updateElementsFromPlayer(playbackManager.getBrightness(player));
|
||||
|
||||
showOsd();
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
if (player === currentPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
releaseCurrentPlayer();
|
||||
|
||||
currentPlayer = player;
|
||||
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
hideOsd();
|
||||
events.on(player, 'brightnesschange', onBrightnessChanged);
|
||||
events.on(player, 'playbackstop', hideOsd);
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playerchange', function () {
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
});
|
||||
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (connectionManager, globalize, userSettings, appHost) {
|
||||
'use strict';
|
||||
|
||||
function getRequirePromise(deps) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
require(deps, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
|
||||
function getWeek(date) {
|
||||
var d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
var dayNum = d.getUTCDay() || 7;
|
||||
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||
var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
|
||||
}
|
||||
|
||||
function showMessage(text, userSettingsKey, appHostFeature) {
|
||||
|
||||
if (appHost.supports(appHostFeature)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var now = new Date();
|
||||
|
||||
userSettingsKey += now.getFullYear() + '-w' + getWeek(now);
|
||||
|
||||
if (userSettings.get(userSettingsKey, false) === '1') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
userSettings.set(userSettingsKey, '1', false);
|
||||
|
||||
require(['alert'], function (alert) {
|
||||
|
||||
return alert(text).then(resolve, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showBlurayMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'blurayexpirementalinfo', 'nativeblurayplayback');
|
||||
}
|
||||
|
||||
function showDvdMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'dvdexpirementalinfo', 'nativedvdplayback');
|
||||
}
|
||||
|
||||
function showIsoMessage() {
|
||||
return showMessage(globalize.translate('UnsupportedPlayback'), 'isoexpirementalinfo', 'nativeisoplayback');
|
||||
}
|
||||
|
||||
function ExpirementalPlaybackWarnings() {
|
||||
|
||||
this.name = 'Experimental playback warnings';
|
||||
this.type = 'preplayintercept';
|
||||
this.id = 'expirementalplaybackwarnings';
|
||||
}
|
||||
|
||||
ExpirementalPlaybackWarnings.prototype.intercept = function (options) {
|
||||
|
||||
var item = options.item;
|
||||
if (!item) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (item.VideoType === 'Iso') {
|
||||
return showIsoMessage();
|
||||
}
|
||||
|
||||
if (item.VideoType === 'BluRay') {
|
||||
return showBlurayMessage();
|
||||
}
|
||||
|
||||
if (item.VideoType === 'Dvd') {
|
||||
return showDvdMessage();
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
return ExpirementalPlaybackWarnings;
|
||||
});
|
||||
@@ -1,7 +1,6 @@
|
||||
import playbackManager from 'playbackManager';
|
||||
import nowPlayingHelper from 'nowPlayingHelper';
|
||||
import events from 'events';
|
||||
import connectionManager from 'connectionManager';
|
||||
/* eslint-disable indent */
|
||||
|
||||
// Reports media playback to the device for lock screen control
|
||||
@@ -16,16 +15,16 @@ import connectionManager from 'connectionManager';
|
||||
} else if (options.type === 'Primary' && item.SeriesPrimaryImageTag) {
|
||||
options.tag = item.SeriesPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
} else if (options.type === 'Thumb') {
|
||||
if (item.SeriesThumbImageTag) {
|
||||
options.tag = item.SeriesThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options);
|
||||
} else if (item.ParentThumbImageTag) {
|
||||
options.tag = item.ParentThumbImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +37,11 @@ import connectionManager from 'connectionManager';
|
||||
if (item.ImageTags && item.ImageTags[options.type]) {
|
||||
options.tag = item.ImageTags[options.type];
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.Id, options);
|
||||
} else if (item.AlbumId && item.AlbumPrimaryImageTag) {
|
||||
options.tag = item.AlbumPrimaryImageTag;
|
||||
|
||||
return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
return window.connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -127,7 +126,7 @@ import connectionManager from 'connectionManager';
|
||||
artwork: getImageUrls(item)
|
||||
});
|
||||
} else {
|
||||
let itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 });
|
||||
const itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 });
|
||||
|
||||
window.NativeShell.updateMediaSession({
|
||||
action: eventName,
|
||||
@@ -241,6 +240,15 @@ import connectionManager from 'connectionManager';
|
||||
navigator.mediaSession.setActionHandler('seekforward', function () {
|
||||
execute('fastForward');
|
||||
});
|
||||
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
navigator.mediaSession.setActionHandler('seekto', function (object) {
|
||||
const item = playbackManager.getPlayerState(currentPlayer).NowPlayingItem;
|
||||
// Convert to ms
|
||||
const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0);
|
||||
const wantedTime = object.seekTime * 1000;
|
||||
playbackManager.seekPercent(wantedTime / duration * 100, currentPlayer);
|
||||
});
|
||||
}
|
||||
|
||||
events.on(playbackManager, 'playerchange', function () {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user