fix: blinking previewer
This commit is contained in:
parent
716396a726
commit
9a2ebbabe2
|
@ -10,10 +10,12 @@
|
||||||
@mouseup="mouseUp"
|
@mouseup="mouseUp"
|
||||||
@wheel="wheelMove"
|
@wheel="wheelMove"
|
||||||
>
|
>
|
||||||
<img :src="src" class="image-ex-img" ref="imgex" @load="setCenter">
|
<img :src="src" class="image-ex-img image-ex-img-center" ref="imgex" @load="onLoad">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import throttle from 'lodash.throttle'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
src: String,
|
src: String,
|
||||||
|
@ -50,7 +52,12 @@ export default {
|
||||||
inDrag: false,
|
inDrag: false,
|
||||||
lastTouchDistance: 0,
|
lastTouchDistance: 0,
|
||||||
moveDisabled: false,
|
moveDisabled: false,
|
||||||
disabledTimer: null
|
disabledTimer: null,
|
||||||
|
imageLoaded: false,
|
||||||
|
position: {
|
||||||
|
center: { x: 0, y: 0 },
|
||||||
|
relative: { x: 0, y: 0 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -63,24 +70,47 @@ export default {
|
||||||
if (getComputedStyle(container).height === "0px") {
|
if (getComputedStyle(container).height === "0px") {
|
||||||
container.style.height = "100%"
|
container.style.height = "100%"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', this.onResize)
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
window.removeEventListener('resize', this.onResize)
|
||||||
|
document.removeEventListener('mouseup', this.onMouseUp)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
onLoad() {
|
||||||
|
let img = this.$refs.imgex
|
||||||
|
|
||||||
|
this.imageLoaded = true
|
||||||
|
|
||||||
|
if (img === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
img.classList.remove('image-ex-img-center')
|
||||||
|
this.setCenter()
|
||||||
|
img.classList.add('image-ex-img-ready')
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', this.onMouseUp)
|
||||||
|
},
|
||||||
|
onMouseUp() {
|
||||||
|
this.inDrag = false
|
||||||
|
},
|
||||||
|
onResize: throttle(function() {
|
||||||
|
if (this.imageLoaded) {
|
||||||
|
this.setCenter()
|
||||||
|
this.doMove(this.position.relative.x, this.position.relative.y)
|
||||||
|
}
|
||||||
|
}, 100),
|
||||||
setCenter() {
|
setCenter() {
|
||||||
let container = this.$refs.container
|
let container = this.$refs.container
|
||||||
let img = this.$refs.imgex
|
let img = this.$refs.imgex
|
||||||
|
|
||||||
let rate = Math.min(
|
this.position.center.x = Math.floor((container.clientWidth - img.clientWidth) / 2)
|
||||||
container.clientWidth / img.clientWidth,
|
this.position.center.y = Math.floor((container.clientHeight - img.clientHeight) / 2)
|
||||||
container.clientHeight / img.clientHeight
|
|
||||||
)
|
img.style.left = this.position.center.x + 'px'
|
||||||
if (!this.autofill && rate > 1) {
|
img.style.top = this.position.center.y + 'px'
|
||||||
rate = 1
|
|
||||||
}
|
|
||||||
// height will be auto set
|
|
||||||
img.width = Math.floor(img.clientWidth * rate)
|
|
||||||
img.style.top = `${Math.floor((container.clientHeight - img.clientHeight) / 2)}px`
|
|
||||||
img.style.left = `${Math.floor((container.clientWidth - img.clientWidth) / 2)}px`
|
|
||||||
document.addEventListener('mouseup', () => this.inDrag = false )
|
|
||||||
},
|
},
|
||||||
mousedownStart(event) {
|
mousedownStart(event) {
|
||||||
this.lastX = null
|
this.lastX = null
|
||||||
|
@ -159,8 +189,22 @@ export default {
|
||||||
},
|
},
|
||||||
doMove(x, y) {
|
doMove(x, y) {
|
||||||
let style = this.$refs.imgex.style
|
let style = this.$refs.imgex.style
|
||||||
style.left = `${this.pxStringToNumber(style.left) + x}px`
|
let posX = this.pxStringToNumber(style.left) + x
|
||||||
style.top = `${this.pxStringToNumber(style.top) + y}px`
|
let posY = this.pxStringToNumber(style.top) + y
|
||||||
|
|
||||||
|
style.left = posX + 'px'
|
||||||
|
style.top = posY + 'px'
|
||||||
|
|
||||||
|
this.position.relative.x = Math.abs(this.position.center.x - posX)
|
||||||
|
this.position.relative.y = Math.abs(this.position.center.y - posY)
|
||||||
|
|
||||||
|
if (posX < this.position.center.x) {
|
||||||
|
this.position.relative.x = this.position.relative.x * -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posY < this.position.center.y) {
|
||||||
|
this.position.relative.y = this.position.relative.y * -1
|
||||||
|
}
|
||||||
},
|
},
|
||||||
wheelMove(event) {
|
wheelMove(event) {
|
||||||
this.scale += (event.wheelDeltaY / 100) * this.zoomStep
|
this.scale += (event.wheelDeltaY / 100) * this.zoomStep
|
||||||
|
@ -185,9 +229,20 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-ex-img {
|
.image-ex-img {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-ex-img-center {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
position: absolute;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-ex-img-ready {
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
position: absolute;
|
|
||||||
transition: transform 0.1s ease;
|
transition: transform 0.1s ease;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,16 +5,14 @@
|
||||||
<i class="material-icons">close</i>
|
<i class="material-icons">close</i>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<template v-if="!loading">
|
<div class="title">
|
||||||
<div class="title">
|
<span>{{ this.name }}</span>
|
||||||
<span>{{ req.name }}</span>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<rename-button v-if="user.perm.rename"></rename-button>
|
<rename-button :disabled="loading" v-if="user.perm.rename"></rename-button>
|
||||||
<delete-button v-if="user.perm.delete"></delete-button>
|
<delete-button :disabled="loading" v-if="user.perm.delete"></delete-button>
|
||||||
<download-button v-if="user.perm.download"></download-button>
|
<download-button :disabled="loading" v-if="user.perm.download"></download-button>
|
||||||
<info-button></info-button>
|
<info-button :disabled="loading"></info-button>
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="loading" v-if="loading">
|
<div class="loading" v-if="loading">
|
||||||
|
@ -25,33 +23,34 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="!loading">
|
<button class="action" @click="prev" v-show="hasPrevious" :aria-label="$t('buttons.previous')" :title="$t('buttons.previous')">
|
||||||
<button class="action" @click="prev" v-show="hasPrevious" :aria-label="$t('buttons.previous')" :title="$t('buttons.previous')">
|
<i class="material-icons">chevron_left</i>
|
||||||
<i class="material-icons">chevron_left</i>
|
</button>
|
||||||
</button>
|
<button class="action" @click="next" v-show="hasNext" :aria-label="$t('buttons.next')" :title="$t('buttons.next')">
|
||||||
<button class="action" @click="next" v-show="hasNext" :aria-label="$t('buttons.next')" :title="$t('buttons.next')">
|
<i class="material-icons">chevron_right</i>
|
||||||
<i class="material-icons">chevron_right</i>
|
</button>
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="preview">
|
<template v-if="!loading">
|
||||||
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
<div class="preview">
|
||||||
<audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls></audio>
|
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
||||||
<video v-else-if="req.type == 'video'" :src="raw" autoplay controls>
|
<audio v-else-if="req.type == 'audio'" :src="raw" autoplay controls></audio>
|
||||||
<track
|
<video v-else-if="req.type == 'video'" :src="raw" autoplay controls>
|
||||||
kind="captions"
|
<track
|
||||||
v-for="(sub, index) in subtitles"
|
kind="captions"
|
||||||
:key="index"
|
v-for="(sub, index) in subtitles"
|
||||||
:src="sub"
|
:key="index"
|
||||||
:label="'Subtitle ' + index" :default="index === 0">
|
:src="sub"
|
||||||
Sorry, your browser doesn't support embedded videos,
|
:label="'Subtitle ' + index" :default="index === 0">
|
||||||
but don't worry, you can <a :href="download">download it</a>
|
Sorry, your browser doesn't support embedded videos,
|
||||||
and watch it with your favorite video player!
|
but don't worry, you can <a :href="download">download it</a>
|
||||||
</video>
|
and watch it with your favorite video player!
|
||||||
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw"></object>
|
</video>
|
||||||
<a v-else-if="req.type == 'blob'" :href="download">
|
<object v-else-if="req.extension == '.pdf'" class="pdf" :data="raw"></object>
|
||||||
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
|
<a v-else-if="req.type == 'blob'" :href="download">
|
||||||
</a>
|
<h2 class="message">{{ $t('buttons.download') }} <i class="material-icons">file_download</i></h2>
|
||||||
</div>
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -87,6 +86,7 @@ export default {
|
||||||
previousLink: '',
|
previousLink: '',
|
||||||
nextLink: '',
|
nextLink: '',
|
||||||
listing: null,
|
listing: null,
|
||||||
|
name: '',
|
||||||
subtitles: []
|
subtitles: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -111,30 +111,24 @@ export default {
|
||||||
return `${this.previewUrl}&inline=true`
|
return `${this.previewUrl}&inline=true`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
$route: function () {
|
||||||
|
this.updatePreview()
|
||||||
|
}
|
||||||
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
window.addEventListener('keyup', this.key)
|
window.addEventListener('keyup', this.key)
|
||||||
|
this.$store.commit('setPreviewMode', true)
|
||||||
if (this.req.subtitles) {
|
this.listing = this.oldReq.items
|
||||||
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
this.updatePreview()
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (this.oldReq.items) {
|
|
||||||
this.updateLinks(this.oldReq.items)
|
|
||||||
} else {
|
|
||||||
const path = url.removeLastDir(this.$route.path)
|
|
||||||
const res = await api.fetch(path)
|
|
||||||
this.updateLinks(res.items)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
window.removeEventListener('keyup', this.key)
|
window.removeEventListener('keyup', this.key)
|
||||||
|
this.$store.commit('setPreviewMode', false)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
back () {
|
back () {
|
||||||
|
this.$store.commit('setPreviewMode', false)
|
||||||
let uri = url.removeLastDir(this.$route.path) + '/'
|
let uri = url.removeLastDir(this.$route.path) + '/'
|
||||||
this.$router.push({ path: uri })
|
this.$router.push({ path: uri })
|
||||||
},
|
},
|
||||||
|
@ -153,22 +147,42 @@ export default {
|
||||||
if (this.hasPrevious) this.prev()
|
if (this.hasPrevious) this.prev()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateLinks (items) {
|
async updatePreview () {
|
||||||
for (let i = 0; i < items.length; i++) {
|
if (this.req.subtitles) {
|
||||||
if (items[i].name !== this.req.name) {
|
this.subtitles = this.req.subtitles.map(sub => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`)
|
||||||
|
}
|
||||||
|
|
||||||
|
let dirs = this.$route.fullPath.split("/")
|
||||||
|
this.name = decodeURIComponent(dirs[dirs.length - 1])
|
||||||
|
|
||||||
|
if (!this.listing) {
|
||||||
|
try {
|
||||||
|
const path = url.removeLastDir(this.$route.path)
|
||||||
|
const res = await api.fetch(path)
|
||||||
|
this.listing = res.items
|
||||||
|
} catch (e) {
|
||||||
|
this.$showError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.previousLink = ''
|
||||||
|
this.nextLink = ''
|
||||||
|
|
||||||
|
for (let i = 0; i < this.listing.length; i++) {
|
||||||
|
if (this.listing[i].name !== this.name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = i - 1; j >= 0; j--) {
|
for (let j = i - 1; j >= 0; j--) {
|
||||||
if (mediaTypes.includes(items[j].type)) {
|
if (mediaTypes.includes(this.listing[j].type)) {
|
||||||
this.previousLink = items[j].url
|
this.previousLink = this.listing[j].url
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = i + 1; j < items.length; j++) {
|
for (let j = i + 1; j < this.listing.length; j++) {
|
||||||
if (mediaTypes.includes(items[j].type)) {
|
if (mediaTypes.includes(this.listing[j].type)) {
|
||||||
this.nextLink = items[j].url
|
this.nextLink = this.listing[j].url
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@ const state = {
|
||||||
show: null,
|
show: null,
|
||||||
showShell: false,
|
showShell: false,
|
||||||
showMessage: null,
|
showMessage: null,
|
||||||
showConfirm: null
|
showConfirm: null,
|
||||||
|
previewMode: false
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
|
|
|
@ -82,6 +82,9 @@ const mutations = {
|
||||||
resetClipboard: (state) => {
|
resetClipboard: (state) => {
|
||||||
state.clipboard.key = ''
|
state.clipboard.key = ''
|
||||||
state.clipboard.items = []
|
state.clipboard.items = []
|
||||||
|
},
|
||||||
|
setPreviewMode(state, value) {
|
||||||
|
state.previewMode = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,15 @@
|
||||||
<router-link :to="link.url">{{ link.name }}</router-link>
|
<router-link :to="link.url">{{ link.name }}</router-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="error">
|
<div v-if="error">
|
||||||
<not-found v-if="error.message === '404'"></not-found>
|
<not-found v-if="error.message === '404'"></not-found>
|
||||||
<forbidden v-else-if="error.message === '403'"></forbidden>
|
<forbidden v-else-if="error.message === '403'"></forbidden>
|
||||||
<internal-error v-else></internal-error>
|
<internal-error v-else></internal-error>
|
||||||
</div>
|
</div>
|
||||||
|
<preview v-else-if="isPreview"></preview>
|
||||||
<editor v-else-if="isEditor"></editor>
|
<editor v-else-if="isEditor"></editor>
|
||||||
<listing :class="{ multiple }" v-else-if="isListing"></listing>
|
<listing :class="{ multiple }" v-else-if="isListing"></listing>
|
||||||
<preview v-else-if="isPreview"></preview>
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h2 class="message">
|
<h2 class="message">
|
||||||
<span>{{ $t('files.loading') }}</span>
|
<span>{{ $t('files.loading') }}</span>
|
||||||
|
@ -65,7 +66,7 @@ export default {
|
||||||
'show'
|
'show'
|
||||||
]),
|
]),
|
||||||
isPreview () {
|
isPreview () {
|
||||||
return !this.loading && !this.isListing && !this.isEditor
|
return !this.loading && !this.isListing && !this.isEditor || this.loading && this.$store.state.previewMode
|
||||||
},
|
},
|
||||||
breadcrumbs () {
|
breadcrumbs () {
|
||||||
let parts = this.$route.path.split('/')
|
let parts = this.$route.path.split('/')
|
||||||
|
|
Loading…
Reference in New Issue