tissue/resources/assets/js/components/TagInput.vue

97 lines
2.8 KiB
Vue

<template>
<div :class="containerClass" @click="$refs.input.focus()">
<input :name="name" type="hidden" :value="tagValue" />
<ul class="list-inline d-inline">
<li
v-for="(tag, i) in tags"
class="list-inline-item badge badge-primary tag-item"
@click="removeTag(i)"
:key="tag"
>
<span class="oi oi-tag"></span> {{ tag }} | x
</li>
</ul>
<input :id="id" ref="input" type="text" class="tag-input" v-model="buffer" @keydown="onKeyDown" />
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import { bus } from '../checkin';
@Component
export default class TagInput extends Vue {
@Prop(String) readonly id!: string;
@Prop(String) readonly name!: string;
@Prop(String) readonly value!: string;
@Prop(Boolean) readonly isInvalid!: boolean;
tags: string[] = this.value.trim() !== '' ? this.value.trim().split(' ') : [];
buffer = '';
created() {
bus.$on('add-tag', (tag: string) => this.tags.indexOf(tag) === -1 && this.tags.push(tag));
bus.$on('resend-tag', () => bus.$emit('change-tag', this.tags));
}
onKeyDown(event: KeyboardEvent) {
if (this.buffer.trim() !== '') {
switch (event.key) {
case 'Tab':
case 'Enter':
case ' ':
if ((event as any).isComposing !== true) {
this.tags.push(this.buffer.trim().replace(/\s+/g, '_'));
this.buffer = '';
}
event.preventDefault();
break;
case 'Unidentified':
// 実際にテキストボックスに入力されている文字を見に行く (フォールバック処理)
if (event.srcElement && (event.srcElement as HTMLInputElement).value.slice(-1) == ' ') {
this.tags.push(this.buffer.trim().replace(/\s+/g, '_'));
this.buffer = '';
event.preventDefault();
}
break;
}
} else if (event.key === 'Enter') {
// 誤爆防止
event.preventDefault();
}
}
removeTag(index: number) {
this.tags.splice(index, 1);
}
@Watch('tags')
onTagsChanged() {
bus.$emit('change-tag', this.tags);
}
get containerClass() {
return {
'form-control': true,
'h-auto': true,
'is-invalid': this.isInvalid,
};
}
get tagValue(): string {
return this.tags.join(' ');
}
}
</script>
<style lang="scss" scoped>
.tag-item {
cursor: pointer;
}
.tag-input {
border: 0;
outline: 0;
}
</style>