1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-12 16:28:06 +00:00
bramw_baserow/web-frontend/modules/database/components/view/grid/GridViewField.vue

138 lines
3.9 KiB
Vue

<template>
<div class="grid-view-column" style="width: 200px;" @click="select($event)">
<component
:is="getFieldComponent(field.type)"
ref="column"
:field="field"
:value="row['field_' + field.id]"
:selected="selected"
@update="update"
/>
</div>
</template>
<script>
import { isElement } from '@baserow/modules/core/utils/dom'
import { notifyIf } from '@baserow/modules/core/utils/error'
export default {
name: 'GridViewField',
props: {
table: {
type: Object,
required: true,
},
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.$store
.dispatch('view/grid/updateValue', {
table: this.table,
row: this.row,
field: this.field,
value,
oldValue,
})
.catch((error) => {
notifyIf(error, 'column')
})
.then(() => {
this.$forceUpdate()
})
// This is needed because in some cases we do have a value yet, so a watcher of
// the value is not guaranteed. This will make sure the component shows the
// latest value.
this.$forceUpdate()
},
/**
* Method that is called when a user clicks on the grid field. It wil
* @TODO improve speed somehow, maybe with the fastclick library.
*/
select(event) {
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.column.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.column.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)
}
this.clickTimestamp = timestamp
},
unselect() {
this.$refs.column.beforeUnSelect()
this.$nextTick(() => {
this.selected = false
})
document.body.removeEventListener('click', this.$el.clickOutsideEvent)
},
},
}
</script>