2022-04-26 20:13:17 +08:00
|
|
|
<template>
|
2022-05-11 21:51:26 +08:00
|
|
|
<div class="sci-inline-edit" :class="{ 'editing': editing }">
|
2022-04-26 20:13:17 +08:00
|
|
|
<div class="sci-inline-edit__content">
|
2022-05-11 21:51:26 +08:00
|
|
|
<textarea
|
|
|
|
ref="input"
|
|
|
|
rows="1"
|
|
|
|
v-if="editing"
|
|
|
|
:class="{ 'error': error }"
|
|
|
|
:placeholder="placeholder"
|
|
|
|
v-model="newValue"
|
|
|
|
@input="handleInput"
|
|
|
|
@keydown="handleKeypress"
|
|
|
|
@paste="handlePaste"
|
|
|
|
@blur="handleBlur"
|
|
|
|
></textarea>
|
2022-06-09 20:40:45 +08:00
|
|
|
<div v-else @click="enableEdit" class="sci-inline-edit__view" :class="{ 'blank': isBlank }">{{ value || placeholder }}</div>
|
2022-04-26 20:13:17 +08:00
|
|
|
<div v-if="editing && error" class="sci-inline-edit__error">
|
|
|
|
{{ error }}
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-06-09 20:40:45 +08:00
|
|
|
<template v-if="editing">
|
|
|
|
<div class="sci-inline-edit__control btn btn-primary icon-btn" @click="update">
|
2022-05-11 21:51:26 +08:00
|
|
|
<i class="fas fa-check"></i>
|
2022-04-26 20:13:17 +08:00
|
|
|
</div>
|
2022-06-09 20:40:45 +08:00
|
|
|
<div class="sci-inline-edit__control btn btn-light icon-btn" @click="cancelEdit">
|
2022-05-11 21:51:26 +08:00
|
|
|
<i class="fas fa-times"></i>
|
2022-04-26 20:13:17 +08:00
|
|
|
</div>
|
2022-06-09 20:40:45 +08:00
|
|
|
</template>
|
2022-04-26 20:13:17 +08:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
name: 'InlineEdit',
|
|
|
|
props: {
|
|
|
|
value: { type: String, default: '' },
|
|
|
|
allowBlank: { type: Boolean, default: true },
|
|
|
|
attributeName: { type: String, required: true },
|
|
|
|
characterLimit: { type: Number },
|
|
|
|
placeholder: { type: String },
|
2022-05-11 21:51:26 +08:00
|
|
|
autofocus: { type: Boolean, default: false },
|
|
|
|
multilinePaste: { type: Boolean, default: false }
|
2022-04-26 20:13:17 +08:00
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
editing: false,
|
|
|
|
newValue: ''
|
|
|
|
}
|
|
|
|
},
|
|
|
|
created( ){
|
2022-04-26 20:30:07 +08:00
|
|
|
this.newValue = this.value || '';
|
2022-04-26 20:13:17 +08:00
|
|
|
},
|
|
|
|
mounted() {
|
2022-05-05 18:56:31 +08:00
|
|
|
this.handleAutofocus();
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
autofocus() {
|
|
|
|
this.handleAutofocus();
|
2022-04-26 20:13:17 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
isBlank() {
|
|
|
|
return this.newValue.length === 0
|
|
|
|
},
|
|
|
|
error() {
|
|
|
|
if(!this.allowBlank && this.isBlank) {
|
|
|
|
return this.i18n.t('inline_edit.errors.blank', { attribute: this.attributeName })
|
|
|
|
}
|
|
|
|
if(this.characterLimit && this.newValue.length > this.characterLimit) {
|
|
|
|
return(
|
|
|
|
this.i18n.t('inline_edit.errors.over_limit',
|
|
|
|
{ attribute: this.attributeName, limit: this.characterLimit }
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2022-05-05 18:56:31 +08:00
|
|
|
handleAutofocus() {
|
2022-05-11 21:51:26 +08:00
|
|
|
if (this.autofocus || !this.placeholder && this.isBlank) {
|
|
|
|
this.enableEdit();
|
2022-05-05 18:56:31 +08:00
|
|
|
setTimeout(this.focus, 50);
|
|
|
|
}
|
|
|
|
},
|
2022-05-11 21:51:26 +08:00
|
|
|
handleBlur() {
|
|
|
|
if (!this.isBlank) {
|
|
|
|
this.$nextTick(this.update);
|
|
|
|
} else {
|
|
|
|
this.$emit('delete');
|
|
|
|
}
|
|
|
|
},
|
2022-04-26 20:13:17 +08:00
|
|
|
focus() {
|
|
|
|
this.$nextTick(() => {
|
2022-06-09 20:40:45 +08:00
|
|
|
if (!this.$refs.input) return;
|
|
|
|
|
2022-04-26 20:13:17 +08:00
|
|
|
this.$refs.input.focus();
|
|
|
|
this.resize();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
enableEdit() {
|
|
|
|
this.editing = true;
|
|
|
|
this.focus();
|
2022-05-05 18:56:31 +08:00
|
|
|
this.$emit('editingEnabled');
|
2022-04-26 20:13:17 +08:00
|
|
|
},
|
|
|
|
cancelEdit() {
|
|
|
|
this.editing = false;
|
|
|
|
this.newValue = this.value || '';
|
2022-05-05 18:56:31 +08:00
|
|
|
this.$emit('editingDisabled');
|
|
|
|
},
|
2022-05-11 21:51:26 +08:00
|
|
|
handlePaste(e) {
|
|
|
|
if (!this.multilinePaste) return;
|
|
|
|
e.clipboardData.items[0].getAsString((data) => {
|
|
|
|
let lines = data.split(/[\n\r]/);
|
|
|
|
if (lines.length > 1) {
|
|
|
|
this.newValue = lines[0];
|
|
|
|
this.$emit('multilinePaste', lines);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
2022-05-05 18:56:31 +08:00
|
|
|
handleInput() {
|
2022-05-11 21:51:26 +08:00
|
|
|
this.newValue = this.newValue.replace(/^[\n\r]+|[\n\r]+$/g, '');
|
2022-05-05 18:56:31 +08:00
|
|
|
this.$nextTick(this.resize);
|
|
|
|
},
|
|
|
|
handleKeypress(e) {
|
|
|
|
switch(e.key) {
|
|
|
|
case 'Escape':
|
|
|
|
this.cancelEdit();
|
|
|
|
break;
|
|
|
|
case 'Enter':
|
|
|
|
this.update();
|
|
|
|
break;
|
|
|
|
}
|
2022-04-26 20:13:17 +08:00
|
|
|
},
|
|
|
|
resize() {
|
|
|
|
this.$refs.input.style.height = "auto";
|
2022-05-05 18:56:31 +08:00
|
|
|
this.$refs.input.style.height = (this.$refs.input.scrollHeight) + "px";
|
2022-04-26 20:13:17 +08:00
|
|
|
},
|
|
|
|
update() {
|
2022-05-11 21:51:26 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
if(!this.allowBlank && this.isBlank) return;
|
|
|
|
if(!this.editing) return;
|
2022-04-26 20:13:17 +08:00
|
|
|
|
2022-05-11 21:51:26 +08:00
|
|
|
this.newValue = this.newValue.trim();
|
|
|
|
this.editing = false;
|
|
|
|
this.$emit('editingDisabled');
|
|
|
|
this.$emit('update', this.newValue);
|
|
|
|
}, 100) // due to clicking 'x' also triggering a blur event
|
2022-04-26 20:13:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|