mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-13 00:38:06 +00:00
140 lines
4.1 KiB
Vue
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>
|