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