1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-13 00:38:06 +00:00
bramw_baserow/web-frontend/modules/database/components/view/grid/GridViewField.vue
2020-05-11 17:27:35 +00:00

140 lines
4.1 KiB
Vue

<template>
<div class="grid-view-column" @click="select()">
<component
:is="getFieldComponent(field.type)"
ref="field"
:field="field"
:value="row['field_' + field.id]"
:selected="selected"
@update="update"
/>
</div>
</template>
<script>
import { isElement } from '@baserow/modules/core/utils/dom'
export default {
name: 'GridViewField',
props: {
field: {
type: Object,
required: true,
},
row: {
type: Object,
required: true,
},
},
data() {
return {
/**
* Indicates whether the field is selected.
*/
selected: false,
/**
* Timestamp of the last the time the user clicked on the field. We need this to
* check if it was double clicked.
*/
clickTimestamp: null,
}
},
/**
* Because the component can be destroyed if it moves out of the viewport we might
* need to take some action if the the component is in a selected state.
*/
beforeDestroy() {
if (this.selected) {
this.unselect()
}
},
methods: {
getFieldComponent(type) {
return this.$registry.get('field', type).getGridViewFieldComponent()
},
/**
* If the grid field component emits an update event this method will be called
* which will actually update the value via the store.
*/
update(value, oldValue) {
this.$emit('update', {
row: this.row,
field: this.field,
value,
oldValue,
})
},
/**
* Method that is called when a user clicks on the grid field. It wil
* @TODO improve speed somehow, maybe with the fastclick library.
*/
select() {
const timestamp = new Date().getTime()
if (this.selected) {
// If the field is already selected we will check if the click is a doubleclick
// if it was within 200 ms. The double click event can be useful for components
// because they might want to change the editing state.
if (
this.clickTimestamp !== null &&
timestamp - this.clickTimestamp < 200
) {
this.$refs.field.doubleClick()
}
} else {
// If the field is not yet selected we can change the state to selected.
this.selected = true
this.$nextTick(() => {
// Call the select method on the next tick because we want to wait for all
// changes to have rendered.
this.$refs.field.select()
})
// Register a body click event listener so that we can detect if a user has
// clicked outside the field. If that happens we want to unselect the field and
// possibly save the value.
this.$el.clickOutsideEvent = (event) => {
if (
// Check if the column is still selected.
this.selected &&
// If the click was outside the column element.
!isElement(this.$el, event.target)
) {
this.unselect()
}
}
document.body.addEventListener('click', this.$el.clickOutsideEvent)
// If the tab key is pressed want to select the next field. This is however out
// of the scope of the component so we emit the selectNext event that the
// GridView can handle.
this.$el.tabPressedEvent = (event) => {
if (event.keyCode !== 9) {
return
}
event.preventDefault()
this.$emit(event.shiftKey ? 'selectPrevious' : 'selectNext')
}
document.body.addEventListener('keydown', this.$el.tabPressedEvent)
// Emit the selected event so that the parent component can take an action like
// making sure that the element fits in the viewport.
this.$emit('selected', {
component: this,
})
}
this.clickTimestamp = timestamp
},
unselect() {
this.$refs.field.beforeUnSelect()
this.$nextTick(() => {
this.selected = false
})
document.body.removeEventListener('click', this.$el.clickOutsideEvent)
document.body.removeEventListener('keydown', this.$el.tabPressedEvent)
},
},
}
</script>