2020-11-22 17:32:35 +01:00
|
|
|
<template>
|
|
|
|
<div class="heading">
|
|
|
|
<h1 class="title task-id" v-if="task.identifier === ''">
|
|
|
|
#{{ task.index }}
|
|
|
|
</h1>
|
|
|
|
<h1 class="title task-id" v-else>
|
|
|
|
{{ task.identifier }}
|
|
|
|
</h1>
|
|
|
|
<div class="is-done" v-if="task.done">Done</div>
|
|
|
|
<h1
|
2020-11-28 15:30:34 +01:00
|
|
|
class="title input"
|
|
|
|
:class="{'disabled': !canWrite}"
|
2020-11-22 17:32:35 +01:00
|
|
|
@focusout="save()"
|
2021-01-15 23:47:14 +01:00
|
|
|
@keydown.enter.prevent.stop="save()"
|
2020-11-28 15:30:34 +01:00
|
|
|
:contenteditable="canWrite ? 'true' : 'false'"
|
2021-01-15 23:47:14 +01:00
|
|
|
ref="taskTitle">{{ task.title.trim() }}</h1>
|
2020-11-22 17:32:35 +01:00
|
|
|
<transition name="fade">
|
|
|
|
<span class="is-inline-flex is-align-items-center" v-if="loading && saving">
|
|
|
|
<span class="loader is-inline-block mr-2"></span>
|
|
|
|
Saving...
|
|
|
|
</span>
|
|
|
|
<span class="has-text-success is-inline-flex is-align-content-center" v-if="!loading && saved">
|
|
|
|
<icon icon="check" class="mr-2"/>
|
|
|
|
Saved!
|
|
|
|
</span>
|
|
|
|
</transition>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import {LOADING} from '@/store/mutation-types'
|
|
|
|
import {mapState} from 'vuex'
|
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'heading',
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
task: {title: '', identifier: '', index:''},
|
|
|
|
taskTitle: '',
|
|
|
|
saved: false,
|
|
|
|
saving: false, // Since loading is global state, this variable ensures we're only showing the saving icon when saving the description.
|
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: mapState({
|
|
|
|
loading: LOADING,
|
|
|
|
}),
|
|
|
|
props: {
|
|
|
|
value: {
|
|
|
|
required: true,
|
|
|
|
},
|
2020-11-28 15:30:34 +01:00
|
|
|
canWrite: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
2020-11-22 17:32:35 +01:00
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
value(newVal) {
|
|
|
|
this.task = newVal
|
|
|
|
this.taskTitle = this.task.title
|
|
|
|
},
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.task = this.value
|
|
|
|
this.taskTitle = this.task.title
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
save() {
|
|
|
|
this.$refs.taskTitle.spellcheck = false
|
|
|
|
|
|
|
|
// Pull the task title from the contenteditable
|
|
|
|
let taskTitle = this.$refs.taskTitle.textContent
|
|
|
|
this.task.title = taskTitle
|
|
|
|
|
|
|
|
// We only want to save if the title was actually change.
|
|
|
|
// Because the contenteditable does not have a change event,
|
|
|
|
// we're building it ourselves and only calling saveTask()
|
|
|
|
// if the task title changed.
|
|
|
|
if (this.task.title !== this.taskTitle) {
|
2021-01-15 23:47:14 +01:00
|
|
|
this.$refs.taskTitle.blur()
|
2020-11-22 17:32:35 +01:00
|
|
|
this.saveTask()
|
|
|
|
this.taskTitle = taskTitle
|
|
|
|
}
|
|
|
|
},
|
|
|
|
saveTask() {
|
|
|
|
this.saving = true
|
|
|
|
|
|
|
|
this.$store.dispatch('tasks/update', this.task)
|
|
|
|
.then(() => {
|
|
|
|
this.$emit('input', this.task)
|
|
|
|
this.saved = true
|
|
|
|
setTimeout(() => {
|
|
|
|
this.saved = false
|
|
|
|
}, 2000)
|
|
|
|
})
|
|
|
|
.catch(e => {
|
|
|
|
this.error(e, this)
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
this.saving = false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|