mirror of
https://github.com/go-shiori/shiori.git
synced 2024-11-16 14:16:29 +08:00
229 lines
No EOL
8.5 KiB
JavaScript
229 lines
No EOL
8.5 KiB
JavaScript
var YlaDialog = function () {
|
|
// Private variable
|
|
var _template = `
|
|
<div v-if="visible" class="yla-dialog__overlay">
|
|
<div class="yla-dialog">
|
|
<div class="yla-dialog__header">
|
|
<p>{{title}}</p>
|
|
</div>
|
|
<div class="yla-dialog__body">
|
|
<slot>
|
|
<p class="yla-dialog__content">{{content}}</p>
|
|
<template v-for="(field,index) in formFields">
|
|
<p v-if="showLabel" class="label">{{field.label}} :</p>
|
|
<textarea v-if="field.type === 'area'"
|
|
:style="{gridColumnEnd: showLabel ? null : 'span 2'}"
|
|
:placeholder="field.label"
|
|
:tabindex="index+1"
|
|
ref="input"
|
|
v-model="field.value"
|
|
@focus="$event.target.select()"
|
|
@keyup="handleInput(index)">
|
|
</textarea>
|
|
<input v-else
|
|
:style="{gridColumnEnd: showLabel ? null : 'span 2'}"
|
|
:type="fieldType(field)"
|
|
:placeholder="field.label"
|
|
:tabindex="index+1"
|
|
ref="input"
|
|
v-model="field.value"
|
|
@focus="$event.target.select()"
|
|
@keyup="handleInput(index)"
|
|
@keyup.enter="handleInputEnter(index)">
|
|
<span :ref="'suggestion-'+index" v-if="field.suggestion" class="suggestion">{{field.suggestion}}</span>
|
|
</template>
|
|
</slot>
|
|
</div>
|
|
<div class="yla-dialog__footer">
|
|
<i v-if="loading" class="fas fa-fw fa-spinner fa-spin"></i>
|
|
<slot v-else name="custom-footer">
|
|
<a v-if="secondText"
|
|
:tabindex="btnTabIndex+1"
|
|
@click="handleSecondClick"
|
|
@keyup.enter="handleSecondClick"
|
|
class="yla-dialog__button">{{secondText}}
|
|
</a>
|
|
<a :tabindex="btnTabIndex"
|
|
ref="mainButton"
|
|
@click="handleMainClick"
|
|
@keyup.enter="handleMainClick"
|
|
class="yla-dialog__button main">{{mainText}}
|
|
</a>
|
|
</slot>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
|
|
return {
|
|
template: _template,
|
|
props: {
|
|
visible: Boolean,
|
|
loading: Boolean,
|
|
title: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
content: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
fields: {
|
|
type: Array,
|
|
default () {
|
|
return []
|
|
}
|
|
},
|
|
showLabel: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
mainText: {
|
|
type: String,
|
|
default: 'OK'
|
|
},
|
|
secondText: String,
|
|
mainClick: {
|
|
type: Function,
|
|
default () {}
|
|
},
|
|
secondClick: {
|
|
type: Function,
|
|
default () {}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
formFields: []
|
|
};
|
|
},
|
|
computed: {
|
|
btnTabIndex() {
|
|
return this.fields.length + 1;
|
|
}
|
|
},
|
|
watch: {
|
|
fields: {
|
|
immediate: true,
|
|
handler() {
|
|
this.formFields = this.fields.map(field => {
|
|
if (typeof field === 'string') return {
|
|
name: field,
|
|
label: field,
|
|
value: '',
|
|
type: 'text',
|
|
dictionary: [],
|
|
separator: ' ',
|
|
suggestion: undefined
|
|
}
|
|
|
|
if (typeof field === 'object') return {
|
|
name: field.name || '',
|
|
label: field.label || '',
|
|
value: field.value || '',
|
|
type: field.type || 'text',
|
|
dictionary: field.dictionary instanceof Array ? field.dictionary : [],
|
|
separator: field.separator || ' ',
|
|
suggestion: undefined
|
|
}
|
|
});
|
|
}
|
|
},
|
|
'fields.length' () {
|
|
this.focus();
|
|
},
|
|
visible() {
|
|
this.focus();
|
|
}
|
|
},
|
|
methods: {
|
|
fieldType(f) {
|
|
var type = f.type || 'text';
|
|
if (type !== 'text' && type !== 'password') return 'text';
|
|
else return type;
|
|
},
|
|
handleMainClick() {
|
|
var data = {};
|
|
this.formFields.forEach(field => {
|
|
var value = field.value;
|
|
if (field.type === 'number') value = parseInt(value, 10) || 0;
|
|
else if (field.type === 'float') value = parseFloat(value) || 0.0;
|
|
data[field.name] = value;
|
|
})
|
|
this.mainClick(data);
|
|
},
|
|
handleSecondClick() {
|
|
this.secondClick();
|
|
},
|
|
handleInput(index) {
|
|
// Create initial variable
|
|
var field = this.formFields[index],
|
|
dictionary = field.dictionary;
|
|
|
|
// Make sure dictionary is not empty
|
|
if (dictionary.length === 0) return;
|
|
|
|
// Fetch suggestion from dictionary
|
|
var words = field.value.split(field.separator),
|
|
lastWord = words[words.length - 1].toLowerCase(),
|
|
suggestion;
|
|
|
|
if (lastWord !== '') {
|
|
suggestion = dictionary.find(word => {
|
|
return word.toLowerCase().startsWith(lastWord)
|
|
});
|
|
}
|
|
|
|
this.formFields[index].suggestion = suggestion;
|
|
|
|
// Make sure suggestion exist
|
|
if (suggestion == null) return;
|
|
|
|
// Display suggestion
|
|
this.$nextTick(() => {
|
|
var input = this.$refs.input[index],
|
|
span = this.$refs['suggestion-' + index][0],
|
|
inputRect = input.getBoundingClientRect();
|
|
|
|
span.style.top = (inputRect.bottom - 1) + 'px';
|
|
span.style.left = inputRect.left + 'px';
|
|
});
|
|
},
|
|
handleInputEnter(index) {
|
|
var suggestion = this.formFields[index].suggestion;
|
|
|
|
if (suggestion == null) {
|
|
this.handleMainClick();
|
|
return;
|
|
}
|
|
|
|
var separator = this.formFields[index].separator,
|
|
words = this.formFields[index].value.split(separator);
|
|
|
|
words.pop();
|
|
words.push(suggestion);
|
|
|
|
this.formFields[index].value = words.join(separator) + separator;
|
|
this.formFields[index].suggestion = undefined;
|
|
},
|
|
focus() {
|
|
this.$nextTick(() => {
|
|
if (!this.visible) return;
|
|
|
|
var fields = this.$refs.input,
|
|
otherInput = this.$el.querySelectorAll('input'),
|
|
button = this.$refs.mainButton;
|
|
|
|
if (fields && fields.length > 0) {
|
|
this.$refs.input[0].focus();
|
|
this.$refs.input[0].select();
|
|
} else if (otherInput && otherInput.length > 0) {
|
|
otherInput[0].focus();
|
|
otherInput[0].select();
|
|
} else if (button) {
|
|
button.focus();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}; |