Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85630457
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/components/media_modal/media_modal.js b/src/components/media_modal/media_modal.js
index 6a36850848..4ed0b66fb8 100644
--- a/src/components/media_modal/media_modal.js
+++ b/src/components/media_modal/media_modal.js
@@ -1,143 +1,142 @@
import StillImage from '../still-image/still-image.vue'
import VideoAttachment from '../video_attachment/video_attachment.vue'
import Modal from '../modal/modal.vue'
import PinchZoom from '../pinch_zoom/pinch_zoom.vue'
import SwipeClick from '../swipe_click/swipe_click.vue'
import GestureService from '../../services/gesture_service/gesture_service'
import Flash from 'src/components/flash/flash.vue'
import Vuex from 'vuex'
import fileTypeService from '../../services/file_type/file_type.service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faChevronLeft,
faChevronRight,
faCircleNotch
} from '@fortawesome/free-solid-svg-icons'
library.add(
faChevronLeft,
faChevronRight,
faCircleNotch
)
const MediaModal = {
components: {
StillImage,
VideoAttachment,
PinchZoom,
SwipeClick,
Modal,
Flash
},
data () {
return {
loading: false,
swipeDirection: GestureService.DIRECTION_LEFT,
swipeThreshold: () => {
const considerableMoveRatio = 1 / 4
return window.innerWidth * considerableMoveRatio
},
pinchZoomMinScale: 1,
pinchZoomScaleResetLimit: 1.2
}
},
computed: {
showing () {
return this.$store.state.mediaViewer.activated
},
media () {
return this.$store.state.mediaViewer.media
},
description () {
return this.currentMedia.description
},
currentIndex () {
return this.$store.state.mediaViewer.currentIndex
},
currentMedia () {
return this.media[this.currentIndex]
},
canNavigate () {
return this.media.length > 1
},
type () {
return this.currentMedia ? this.getType(this.currentMedia) : null
},
},
methods: {
getType (media) {
return fileTypeService.fileType(media.mimetype)
},
hide () {
// HACK: Closing immediately via a touch will cause the click
// to be processed on the content below the overlay
const transitionTime = 100 // ms
setTimeout(() => {
this.$store.dispatch('closeMediaViewer')
}, transitionTime)
},
goPrev () {
if (this.canNavigate) {
const prevIndex = this.currentIndex === 0 ? this.media.length - 1 : (this.currentIndex - 1)
const newMedia = this.media[prevIndex]
if (this.getType(newMedia) === 'image') {
this.loading = true
}
this.$store.dispatch('setCurrentMedia', newMedia)
}
},
goNext () {
if (this.canNavigate) {
const nextIndex = this.currentIndex === this.media.length - 1 ? 0 : (this.currentIndex + 1)
const newMedia = this.media[nextIndex]
if (this.getType(newMedia) === 'image') {
this.loading = true
}
this.$store.dispatch('setCurrentMedia', newMedia)
}
},
onImageLoaded () {
this.loading = false
},
handleSwipePreview (offsets) {
this.$refs.pinchZoom.setTransform({ scale: 1, x: offsets[0], y: 0 })
},
handleSwipeEnd (sign) {
- console.log('handleSwipeEnd:', sign)
this.$refs.pinchZoom.setTransform({ scale: 1, x: 0, y: 0 })
if (sign > 0) {
this.goNext()
} else if (sign < 0) {
this.goPrev()
}
},
handleKeyupEvent (e) {
if (this.showing && e.keyCode === 27) { // escape
this.hide()
}
},
handleKeydownEvent (e) {
if (!this.showing) {
return
}
if (e.keyCode === 39) { // arrow right
this.goNext()
} else if (e.keyCode === 37) { // arrow left
this.goPrev()
}
}
},
mounted () {
window.addEventListener('popstate', this.hide)
document.addEventListener('keyup', this.handleKeyupEvent)
document.addEventListener('keydown', this.handleKeydownEvent)
},
destroyed () {
window.removeEventListener('popstate', this.hide)
document.removeEventListener('keyup', this.handleKeyupEvent)
document.removeEventListener('keydown', this.handleKeydownEvent)
}
}
export default MediaModal
diff --git a/src/services/gesture_service/gesture_service.js b/src/services/gesture_service/gesture_service.js
index 741d4a1264..94da3f43a9 100644
--- a/src/services/gesture_service/gesture_service.js
+++ b/src/services/gesture_service/gesture_service.js
@@ -1,221 +1,205 @@
const DIRECTION_LEFT = [-1, 0]
const DIRECTION_RIGHT = [1, 0]
const DIRECTION_UP = [0, -1]
const DIRECTION_DOWN = [0, 1]
const BUTTON_LEFT = 0
const deltaCoord = (oldCoord, newCoord) => [newCoord[0] - oldCoord[0], newCoord[1] - oldCoord[1]]
const touchCoord = touch => [touch.screenX, touch.screenY]
const touchEventCoord = e => touchCoord(e.touches[0])
const pointerEventCoord = e => [e.clientX, e.clientY]
const vectorLength = v => Math.sqrt(v[0] * v[0] + v[1] * v[1])
const perpendicular = v => [v[1], -v[0]]
const dotProduct = (v1, v2) => v1[0] * v2[0] + v1[1] * v2[1]
const project = (v1, v2) => {
const scalar = (dotProduct(v1, v2) / dotProduct(v2, v2))
return [scalar * v2[0], scalar * v2[1]]
}
-// const debug = console.log
-const debug = () => {}
-
// direction: either use the constants above or an arbitrary 2d vector.
// threshold: how many Px to move from touch origin before checking if the
// callback should be called.
// divergentTolerance: a scalar for much of divergent direction we tolerate when
// above threshold. for example, with 1.0 we only call the callback if
// divergent component of delta is < 1.0 * direction component of delta.
const swipeGesture = (direction, onSwipe, threshold = 30, perpendicularTolerance = 1.0) => {
return {
direction,
onSwipe,
threshold,
perpendicularTolerance,
_startPos: [0, 0],
_swiping: false
}
}
const beginSwipe = (event, gesture) => {
gesture._startPos = touchEventCoord(event)
gesture._swiping = true
}
const updateSwipe = (event, gesture) => {
if (!gesture._swiping) return
// movement too small
const delta = deltaCoord(gesture._startPos, touchEventCoord(event))
if (vectorLength(delta) < gesture.threshold) return
// movement is opposite from direction
if (dotProduct(delta, gesture.direction) < 0) return
// movement perpendicular to direction is too much
const towardsDir = project(delta, gesture.direction)
const perpendicularDir = perpendicular(gesture.direction)
const towardsPerpendicular = project(delta, perpendicularDir)
if (
vectorLength(towardsDir) * gesture.perpendicularTolerance <
vectorLength(towardsPerpendicular)
) return
gesture.onSwipe()
gesture._swiping = false
}
class SwipeAndClickGesture {
// swipePreviewCallback(offsets: Array[Number])
// offsets: the offset vector which the underlying component should move, from the starting position
// swipeEndCallback(sign: 0|-1|1)
// sign: if the swipe does not meet the threshold, 0
// if the swipe meets the threshold in the positive direction, 1
// if the swipe meets the threshold in the negative direction, -1
constructor ({
direction,
// swipeStartCallback
swipePreviewCallback,
swipeEndCallback,
swipeCancelCallback,
swipelessClickCallback,
threshold = 30, perpendicularTolerance = 1.0
}) {
- const nop = () => { debug('Warning: Not implemented') }
+ const nop = () => {}
this.direction = direction
this.swipePreviewCallback = swipePreviewCallback || nop
this.swipeEndCallback = swipeEndCallback || nop
this.swipeCancelCallback = swipeCancelCallback || nop
this.swipelessClickCallback = swipelessClickCallback || nop
this.threshold = typeof threshold === 'function' ? threshold : () => threshold
this.perpendicularTolerance = perpendicularTolerance
this._reset()
}
_reset () {
this._startPos = [0, 0]
this._pointerId = -1
this._swiping = false
this._swiped = false
this._preventNextClick = false
}
start (event) {
- debug('start() called', event)
-
// Only handle left click
if (event.button !== BUTTON_LEFT) {
return
}
this._startPos = pointerEventCoord(event)
this._pointerId = event.pointerId
- debug('start pos:', this._startPos)
this._swiping = true
this._swiped = false
}
move (event) {
if (this._swiping && this._pointerId === event.pointerId) {
this._swiped = true
const coord = pointerEventCoord(event)
const delta = deltaCoord(this._startPos, coord)
this.swipePreviewCallback(delta)
}
}
cancel (event) {
- debug('cancel called')
if (!this._swiping || this._pointerId !== event.pointerId) {
return
}
this.swipeCancelCallback()
}
end (event) {
if (!this._swiping) {
- debug('not swiping')
return
}
if (this._pointerId !== event.pointerId) {
- debug('pointer id does not match')
return
}
this._swiping = false
- debug('end: is swipe event')
-
- debug('button = ', event.button)
-
// movement too small
const coord = pointerEventCoord(event)
const delta = deltaCoord(this._startPos, coord)
const sign = (() => {
- debug(
- 'threshold = ', this.threshold(),
- 'vector len =', vectorLength(delta))
if (vectorLength(delta) < this.threshold()) {
return 0
}
// movement is opposite from direction
const isPositive = dotProduct(delta, this.direction) > 0
// movement perpendicular to direction is too much
const towardsDir = project(delta, this.direction)
const perpendicularDir = perpendicular(this.direction)
const towardsPerpendicular = project(delta, perpendicularDir)
if (
vectorLength(towardsDir) * this.perpendicularTolerance <
vectorLength(towardsPerpendicular)
) {
return 0
}
return isPositive ? 1 : -1
})()
const swiped = this._swiped
if (this._swiped) {
this.swipeEndCallback(sign)
}
this._reset()
// Only a mouse will fire click event when
// the end point is far from the starting point
// so for other kinds of pointers do not check
// whether we have swiped
if (swiped && event.pointerType === 'mouse') {
this._preventNextClick = true
}
}
click (event) {
if (!this._preventNextClick) {
this.swipelessClickCallback()
}
this._reset()
}
}
const GestureService = {
DIRECTION_LEFT,
DIRECTION_RIGHT,
DIRECTION_UP,
DIRECTION_DOWN,
swipeGesture,
beginSwipe,
updateSwipe,
SwipeAndClickGesture
}
export default GestureService
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Aug 9, 1:24 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1724635
Default Alt Text
(10 KB)
Attached To
Mode
rPUFE pleroma-fe-upstream
Attached
Detach File
Event Timeline
Log In to Comment