1
0
mirror of https://gitlab.com/bramw/baserow.git synced 2024-11-21 23:37:55 +00:00
bramw_baserow/web-frontend/modules/core/components/Scrollbars.vue

203 lines
6.4 KiB
Vue

<template>
<div class="scrollbars">
<div
v-if="vertical !== null && verticalShow"
class="scrollbars__vertical-wrapper"
>
<div
ref="scrollbarVertical"
class="scrollbars__vertical"
:style="{ top: verticalTop + '%', height: verticalHeight + '%' }"
@mousedown="mouseDownVertical($event)"
></div>
</div>
<div
v-if="horizontal !== null && horizontalShow"
class="scrollbars__horizontal-wrapper"
>
<div
ref="scrollbarHorizontal"
class="scrollbars__horizontal"
:style="{ left: horizontalLeft + '%', width: horizontalWidth + '%' }"
@mousedown="mouseDownHorizontal($event)"
></div>
</div>
</div>
</template>
<script>
import { floor, ceil } from '@baserow/modules/core/utils/number'
/**
* This component will render custom scrollbars to a scrollable div. They will
* automatically adjust when you resize the window and can be dragged.
*/
export default {
name: 'Scrollbars',
props: {
/**
* The vertical property should be the reference of the vertical scrollable element
* in the parent component.
*/
vertical: {
required: false,
type: String,
default: null,
},
/**
* The horizontal property should be the reference of the vertical scrollable
* element in the parent component.
*/
horizontal: {
required: false,
type: String,
default: null,
},
},
data() {
return {
dragging: null,
elementStart: 0,
mouseStart: 0,
verticalShow: false,
verticalHeight: 0,
verticalTop: 0,
horizontalShow: false,
horizontalWidth: 0,
horizontalLeft: 0,
}
},
mounted() {
this.update()
// Register the event when the window is resized because the size of the scrollbars
// might need to updated.
this.$el.resizeEventListener = () => this.update()
window.addEventListener('resize', this.$el.resizeEventListener)
// Register the mouseup event for when the user releases the mouse button. This is
// needed for the dragging of the scrollbar handle.
this.$el.mouseUpEventListener = (event) => this.mouseUp(event)
window.addEventListener('mouseup', this.$el.mouseUpEventListener)
// Register the mousemove event for when the user moves his mouse. This is needed
// for the dragging of the scrollbar handle.
this.$el.mouseMoveEventListener = (event) => this.mouseMove(event)
window.addEventListener('mousemove', this.$el.mouseMoveEventListener)
},
beforeDestroy() {
window.removeEventListener('resize', this.$el.resizeEventListener)
window.removeEventListener('mouseup', this.$el.mouseUpEventListener)
window.removeEventListener('mousemove', this.$el.mouseMoveEventListener)
},
methods: {
update() {
if (this.vertical !== null) {
this.updateVertical()
}
if (this.horizontal !== null) {
this.updateHorizontal()
}
},
/**
* Method that updates the visibility, height and top position of the vertical
* scrollbar handle based on the scrollTop of the vertical scrolling element of the
* parent.
*/
updateVertical() {
const element = this.$parent[this.vertical]()
const show = element.scrollHeight > element.clientHeight
// @TODO if the client height is very high we have a minimum of 2%, but this needs
// to be subtracted from the top position so that it fits. Same goes for the
// horizontal handler.
const height = Math.max(
floor((element.clientHeight / element.scrollHeight) * 100, 2),
2
)
const top = ceil((element.scrollTop / element.scrollHeight) * 100, 2)
this.verticalShow = show
this.verticalHeight = height
this.verticalTop = top
},
/**
* Method that updates the visibility, width and left position of the horizontal
* scrollbar handle based on the scrollLeft of horizontal scrolling element of the
* parent.
*/
updateHorizontal() {
const element = this.$parent[this.horizontal]()
const show = element.scrollWidth > element.clientWidth
const width = Math.max(
floor((element.clientWidth / element.scrollWidth) * 100, 2),
2
)
const left = ceil((element.scrollLeft / element.scrollWidth) * 100, 2)
this.horizontalShow = show
this.horizontalWidth = width
this.horizontalLeft = left
},
/**
* Event that is called when the user clicks on the vertical scrollbar handle. It
* will start the vertical dragging.
*/
mouseDownVertical(event) {
event.preventDefault()
this.dragging = 'vertical'
this.elementStart = this.$refs.scrollbarVertical.offsetTop
this.mouseStart = event.clientY
},
/**
* Event that is called when the user clicks on the horizontal scrollbar handle. It
* will start the horizontal dragging.
*/
mouseDownHorizontal(event) {
event.preventDefault()
this.dragging = 'horizontal'
this.elementStart = this.$refs.scrollbarHorizontal.offsetLeft
this.mouseStart = event.clientX
},
/**
* Event that is called when the mouse moves. If vertical of horizontal scrollbar
* handle is in a dragging state it will emit an event with the new scrollTop.
*/
mouseMove(event) {
if (this.dragging === 'vertical') {
event.preventDefault()
const element = this.$parent[this.vertical]()
const delta = event.clientY - this.mouseStart
const pixel = element.scrollHeight / element.clientHeight
const top = Math.ceil((this.elementStart + delta) * pixel)
this.$emit('vertical', top)
this.updateVertical()
}
if (this.dragging === 'horizontal') {
event.preventDefault()
const element = this.$parent[this.horizontal]()
const delta = event.clientX - this.mouseStart
const pixel = element.scrollWidth / element.clientWidth
const left = Math.ceil((this.elementStart + delta) * pixel)
this.$emit('horizontal', left)
this.updateHorizontal()
}
},
/**
* Event that is called when the mouse button is released. It will stop the dragging
* of the handle.
*/
mouseUp() {
if (this.dragging === null) {
return
}
this.dragging = null
this.elementStart = 0
this.mouseStart = 0
},
},
}
</script>