<template> <DialogBase ref="dialogWindow" :title="selectedBox.title" @canceled="closed" :showFooter="false" :closeOnEscape="selectedVideo._id == null" :disableXscroll="true" :disableYscroll="true" :flatDialogHeader="true"> <div id="boxViewer" class="flex-row"> <div id="header" class="flex-column grow"> <div id="background" :style="coverBackground" /> <div id="title" class="grow z1 pa flex-column"> <img class="glow ma" :src="cover" /> <span id="stats" class="center"> <b>{{ selectedBox.title }}</b> <br /> <b>{{ box_videos.length }}</b> Videos </span> <div class="grow"> </div> <div class="flex-row ma-top grow"> <button class="flat ma-right" title="Favourite" @click="toggleFavourite"> <awesome-icon :icon="['fas', 'star']" size="2x" class="white-text favourite active" v-if="isFavourite" /> <awesome-icon :icon="['far', 'star']" size="2x" class="white-text favourite" v-else /> </button> <button class="flat ma-right" title="Keep playing" @click="playProgress" v-if="selectedBox.progress"> <awesome-icon icon="play" size="2x" class="primary-text" /> </button> <button class="flat ma-right" title="Play" @dblclick="dblclick" v-else> <awesome-icon icon="play" size="2x" class="white-text" /> </button> <button @click="gotoPrevBox" class="flat ma-left ma-right" :title="prevBox.name" :disabled="!prevBox._id"> <awesome-icon icon="angle-left" class="ma4 white-text" /> </button> <button @click="gotoNextBox" class="flat" :title="nextBox.name" :disabled="!nextBox._id"> <awesome-icon icon="angle-right" class="ma4 white-text" /> </button> <div class="grow"></div> <DropDown v-if="$store.getters['user/isAdministrator']"> <button class="flat center" :title="visibility_text"> <awesome-icon :icon="visibility_icon" class="white-text" /> </button> <template v-slot:dropdown-content> <div> <button v-for="(item, i) in $store.state.system.lists.visibility" :key="i" @click="setVisibility(item)"> <awesome-icon :icon="getVisibilityIcon(item)" />{{ getVisibilityText(item) }} </button> <hr /> <button v-if="!selectedBox.share._id" @click="shareEnable"> <awesome-icon icon="share" />Share this box </button> <button v-if="selectedBox.share._id" @click="addShareUrlToClipboard"> <awesome-icon icon="clipboard" />Copy url into clipboard </button> <button v-if="selectedBox.share._id" @click="shareDisable"> <awesome-icon icon="share" />Remove share </button> </div> </template> </DropDown> <DropDown v-if="$store.getters['user/isAdministrator']"> <button class="flat center"> <awesome-icon icon="ellipsis-v" class="white-text" /> </button> <template v-slot:dropdown-content> <div> <button @click="uploadNewCover"> <awesome-icon icon="image" />Set new Cover... </button> <button @click="resetCover"> <awesome-icon icon="eraser" />Reset Cover </button> <hr /> <button @click="mergeBox"> <awesome-icon icon="compress-alt" />Merge Boxes... </button> </div> </template> </DropDown> </div> </div> </div> <ul id="videoList" class="videos"> <li v-for="item in selectedBox.videos" :key="item._id"> <VideoItem :video="item" /> </li> </ul> </div> <BoxMerge ref="mergeDialog" /> </DialogBase> </template> <script> import BoxMerge from "./BoxMerge"; import VideoItem from "../Video"; import { mapGetters } from "vuex"; export default { methods: { addShareUrlToClipboard() { let url = window.location.origin + "/#/share?id=" + this.selectedBox.share._id; navigator.clipboard.writeText(url); }, dblclick() { this.$store.commit("tracks/resetSelectedTrack"); this.$store.commit("radios/resetSelectedRadio"); this.$store.dispatch("videos/playContainer", this.selectedBox); }, gotoVideo() { if (this.$route.query.play) { let video = this.selectedBox.videos.find( (f) => f._id == this.$route.query.play ); if (video) { this.$store.dispatch("videos/play", video); } } }, playProgress() { let video = this.selectedBox.videos.find( (f) => f._id == this.selectedBox.progress.id ); if (video) { this.$store.dispatch("videos/play", video); } }, gotoNextBox() { this.$store.dispatch("boxes/gotoNextBox"); }, gotoPrevBox() { this.$store.dispatch("boxes/gotoPrevBox"); }, closed() { if ( window.history.state.back.indexOf("?") == -1 || window.history.state.back.startsWith("/search") ) { this.$router.back(); } else { this.$store.dispatch("boxes/resetSelectedBox"); } }, keydownListener(e) { if (e.key == "ArrowLeft") { e.preventDefault(); this.gotoPrevBox(); } if (e.key == "ArrowRight") { e.preventDefault(); this.gotoNextBox(); } }, mergeBox() { this.$refs.mergeDialog.open(this.selectedBox); }, toggleFavourite() { this.$store.dispatch("user/toggleFavourite", { itemId: this.selectedBox._id, type: "box", }); }, setVisibility(visibility) { this.selectedBox.visibility = visibility; this.$store.dispatch("boxes/updateBox", this.selectedBox); }, uploadNewCover() { this.$store.dispatch("boxes/uploadNewCover", this.selectedBox); }, getVisibilityIcon(visibility) { return visibility == "global" ? "globe" : visibility == "instance" ? "server" : visibility == "hidden" ? "eye-slash" : "user"; }, getVisibilityText(visibility) { return visibility == "global" ? "Global" : visibility == "instance" ? "On this server" : visibility == "hidden" ? "Hide this Box" : "Only for me"; }, resetCover() { this.$store.dispatch("boxes/resetCover", this.selectedBox); }, shareEnable() { this.$store.dispatch("boxes/shareEnable", this.selectedBox).then(() => { this.addShareUrlToClipboard(); }); }, shareDisable() { this.$store.dispatch("boxes/shareDisable", this.selectedBox); }, loadUserProgress() { if (this.selectedVideo.parent._id != this.selectedBox._id) { this.$store .dispatch("user/getProgress", this.selectedBox) .then(() => { this.gotoVideo(); }); } } }, computed: { ...mapGetters({ prevBox: ["boxes/prevBox"], nextBox: ["boxes/nextBox"], selectedBox: ["boxes/selectedBox"], selectedVideo: ["videos/selectedVideo"], favourites: ["user/favourites"], }), box_videos() { return this.selectedBox.videos || []; }, box_year() { return this.selectedBox.year; }, coverBackground() { return "background-image: url('" + this.cover + "')"; }, cover() { let cover = "/static/icons/dummy/box.svg"; if (this.selectedBox.covers && this.selectedBox.covers.cover256) { cover = this.selectedBox.covers.cover256; } return cover; }, isFavourite() { return ( this.favourites.find((f) => f.itemId == this.selectedBox._id) != undefined ); }, visibility_icon() { return this.selectedBox.visibility == "global" ? "globe" : this.selectedBox.visibility == "instance" ? "server" : this.selectedBox.visibility == "hidden" ? "eye-slash" : "user"; }, visibility_text() { return this.selectedBox.visibility == "global" ? "Visible for the whole world" : this.selectedBox.visibility == "instance" ? "Visible on this instance" : this.selectedBox.visibility == "hidden" ? "Hidden for all users" : "Visible only for me"; }, }, watch: { selectedBox(newVal) { if (newVal._id) { if (!this.$refs.dialogWindow.visible) { this.$refs.dialogWindow.open(); window.addEventListener("keydown", this.keydownListener); } this.loadUserProgress(); } else { if (this.$refs.dialogWindow.visible) { this.$refs.dialogWindow.close(); } window.removeEventListener("keydown", this.keydownListener); } }, }, components: { BoxMerge, VideoItem, }, }; </script> <style scoped> #boxViewer { height: 486px; } #header { position: relative; background-color: black; } #header img { align-self: center; width: 256px; } #stats { z-index: 2; color: var(--white); text-shadow: 0 1px 2px black; } .dropdown-activator button { width: 32px; height: 32px; } #videoList { background-color: var(--white); z-index: 1; overflow: overlay; } .video { width: 220px; } @media (max-width: 480px) { #boxViewer { flex-direction: column; } #stats p { max-width: initial; } } @media (max-width: 480px), (max-height: 480px) { #boxViewer { width: 100%; height: 100%; } #header img { width: 192px; } #videoList { height: initial; flex-grow: 1; } .video { width: initial; } } @media (max-height: 480px) {} </style>