181 lines
3.7 KiB
Vue
181 lines
3.7 KiB
Vue
<template>
|
|
<div
|
|
v-if="enabled"
|
|
class="config-editor"
|
|
>
|
|
<p
|
|
class="label"
|
|
v-text="template.name"
|
|
/>
|
|
<!-- editor -->
|
|
<div
|
|
v-if="template.type === 'object'"
|
|
class="editor"
|
|
>
|
|
<ConfigEditor
|
|
v-for="(prop,key) of template.properties"
|
|
:key="key"
|
|
v-model="config[prop.name]"
|
|
:template="prop"
|
|
:enabled="is_enabled(prop.if)"
|
|
/>
|
|
</div>
|
|
<div
|
|
v-else-if="template.type === 'array'"
|
|
class="editor"
|
|
>
|
|
<ConfigEditor
|
|
v-for="(child,key) of config"
|
|
:key="key"
|
|
v-model="config[key]"
|
|
:template="template.child"
|
|
:enabled="is_enabled(template.child.if)"
|
|
/>
|
|
<button
|
|
type="button"
|
|
@click="add_item"
|
|
>
|
|
add
|
|
</button>
|
|
</div>
|
|
<div
|
|
v-else-if="template.type === 'string'"
|
|
class="editor"
|
|
>
|
|
<select
|
|
v-if="Array.isArray(template.choices)"
|
|
v-model="config"
|
|
>
|
|
<option
|
|
v-for="(opt,optkey) in template.choices"
|
|
:key="optkey"
|
|
v-text="opt"
|
|
/>
|
|
</select>
|
|
<input
|
|
v-else
|
|
v-model="config"
|
|
type="text"
|
|
>
|
|
</div>
|
|
<div
|
|
v-else-if="template.type === 'number'"
|
|
class="editor"
|
|
>
|
|
<input
|
|
v-model="config"
|
|
type="number"
|
|
>
|
|
</div>
|
|
<div
|
|
v-else-if="template.type === 'boolean'"
|
|
class="editor"
|
|
>
|
|
<input
|
|
v-model="config"
|
|
type="checkbox"
|
|
>
|
|
</div>
|
|
<pre v-else>
|
|
invalid config
|
|
</pre>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { resolve_data } from '../helper';
|
|
|
|
export default {
|
|
name: 'ConfigEditor',
|
|
props: {
|
|
// eslint-disable-next-line vue/require-prop-types
|
|
value: { required: true },
|
|
template: {
|
|
type: Object,
|
|
required: true,
|
|
enabled: { type: Boolean, default: true }
|
|
},
|
|
enabled: {
|
|
type: Boolean,
|
|
default: true
|
|
}
|
|
},
|
|
data () {
|
|
return { temp: this.value };
|
|
},
|
|
computed: {
|
|
config: {
|
|
get () {
|
|
return this.temp;
|
|
},
|
|
set (val) {
|
|
this.$emit ('input', val);
|
|
this.temp = val;
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
is_enabled (condition) {
|
|
if (typeof condition === 'undefined')
|
|
return true;
|
|
switch (condition.op) {
|
|
case '=':
|
|
return resolve_data (this.config, condition.prop) === condition.val;
|
|
case '<':
|
|
return resolve_data (this.config, condition.prop) < condition.val;
|
|
case '>':
|
|
return resolve_data (this.config, condition.prop) > condition.val;
|
|
default:
|
|
return false;
|
|
}
|
|
},
|
|
add_item () {
|
|
if (
|
|
typeof this.config === 'undefined'
|
|
|| !Array.isArray (this.config)
|
|
)
|
|
this.config = [];
|
|
this.config.push (this.create_default (this.template.child));
|
|
},
|
|
create_default (template) {
|
|
if (typeof template.default !== 'undefined')
|
|
return template.default;
|
|
if (template.type === 'string')
|
|
return '';
|
|
if (template.type === 'number')
|
|
return 0;
|
|
if (template.type === 'boolean')
|
|
return false;
|
|
if (template.type === 'array')
|
|
return [];
|
|
if (template.type === 'object') {
|
|
const res = {};
|
|
for (const prop of template.properties)
|
|
res[prop.name] = this.create_default (prop);
|
|
return res;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.config-editor {
|
|
display: grid;
|
|
grid-template-areas: 'label editor';
|
|
grid-template-columns: auto 1fr;
|
|
}
|
|
|
|
.editor {
|
|
border: 1px solid black;
|
|
margin-left: 10px;
|
|
grid-column: editor;
|
|
}
|
|
|
|
.label {
|
|
display: inline-block;
|
|
grid-column: label;
|
|
}
|
|
</style>
|