187 lines
6.5 KiB
Vue
187 lines
6.5 KiB
Vue
<template>
|
|
<modal-inner class="modal__inner-1--templates" aria-label="管理模板">
|
|
<div class="modal__content">
|
|
<div class="form-entry">
|
|
<label class="form-entry__label" for="template">模板</label>
|
|
<div class="form-entry__field">
|
|
<input v-if="isEditing" id="template" type="text" class="textfield" v-focus @blur="submitEdit()" @keydown.enter="submitEdit()" @keydown.esc.stop="submitEdit(true)" v-model="editingName">
|
|
<select v-else id="template" v-model="selectedId" class="textfield">
|
|
<option v-for="(template, id) in templates" :key="id" :value="id">
|
|
{{ template.name }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-entry__actions flex flex--row flex--end">
|
|
<button class="form-entry__button button" @click="create" v-title="'新建模板'">
|
|
<icon-file-plus></icon-file-plus>
|
|
</button>
|
|
<button class="form-entry__button button" @click="copy" v-title="'复制模板'">
|
|
<icon-file-multiple></icon-file-multiple>
|
|
</button>
|
|
<button v-if="!isReadOnly" class="form-entry__button button" @click="isEditing = true" v-title="'重命名模板'">
|
|
<icon-pen></icon-pen>
|
|
</button>
|
|
<button v-if="!isReadOnly" class="form-entry__button button" @click="remove" v-title="'删除模板'">
|
|
<icon-delete></icon-delete>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="form-entry">
|
|
<label class="form-entry__label">值</label>
|
|
<div class="form-entry__field" v-for="(template, id) in templates" :key="id" v-if="id === selectedId">
|
|
<code-editor lang="handlebars" :value="template.value" :disabled="isReadOnly" @changed="template.value = $event"></code-editor>
|
|
</div>
|
|
</div>
|
|
<div v-if="!isReadOnly">
|
|
<a href="javascript:void(0)" v-if="!showHelpers" @click="showHelpers = true">添加帮助</a>
|
|
<div class="form-entry" v-else>
|
|
<br>
|
|
<label class="form-entry__label">帮助</label>
|
|
<div class="form-entry__field" v-for="(template, id) in templates" :key="id" v-if="id === selectedId">
|
|
<code-editor lang="javascript" :value="template.helpers" @changed="template.helpers = $event"></code-editor>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal__button-bar">
|
|
<button class="button" @click="config.reject()">取消</button>
|
|
<button class="button button--resolve" @click="resolve()">确认</button>
|
|
</div>
|
|
</modal-inner>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapGetters } from 'vuex';
|
|
import utils from '../../services/utils';
|
|
import badgeSvc from '../../services/badgeSvc';
|
|
import ModalInner from './common/ModalInner';
|
|
import CodeEditor from '../CodeEditor';
|
|
import emptyTemplateValue from '../../data/empties/emptyTemplateValue.html';
|
|
import emptyTemplateHelpers from '!raw-loader!../../data/empties/emptyTemplateHelpers.js'; // eslint-disable-line
|
|
import store from '../../store';
|
|
|
|
const collator = new Intl.Collator(undefined, { sensitivity: 'base' });
|
|
|
|
function fillEmptyFields(template) {
|
|
if (template.value === '\n') {
|
|
template.value = emptyTemplateValue;
|
|
}
|
|
if (template.helpers === '\n') {
|
|
template.helpers = emptyTemplateHelpers;
|
|
}
|
|
}
|
|
|
|
export default {
|
|
components: {
|
|
ModalInner,
|
|
CodeEditor,
|
|
},
|
|
data: () => ({
|
|
selectedId: '',
|
|
templates: {},
|
|
showHelpers: false,
|
|
isEditing: false,
|
|
editingName: '',
|
|
}),
|
|
computed: {
|
|
...mapGetters('modal', [
|
|
'config',
|
|
]),
|
|
isReadOnly() {
|
|
return this.templates[this.selectedId].isAdditional;
|
|
},
|
|
},
|
|
created() {
|
|
this.$watch(
|
|
() => store.getters['data/allTemplatesById'],
|
|
(allTemplatesById) => {
|
|
const templates = {};
|
|
// Sort templates by name
|
|
Object.entries(allTemplatesById)
|
|
.sort(([, template1], [, template2]) => collator.compare(template1.name, template2.name))
|
|
.forEach(([id, template]) => {
|
|
const templateClone = utils.deepCopy(template);
|
|
fillEmptyFields(templateClone);
|
|
templates[id] = templateClone;
|
|
});
|
|
this.templates = templates;
|
|
this.selectedId = this.config.selectedId;
|
|
if (!templates[this.selectedId]) {
|
|
[this.selectedId] = Object.keys(templates);
|
|
}
|
|
this.isEditing = false;
|
|
},
|
|
{ immediate: true },
|
|
);
|
|
this.$watch('selectedId', (selectedId) => {
|
|
const template = this.templates[selectedId];
|
|
this.showHelpers = template.helpers !== emptyTemplateHelpers;
|
|
this.editingName = template.name;
|
|
}, { immediate: true });
|
|
},
|
|
methods: {
|
|
create() {
|
|
const template = {
|
|
name: 'New template',
|
|
value: '\n',
|
|
helpers: '\n',
|
|
};
|
|
fillEmptyFields(template);
|
|
this.selectedId = utils.uid();
|
|
this.templates[this.selectedId] = template;
|
|
this.isEditing = true;
|
|
},
|
|
copy() {
|
|
const template = utils.deepCopy(this.templates[this.selectedId]);
|
|
template.name += ' copy';
|
|
delete template.isAdditional;
|
|
this.selectedId = utils.uid();
|
|
this.templates[this.selectedId] = template;
|
|
this.isEditing = true;
|
|
},
|
|
remove() {
|
|
delete this.templates[this.selectedId];
|
|
[this.selectedId] = Object.keys(this.templates);
|
|
},
|
|
submitEdit(cancel) {
|
|
const template = this.templates[this.selectedId];
|
|
if (!cancel && this.editingName) {
|
|
template.name = utils.sanitizeName(this.editingName);
|
|
} else {
|
|
this.editingName = template.name;
|
|
}
|
|
setTimeout(() => { // For the form-entry to get the blur event
|
|
this.isEditing = false;
|
|
}, 1);
|
|
},
|
|
async resolve() {
|
|
const oldTemplateIds = Object.keys(store.getters['data/templatesById']);
|
|
await store.dispatch('data/setTemplatesById', this.templates);
|
|
const newTemplateIds = Object.keys(store.getters['data/templatesById']);
|
|
const createdCount = newTemplateIds
|
|
.filter(id => !oldTemplateIds.includes(id))
|
|
.length;
|
|
const removedCount = oldTemplateIds
|
|
.filter(id => !newTemplateIds.includes(id))
|
|
.length;
|
|
if (createdCount) {
|
|
badgeSvc.addBadge('addTemplate');
|
|
}
|
|
if (removedCount) {
|
|
badgeSvc.addBadge('removeTemplate');
|
|
}
|
|
this.config.resolve({
|
|
templates: this.templates,
|
|
selectedId: this.selectedId,
|
|
});
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.modal__inner-1.modal__inner-1--templates {
|
|
max-width: 600px;
|
|
}
|
|
</style>
|