fix: blinking previewer
							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