Began generalizing insert forms for character properties to reduce duplicated code
This commit is contained in:
@@ -60,7 +60,7 @@
|
||||
callback(feature){
|
||||
if (!feature) return;
|
||||
feature.charId = charId;
|
||||
let featureId = insertFeature.call({feature});
|
||||
let featureId = insertFeature.call(feature);
|
||||
return featureId
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,23 +15,6 @@
|
||||
<v-card-text>
|
||||
{{description}}
|
||||
</v-card-text>
|
||||
<v-card-actions v-if="uses">
|
||||
<v-spacer/>
|
||||
<v-btn
|
||||
flat
|
||||
:disabled="uses - used <= 0"
|
||||
@click="$emit('used')"
|
||||
>
|
||||
Use
|
||||
</v-btn>
|
||||
<v-btn
|
||||
flat
|
||||
:disabled="!used"
|
||||
@click="$emit('reset')"
|
||||
>
|
||||
Reset
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</toolbar-card>
|
||||
</template>
|
||||
|
||||
@@ -43,9 +26,6 @@
|
||||
charId: String,
|
||||
name: String,
|
||||
description: String,
|
||||
uses: Number,
|
||||
used: Number,
|
||||
reset: String,
|
||||
color: String,
|
||||
enabled: Boolean,
|
||||
alwaysEnabled: Boolean,
|
||||
|
||||
@@ -1,74 +1,51 @@
|
||||
<template lang="html">
|
||||
<dialog-base>
|
||||
<div slot="toolbar">
|
||||
New Feature
|
||||
</div>
|
||||
<feature-edit
|
||||
<property-insert-dialog
|
||||
documentType="Feature"
|
||||
:doc="feature"
|
||||
:schema="schema"
|
||||
@updateErrors="newErrors => errors = newErrors"
|
||||
>
|
||||
<feature-form
|
||||
:feature="feature"
|
||||
:errors="errors"
|
||||
@change="change"
|
||||
@update="update"
|
||||
:debounce-time="0"
|
||||
:errors="errors"
|
||||
/>
|
||||
<v-spacer slot="actions"/>
|
||||
<v-btn
|
||||
flat
|
||||
slot="actions"
|
||||
:disabled="!valid"
|
||||
@click="$store.dispatch('popDialogStack', feature)"
|
||||
>
|
||||
Insert Feature
|
||||
</v-btn>
|
||||
</dialog-base>
|
||||
</property-insert-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FeatureEdit from '/imports/ui/components/features/FeatureEdit.vue';
|
||||
import Features from '/imports/api/creature/properties/Features.js';
|
||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||
import FeatureForm from '/imports/ui/components/features/FeatureForm.vue';
|
||||
import Features, { FeatureSchema } from '/imports/api/creature/properties/Features.js';
|
||||
import PropertyInsertDialog from '/imports/ui/components/properties/PropertyInsertDialog.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FeatureEdit,
|
||||
DialogBase,
|
||||
FeatureForm,
|
||||
PropertyInsertDialog,
|
||||
},
|
||||
data(){ return {
|
||||
feature: {
|
||||
name: 'New Feature',
|
||||
description: null,
|
||||
uses: null,
|
||||
used: 0,
|
||||
reset: null,
|
||||
enabled: true,
|
||||
alwaysEnabled: true,
|
||||
color: '#9E9E9E',
|
||||
},
|
||||
valid: true,
|
||||
schema: FeatureSchema,
|
||||
errors: {},
|
||||
}},
|
||||
methods: {
|
||||
change(update, ack){
|
||||
update(update, ack){
|
||||
for (key in update){
|
||||
this.feature[key] = update[key];
|
||||
}
|
||||
if (ack) ack();
|
||||
},
|
||||
},
|
||||
created(){
|
||||
this.validationContext = Features.simpleSchema().newContext();
|
||||
},
|
||||
computed: {
|
||||
errors(){
|
||||
this.valid = true;
|
||||
let cleanAtt = this.validationContext.clean(this.feature)
|
||||
this.validationContext.validate(cleanAtt, {keys: [
|
||||
'name', 'description', 'uses', 'used', 'reset', 'enabled',
|
||||
'alwaysEnabled', 'color',
|
||||
]});
|
||||
let errors = {};
|
||||
this.validationContext.validationErrors().forEach(error => {
|
||||
if (this.valid) this.valid = false;
|
||||
errors[error.name] = Features.simpleSchema().messageForError(error);
|
||||
});
|
||||
return errors;
|
||||
try {
|
||||
FeatureSchema.validate({$set: update}, {clean: true, modifier: true});
|
||||
ack()
|
||||
} catch (e){
|
||||
ack(e.message);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -3,35 +3,10 @@
|
||||
<text-field
|
||||
label="Name"
|
||||
:value="feature.name"
|
||||
@change="(name, ack) => $emit('change', {name}, ack)"
|
||||
@change="(name, ack) => $emit('update', {name}, ack)"
|
||||
:error-messages="errors.name"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Used"
|
||||
type="number"
|
||||
:value="feature.used"
|
||||
@change="(used, ack) => $emit('change', {used}, ack)"
|
||||
:error-messages="errors.used"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<text-field
|
||||
label="Uses"
|
||||
:value="feature.uses"
|
||||
@change="(uses, ack) => $emit('change', {uses}, ack)"
|
||||
:error-messages="errors.uses"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<smart-select
|
||||
label="Reset"
|
||||
clearable
|
||||
:items="resetOptions"
|
||||
:value="feature.reset"
|
||||
:error-messages="errors.reset"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="(reset, ack) => $emit('change', {reset}, ack)"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
<smart-select
|
||||
label="Enabled"
|
||||
:items="enabledOptions"
|
||||
@@ -45,7 +20,7 @@
|
||||
label="Description"
|
||||
:value="feature.description"
|
||||
:error-messages="errors.description"
|
||||
@change="(description, ack) => $emit('change', {description}, ack)"
|
||||
@change="(description, ack) => $emit('update', {description}, ack)"
|
||||
:debounce-time="debounceTime"
|
||||
/>
|
||||
</div>
|
||||
@@ -65,15 +40,6 @@
|
||||
debounceTime: Number,
|
||||
},
|
||||
data(){ return{
|
||||
resetOptions: [
|
||||
{
|
||||
text: 'Short rest',
|
||||
value: 'shortRest',
|
||||
}, {
|
||||
text: 'Long rest',
|
||||
value: 'longRest',
|
||||
}
|
||||
],
|
||||
enabledOptions: [
|
||||
{
|
||||
text: 'Always enabled',
|
||||
@@ -98,11 +64,11 @@
|
||||
methods: {
|
||||
changeEnabled(value, ack){
|
||||
if (value === 'always'){
|
||||
this.$emit('change', {enabled: true, alwaysEnabled: true}, ack);
|
||||
this.$emit('update', {enabled: true, alwaysEnabled: true}, ack);
|
||||
} else if (value === 'enabled'){
|
||||
this.$emit('change', {enabled: true, alwaysEnabled: false}, ack);
|
||||
this.$emit('update', {enabled: true, alwaysEnabled: false}, ack);
|
||||
} else if (value === 'disabled'){
|
||||
this.$emit('change', {enabled: false, alwaysEnabled: false}, ack);
|
||||
this.$emit('update', {enabled: false, alwaysEnabled: false}, ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<template lang="html">
|
||||
<dialog-base>
|
||||
<slot name="toolbar" slot="toolbar" :color="color">
|
||||
<div>
|
||||
{{doc.name}}
|
||||
</div>
|
||||
</slot>
|
||||
<slot/>
|
||||
<slot name="form" slot="edit" @update="update"/>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import getCollectionByName from '/imports/api/parenting/getCollectionByName.js';
|
||||
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
||||
import propertyUpdateMethods from '/imports/api/creature/properties/propertyUpdateMethods.js';
|
||||
export default {
|
||||
props: {
|
||||
collection: String,
|
||||
id: String,
|
||||
},
|
||||
meteor: {
|
||||
doc(){
|
||||
return fetchDocByRef({
|
||||
id: this.id,
|
||||
collection: this.collection,
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
update(update, ack){
|
||||
propertyUpdateMethods[this.collection].call({
|
||||
_id: this.id,
|
||||
update,
|
||||
}, error => ack(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
<template lang="html">
|
||||
<dialog-base>
|
||||
<template slot="toolbar">
|
||||
<div>
|
||||
New {{documentType}}
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<slot @update="update"/>
|
||||
</template>
|
||||
<template slot="actions">
|
||||
<v-spacer/>
|
||||
<v-btn
|
||||
flat
|
||||
:disabled="!valid"
|
||||
@click="$store.dispatch('popDialogStack', doc)"
|
||||
>
|
||||
Insert {{documentType}}
|
||||
</v-btn>
|
||||
</template>
|
||||
</dialog-base>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DialogBase,
|
||||
},
|
||||
props: {
|
||||
documentType: String,
|
||||
schema: Object,
|
||||
doc: Object,
|
||||
},
|
||||
data(){ return {
|
||||
valid: true,
|
||||
}},
|
||||
watch: {
|
||||
doc: {
|
||||
handler(newDoc){
|
||||
let validationContext = this.schema.newContext();
|
||||
this.valid = true;
|
||||
let cleanAtt = validationContext.clean(newDoc)
|
||||
validationContext.validate(cleanAtt, {keys: [
|
||||
'name', 'description', 'uses', 'used', 'reset', 'enabled',
|
||||
'alwaysEnabled', 'color',
|
||||
]});
|
||||
let errors = {};
|
||||
validationContext.validationErrors().forEach(error => {
|
||||
if (this.valid) this.valid = false;
|
||||
errors[error.name] = this.schema.messageForError(error);
|
||||
});
|
||||
this.$emit('updateErrors', errors);
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
log: console.log
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
||||
@@ -15,6 +15,11 @@
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-toolbar>
|
||||
<template v-if="breadcrumbs">
|
||||
<v-card-text>
|
||||
example > bread > crumb
|
||||
</v-card-text>
|
||||
</template>
|
||||
<v-card-text id="base-dialog-body" v-scroll:#base-dialog-body="onScroll">
|
||||
<v-tabs-items :value="isEditing ? 1 : 0" touchless>
|
||||
<v-tab-item>
|
||||
@@ -37,6 +42,7 @@
|
||||
export default {
|
||||
props: {
|
||||
color: String,
|
||||
breadcrumbs: Object,
|
||||
},
|
||||
data(){ return {
|
||||
offsetTop: 0,
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
@enter="enter"
|
||||
@leave="leave"
|
||||
>
|
||||
<div class="sibling" key="sibling"/>
|
||||
<v-card
|
||||
v-for="(dialog, index) in dialogs"
|
||||
:key="dialog._id"
|
||||
@@ -25,7 +24,9 @@
|
||||
:style="getDialogStyle(index)"
|
||||
:elevation="6"
|
||||
>
|
||||
<component :is="dialog.component" v-bind="dialog.data" @pop="popDialogStack($event)" class="dialog-component"></component>
|
||||
<transition name="slide">
|
||||
<component :is="dialog.component" v-bind="dialog.data" @pop="popDialogStack($event)" class="dialog-component"></component>
|
||||
</transition>
|
||||
</v-card>
|
||||
</transition-group>
|
||||
</v-layout>
|
||||
@@ -168,7 +169,7 @@
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
watch: {
|
||||
dialogs(newDialogs) {
|
||||
let el = document.documentElement;
|
||||
if (newDialogs.length) {
|
||||
|
||||
62
app/package-lock.json
generated
62
app/package-lock.json
generated
@@ -1456,37 +1456,6 @@
|
||||
"requires": {
|
||||
"inherits": "~2.0.1",
|
||||
"readable-stream": "^2.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
}
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"stream-http": {
|
||||
@@ -1499,37 +1468,6 @@
|
||||
"readable-stream": "^2.3.3",
|
||||
"to-arraybuffer": "^1.0.0",
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
}
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
|
||||
Reference in New Issue
Block a user